Python面向对象编程基础实例分析


Posted in Python onJanuary 17, 2020

本文实例讲述了Python面向对象编程基础。分享给大家供大家参考,具体如下:

1、类的定义

Python中类的定义与对象的初始化如下,python中所有类的父类是object,需要继承。

由于Python是动态语言,因此可以直接为对象添加属性并赋值而不必在类定义中声明

class Person(object):  # 定义一个Person类
  pass
p = Person()  # 初始化一个Person对象
p.name="xiaoming"  # 对象属性赋值

Python的类初始化方法为__init__(),其第一个参数为self代之对象自身,其后为各个参数,初始化就是将传入的参数赋值给对象的属性。**kw代表任意数量的属性,通过key=attribute的形式传入,之后通过setattr()方法将每个属性赋值给对象。

直接在class中定义的变量称为类属性,在__init__()中定义的为对象属性,类属性供所有对象共享,对象只能访问却无权修改。当通过对象给类属性赋值时,会为对象新建一个同名的对象属性,而不是修改类属性。无论在类的内部还是外部,都通过类名对类属性进行访问。

以__开头的变量无法被外部访问,类似于私有变量。这时就需要对象的实例方法从类的内部访问私有变量并做出相应的操作,这样在类的内部定义的方法叫做实例方法,实例方法的第一个参数默认为self代表对象自己。

相应地类方法只能访问类属性,其定义方式是在之前添加标记@classmethod:,其第一个参数cls代表类本身

class Person(object):
  count = 0  # 类属性
  @classmethod:
  def get_count(cls):  # 类方法
    return cls.count
  def __init__(self,name,gender,birth,**kw):
    Person.count+=1  # 访问类属性
    self.name = name
    self.__gender = gender
    self.birth = birth
    for k, v in kw.iteritems():  # 遍历之后的键值对,设置属性
      setattr(self, k, v)
  def get_name(self):  # 定义实例方法
    return self.__name
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
xiaoming.count==9  # 为对象创建属性,不会修改Person.count
print(xiaoming.job)  # 显示Student
print(xiaoming.__gender)  # 无法访问,抛出异常AttributeError
print(xiaoming.get_name())  # 通过实例方法访问内部变量

2、类的继承

Python中类的继承方式如下。值得注意的是在子类Teacher中需要通过super(子类名,self)调用父类的初始化函数来完成对父类中参数的初始化。也可以直接通过父类名称调用父类的方法

通过type()方法输出变量的类型,isinstance()可以判断变量是否是某个类型,dir()方法返回变量的所有属性和方法列表。输出对象t的属性结果如下,其中带__的为默认属性,其余为自定义的属性

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'course', 'gender', 'name']

class Person(object):
  def __init__(self, name, gender):
    self.name = name
    self.gender = gender
class Teacher(Person):  # 继承父类Person
  def __init__(self, name, gender, course):
    super(Teacher,self).__init__(name,gender)  # 调用父类的初始化函数
    self.course= course  # 完成子类变量的初始化
t = Teacher('Alice', 'Female', 'English')
print(isinstance(t,Person))  # 结果为True,子类也是父类的类型
print(dir(t))  # 显示对象的所有属性

和其他面向对象的语言一样,Python具有多态的特性,例如父类和不同的子类都定义了相同的方法,当不同的子类调用该方法时会调用自己定义的方法,从而实现相同的方法具有不同的操作。但python是动态语言,和静态语言C++、Java不同的是在调用实例方法时,python不检查类型,只要方法存在,参数正确,就可以调用。例如原本json的load方法中定义了read()方法用于实现对文件的读取,当我们自定义一个类其中包含read()方法时,便可动态调用实例方法

import json
class Students(object):
  def read(self):
    return r'["Tim", "Bob", "Alice"]'
s = Students()
print json.load(s)

一个子类可以同时继承两个以上的父类,这个特性叫做多继承,当有多个父类时,需要在初始化时指明父类

class A(object):
  def __init__(self, a):
    self.a = a
class B(object):
  def __init__(self, b):
    self.b = b
class C(A, B):
  def __init__(self, a, b, c):
    A.__init__(self, a)
    B.__init__(self, b)
    self.c = c
c = C(1, 2, 3)
print(c.a)   # 输出1

3、类的特殊方法

Python的特殊方法是指定义在类中,以__开头和结尾,由某些函数或操作符隐式触发调用的方法。例如当我们使用print(p)打印一个Person对象p时,就会调用Person的__str__()方法将p转化为字符串共print输出,输出结果为:<__main__.Person object at 0x000001787CC7C0D0>

