Python的类与对象
之前学过的C++和Java都是面向对象的编程语言,因此对Pytho的面向对象的学习会更加轻松一点,这里记录一些python面向对象的基本用法
# 类定义 class People: # 定义基本属性 name = '' age = 0 # 定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 # 定义构造方法 def __init__(self, n, a, w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" % (self.name, self.age)) # 但继承实例 class Student(People): grade = '' def __init__(self, n, a, w, g): # 调用父类的构造函数 People.__init__(self, n, a, w) self.grade = g # 覆写父类的方法 def speak(self): print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade)) # 另一个类,多继承之前的准备 class Speaker: topic = '' name = '' def __init__(self, n, t): self.name = n self.topic = t def speak(self): print("我叫 %s,我是一个演说家,我演讲的主题是 %s" % (self.name, self.topic)) # 多继承 class Sample(Speaker, Student): a = '' def __init__(self, n, a, w, g, t): Student.__init__(self, n, a, w, g) Speaker.__init__(self, n, t) test = Sample("Tim", 25, 80, 4, "Python") test.speak() # 方法名同,默认调用的是在括号中排前地父类的方法
注意点1:
在Python中,有以下几种方式来定义变量:
- xx:公有变量
- _xx:单前置下划线,私有化属性或方法,类对象和子类可以访问,from somemodule import *禁止导入
- __xx:双前置下划线,私有化属性或方法,无法在外部直接访问(名字重整所以访问不到)
- __xx__:双前后下划线,系统定义名字(不要自己发明这样的名字)
- xx_:单后置下划线,用于避免与Python关键词的冲突
例如 : 上面代码的__init__()是构造函数,在生成对象时调用,__weight这个是私有变量
注意点2:
继承:
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。
如:上面的代码Sample类对象test在调用speak()方法时调用的是它的父类中从左到右第一个的test方法(方法名同,默认调用的是在括号中排前地父类的方法)
注意点3:
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。
注意点4:
如果多继承中想调用不是第一个父类的同同名方法咋办?
例:在上面的代码中增加Sport类,并改写Sample类
class Sport: def __init__(self, n, a): self.name = n self.age = a # 覆写父类的方法 def speak(self): print("%s 说: 我 %d 岁了,我爱好运动" % (self.name, self.age)) # 多继承 class Sample(Speaker, Student, Sport): a = '' def __init__(self, n, a, w, g, t): Student.__init__(self, n, a, w, g) Speaker.__init__(self, n, t) Sport.__init__(self, n, a)
如何调用Studen或者Sport类的speak方法呢?
在网上看了一些博客,找到了解决方法,在Sample类里重写speak方法,具体要调用哪个类的speak方法,然后使用不同的语句即可:
# 在Sample里增加speak方法: def speak(self): # super().speak() # 调用Speaker的speak方法 # super(Sample, self).speak() # 调用Speaker的speak方法 # super(Speaker, self).speak() # 调用Student的speak方法 # super(Student, self).speak() # 调用Student父类的People的speak方法 super(People, self).speak() # 调用Sport的speak方法
这里出现了一个问题,在 super(Student, self).speak() 前面的都是对的,而写了这句话后期待出现的是调用Sport的speak方法,可是调用的却是People的speak方法(因为Student函数继承了People类)。这时发现了类名.__mro__(Method Resolution Order 方法解析顺序),打印了一下后发现了方法解析顺序,然后继续往下写了一下就好了。
注意点5:
类的专有方法:
- __init__ : 构造函数,在生成对象时调用
- __del__ : 析构函数,释放对象时使用
- __repr__ : 打印,转换
- __setitem__ : 按照索引赋值
- __getitem__: 按照索引获取值
- __len__: 获得长度
- __cmp__: 比较运算
- __call__: 函数调用
- __add__: 加运算
- __sub__: 减运算
- __mul__: 乘运算
- __truediv__: 除运算
- __mod__: 求余运算
- __pow__: 乘方
注意点6:
运算符重载(对类的专有方法进行重载)
class Pair: def __init__(self, x, y): self.x = x self.y = y def __add__(self): return self.x + self.y def __str__(self): return '(%d, %d)' % (self.x, self.y) p = Pair(3, 4) print(p) print(p.__add__())