类基础
类进阶
Python的类提供了面向对象编程的所有基本功能:
类支持两种操作:
inst = clsName(…)
;类定义
类通过class定义,里面有属性与方法。
class ClassName:
def funs(self, arg):
# self is the instance of class
@classmethod
def clsFuns(cls, arg):
# cls is the class
@staticmethod
def staticFun(arg):
# 与普通函数类似
类继承
Python支持多继承,多个父类之间通过逗号分割。若是父类中有相同的方法名,而在子类使用时未指定,Python从左到右依次查找父类中是否包含方法(即优先使用排在前面的父类中的方法)。
在多重继承(特别是有菱形继承时),查找关系会更复杂;具体是通过MRO(Method Resolution Order)
来解决方法调用二义性问题的;而MRO又是使用的C3算法(拓扑排序+深度优先搜索:依次取出入度为0的节点,取出节点后即把其相关的边去掉,然后递归处理)处理顺序的。
子类中要调用基类中同名方法需:baseCls.fun
或super().fun
;
class DerivedClassName(Base1, Base2, Base3):
.
变量与可访问性
变量(属性)分类:
clsName.var
;__init__
方法中定义、初始化);通过实例对象访问inst.var
;Python中的可访问性是通过约定来实现的:
__var
;_var
;只能自身与子类可访问;类专有方法
Python中通过约定一些专有的方法来增强类的功能:
__init__
:构造函数,在生成对象时调用(实例变量也在此函数中定义);__del__
:析构函数,释放对象时使用;__repr__
:打印(若有__str__
,则先尝试str),转换;__setitem__
:按照索引赋值;__getitem__
:按照索引取值;__len__
:获取长度,内置函数len()
使用;__cmp__
:比较运算;__call__
:函数调用(对象看作一个算子);__add__
:加运算;__sub__
:减运算;__mul__
:乘运算;__div__
:除运算;__mod__
:求余运算;__pow__
:乘方运算;repr与str:repr()与str()为内置函数,对应类中的__repr__
与__str__
来处理字符串:
__str__
,若未定义,再查看__repr__
;类方法
Python类中有三种方式定义方法:
@classmethod
修饰方式:定义类方法,第一个参数表示类(一般约定为cls);@staticmethod
修饰方式:定义静态方法;以下是三种函数的定义及调用方式:
class MethodTest:
index = 0
def __init__(self):
self.index = -1
def instFun(self, index):
print('instance function:', index, self.index, MethodTest.index)
self.index = index
@classmethod
def classFun(cls, index):
print('class function:', index, cls.index)
cls.index = index
@staticmethod
def staticFun(index):
print('static function:', index, MethodTest.index)
if __name__=="__main__":
mtest = MethodTest()
mtest.instFun(1) # instance function: -1 0
mtest.classFun(2) # class function: 0 0
mtest.staticFun(3) # static function: 3 2
MethodTest.classFun(4) # class function: 2 2
MethodTest.instFun(mtest, 5) # instance function: 1 4
MethodTest.staticFun(6) # static function: 6 4
通过实例对象可以直接调用三类方法;通过类名可以直接调用静态方法与类方法,若要调用实例方法,还需传递一个实例对象。
类属性
通过get/set
属性,可以增强对变量的控制,便于后续修改与扩展。但类中的属性(get/set
)方法不要手动去实现,应使用@propery
来修饰实现:
@propery
修饰即可;@propery
本身又创建了另一个装饰器,负责把一个setter方法变成属性赋值:若不增加setter方法,则属性将是只读的。以下是属性定义的示例:通过@propery
定义了count的get属性,然后就可以通过@count.setter
来定义set属性了。
class CountProp:
def __init__(self):
self._count=0
@property
def count(self):
return self._count
@count.setter
def count(self, newCount):
self._count = newCount
def __getattr__(self, name):
print('call __getattr__:', name)
value = '{} value for {}'.format(self._index, name)
self._index += 1
setattr(self, name, value)
return value
def __getattribute__(self, name):
print('call __getattribute__:', name)
try:
return super().__getattribute__(name)
except AttributeError:
# setattr(self, name, value)
raise
cPro = CountProp()
print(cPro.count) # 0
cPro.count = 10
print(cPro.count) # 10
类中的属性除在类定义(或初始化时)定义外,还可以在任何时候绑定(在给不存在的属性赋值时会自动绑定)。属性的获取与赋值规则为:
getattribute
:无论属性是否存在(若属性不存在,需抛出AttributeError异常),因此不能在此方法内引用属性,否则会引起循环递归。因此若要访问属性,则调用super().XXX来避免递归。getattr
则调用此方法;setattr
方法。