当我们重新自定义这些特殊方法后,当触发调用时就会按我们定义的函数执行。例如重新定义__str__(),当print()时就会显示My name is Bob

class Person(object):
  def __init__(self, name, gender):
    self.name = name
    self.gender = gender
  def __str__(self):  # 重新定义类特殊方法
    return "My name is " + self.name
p = Person('Bob', 'male')
print(p)  # 输出结果为:My name is Bob

__cmp__()方法用于实现类的比较,在排序时会自动调用。例如在Student类中重新定义该方法,按分数高低对学生进行排序,其有两个参数,第一个自己self,第二个是比较的对象s,如果self应该在s之前,则返回-1

class Student(object):
  def __init__(self, name, score):
    self.name = name
    self.score = score
  def __cmp__(self, s):  # 重写__cmp__方法
    if self.score>s.score:
      return -1  # self在s之前
    elif self.score<s.score:
      return 1
    else:
      return 0
L = [Student('Tim', 99), Student('Bob', 88), Student('Alice', 99)]
Ls = sorted(L)  # 使用sorted对Student类进行排序

__len__()方法用于返回长度,当len()调用类时会触发

__add__、__sub__、__mul__、__div__分别对应类的加减乘除运算,当类遇到运算符+-*/时会调用该方法,例如实现一个分数类Rational的加法:1/2+1/4,通分相加得6/8,最后求最大公约数后约分得到3/4

__int__、__float__方法在int()、float()调用类时触发,可以重新该方法返回一个int或float结果

def gcd(a, b):  # 求最大公约数
  if b == 0:
    return a
  return gcd(b, a % b)
class Rational(object):
  def __init__(self, p, q):
    self.p = p
    self.q = q
  def __add__(self, r):  # 重写加法运算
    return Rational(self.p * r.q + self.q * r.p, self.q * r.q)
  def __str__(self):
    g = gcd(self.p, self.q)  # 将分数约分后输出
    return '%s/%s' % (self.p / g, self.q / g)
  def __float__(self):  # 将分数转化为float小数返回
    return float(self.p)/float(self.q)
r1 = Rational(1, 2)
r2 = Rational(1, 4)
print(r1 + r2)  # 两个类相加
print(float(r1))  # 输出小数形式

类属性的装饰器@property用于将类方法转化为属性,这样就可以像访问属性一样调用方法。例如Student类的__score属性对外是不可见的,通过定义返回方法score使得对象s可以通过s.score得到分数值。

@property.setter方法用于对属性设置方法进行装饰,使得可以像给属性赋值一样调用类方法。例如当使用s.score=99时会调用设置方法score(self,score),将值传递给__score,并且可以对传入值的合法性进行检验。

__slots__()用于定义类中可以使用的属性,父类定义过的子类中无需重复定义。当添加新的属性并赋值时,运行会抛出异常AttributeError

__call__()将一个类实例变成一个可调用对象,例如一个Student对象s,像函数调用一样使用对象:s('Alice')

class Student(object):
  __slots__ = ('name','__score')  # 本类只允许使用name、score两个属性
  def __init__(self, name, score):
    self.name = name
    self.__score = score
  @property        # 定义属性返回方法
  def score(self):
    return self.__score
  @score.setter      # 定义属性设置方法
  def score(self, score):
    if score < 0 or score > 100:
      raise ValueError('invalid score')
    self.__score = score
  def __call__(self, friend):
    print('My friend is %s...' % friend)
s = Student('Bob', 59)
s.score = 60  # 调用属性设置方法
print(s.score)  # 调用属性返回方法
s.grade='A'  # 抛出异常,无法添加其他属性
s('Alice')  # 输出My friend is Alice...

__getattribute__(self,attr)、__setattr__(self,attr)、__delattr__(self,attr)分别用于获取、设置、删除属性时触发的方法,在使用时应注意避免递归调用引起的无限循环,例如在get方法中再调用get类似的方法导致无限循环。

4、模块管理

为了方便分类管理python中的类和方法,需要将代码放在不同的文件中,每个文件构成了一个独立的模块,不同模块之间相同的变量名不会引起命名冲突。但是如果在文件a.py中希望使用文件b.py中的函数func1,则可以通过import在a中导入模块b,并通过b.func1()调用该方法。或者通过from直接引入模块中的函数。在引入时为了防止命名冲突,可以通过as为引入的函数起个别名

# 文件a.py中
import b
print(b.func1())
# 直接引入函数
from b import func1
print(func1())
# 使用别名
from b import func1 as f1
print(f1())

有时将相同类别的模块放在一个文件夹内,就形成了一个包,python要求一个包文件夹内必须有一个__init__.py文件才会识别为一个包,即使它是一个空文件。这时如果一个p1包内的a.py想访问p2包内的b.py中的函数func2,则操作如下

# p1/a.py文件内
import p2.b
print (p2.b.func2())

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
在Linux系统上通过uWSGI配置Nginx+Python环境的教程
Dec 25 Python
mysql 之通过配置文件链接数据库
Aug 12 Python
Python3安装Scrapy的方法步骤
Nov 23 Python
浅析python实现scrapy定时执行爬虫
Mar 04 Python
python中时间、日期、时间戳的转换的实现方法
Jul 06 Python
Django的Modelforms用法简介
Jul 27 Python
Django+uni-app实现数据通信中的请求跨域的示例代码
Oct 12 Python
keras 自定义loss损失函数,sample在loss上的加权和metric详解
May 23 Python
Python计算矩阵的和积的实例详解
Sep 10 Python
python连接mongodb数据库操作数据示例
Nov 30 Python
python利用后缀表达式实现计算器功能
Feb 22 Python
浅谈Python中的正则表达式
Jun 28 Python
通过python实现windows桌面截图代码实例
Jan 17 #Python
PyTorch加载预训练模型实例(pretrained)
Jan 17 #Python
python 正则表达式参数替换实例详解
Jan 17 #Python
Python函数式编程实例详解
Jan 17 #Python
python实现tail -f 功能
Jan 17 #Python
解决Python命令行下退格,删除,方向键乱码(亲测有效)
Jan 16 #Python
python对象销毁实例(垃圾回收)
Jan 16 #Python
You might like
深入理解PHP原理之异常机制
2010/08/21 PHP
PHP操作MongoDB GridFS 存储文件的详解
2013/06/20 PHP
PHP6新特性分析
2016/03/03 PHP
Symfony2联合查询实现方法
2016/03/18 PHP
php安装扩展mysqli的实现步骤及报错解决办法
2017/09/23 PHP
兼容IE和FF的js脚本代码小结(比较常用)
2010/12/06 Javascript
JS实现匀速运动的代码实例
2013/11/29 Javascript
jQuery移除tr无效的解决方法(tr是动态添加)
2014/09/22 Javascript
JavaScript操作class和style样式代码详解
2016/02/13 Javascript
js获取时间精确到秒(年月日)
2016/03/16 Javascript
jQuery AJAX timeout 超时问题详解
2016/06/21 Javascript
Bootstrap 最常用的JS插件系列总结(图片轮播、标签切换等)
2016/07/14 Javascript
jquery文字填写自动高度的实现方法
2016/11/07 Javascript
Bootstrap Table使用整理(五)之分页组合查询
2017/06/09 Javascript
js断点调试心得分享(必看篇)
2017/12/08 Javascript
vue-image-crop基于Vue的移动端图片裁剪组件示例
2018/08/28 Javascript
Node.js原生api搭建web服务器的方法步骤
2019/02/15 Javascript
JavaScript canvas绘制圆弧与圆形
2020/02/18 Javascript
Python下载懒人图库JavaScript特效
2015/05/28 Python
Python的UTC时间转换讲解
2019/02/26 Python
python调用接口的4种方式代码实例
2019/11/19 Python
Python字符串格式化f-string多种功能实现
2020/05/07 Python
基于python实现上传文件到OSS代码实例
2020/05/09 Python
Feelunique澳大利亚:欧洲的化妆品零售电商
2019/12/18 全球购物
经济管理专业毕业生推荐信
2013/11/11 职场文书
项目副经理岗位职责
2013/12/30 职场文书
金融专业大学生自我评价
2014/01/09 职场文书
美术毕业生求职信
2014/02/25 职场文书
数控技校生自我鉴定
2014/03/02 职场文书
个人投资计划书
2014/05/01 职场文书
入职担保书怎么写
2014/05/12 职场文书
酒店员工培训方案
2014/06/02 职场文书
中共广东省委常委会党的群众路线教育实践活动整改方案
2014/09/23 职场文书
签约仪式致辞
2015/07/30 职场文书
婚礼长辈答谢词
2015/09/29 职场文书
CSS变量实现主题切换的方法
2021/06/23 HTML / CSS