目录
重点内容提要
掌握类的定义语法
掌握对象的创建语法
理解数据成员与成员方法的区别
理解私有成员与公有成员的区别
理解属性的工作原理
了解继承的基本概念
理解特殊方法的概念与工作原理
前言
面向对象程序设计(Object Oriented Programming,OOP)的思想主要针对大型软件设计而提出,使得软件设计更加灵活,能够很好地支持代码复用和设计复用,代码具有更好的可读性和可扩展性。
面向对象程序设计的一条基本原则是计算机程序由多个能够起到子程序作用的单元或对象组合而成,这大大地降低了软件开发的难度,使得编程就像搭积木一样简单。
面向对象程序设计的关键就是如何合理地定义和组织类以及类之间的关系。
python中对象的概念很广泛,python中的一切内容都可以称为对象,除了数字、字符串、列表、元组、字典、集合、range对象、zip对象等等,函数也是对象,类也是对象。
对象:把数据以及对数据的操作封装在一起,组成一个整体(称为对象),不同对象之间通过消息机制来通信或者同步。
类:对于相同类型的对象进行分类、抽象后,得出共同的特征而形成了类。创建新类(派生类)时,可以以设计好的类(基类)为基础,这样可大幅度缩短开发周,并且可以实现设计复用。
- 数据成员:创建类时用变量形式表示对象特征的成员成为数据成员
- 成员方法:用函数形式表示对象行为的成员称为成员方法
- 成员:数据成员和成员方法统称为类的成员
继承:类与类之间可以组成继承层次。在派生类中可以对基类某些行为进行继承使之重新实现,从而使得基类的某个同名方法在不同派生类中的行为有可能不同,也体现出一定的多态性。
消息:对象引用一个方法的过程称为向该对象发送一个消息,或者说一个对象接收到一个服务请求。消息是对象之间交互的手段。
类是实现代码复用和设计复用的一个重要方法,封装、继承、多态是面向对象程序设计的三个要素。
面向对象=对象+类+继承+消息
一、类的定义与使用
1.类的定义
class Car[(object1,...)]: #定义一个类Car,派生自objector1类(基类)
#[]在没有基类时可以不写,类的名称一般大写
price=100000 #定义一个数据成员(属于类的)
def infor(self,color): #定义一个成员方法,至少要有一个参数self
self.color='red' #定义一个数据成员(实例属性)
print("This is a car")
python使用class关键字来定义类,class关键字之后是一个空格,接下来是类的名字,如果派生自其他基类的话则需要把所有基类放到一对圆括号中并使用逗号分隔,然后是一个冒号,最后换行并定义类的内部实现。
类名的首字母一般要大写,当然也可以按照自己的习惯定义类名,但是一般推荐参考惯例来命名,并在整个系统的设计和实现中保持风格一致。
2.类的使用
定义了类之后,就可以用来实例化对象(将抽象化的类具体化),并通过“对象名.成员”的方式来访问其中的数据成员或成员方法。
>>> class Car:
... def infor(self):
... print('This is a car')
...
...
>>> car=Car() #实例化对象(类也是可调用的!类后的()不能省!)
>>> car.infor() #(实例car)调用对象(car)的成员方法
This is a car
>>> isinstance(car,Car) #测试car是否为Car的实例
True
3.pass关键字
python提供了一个关键字“pass”:类似于空语句,可用在:
- 类的定义
>>>class A:
pass
- 函数的定义
>>>def demo:
pass
- 选择结构
>>>if 5>3:
pass
pass的作用:当暂时没有确定如何实现功能,或者为以后的软件升级预留空间,或者其他类型功能时,可以使用该关键字来“占位”
4.类定义中的self参数
参数self的作用:
- 类中的所有实例方法都必须至少有一个名为self的参数,并且必须是实例方法的第一个形参(如果有多个形参的话),self参数代表将来要创建的对象(即实例化对象)本身
- 在类中定义实例方法时self的作用:访问实例属性时需要以self为前缀
调用实例方法时如何给self传值:
- 在外部(类的外部)通过对象名调用对象方法时并不需要传递这个参数
- 如果在外部通过类名调用对象方法则需要显式为self参数传值
在python中,在类中定义实例方法时将第一个参数定义为“self”只是一个习惯,而实际上类的实例方法中第一个参数的名字是可以变化的,而不必须使用“self”这个名字,尽管如此,建议编写代码时仍以self作为方法的第一个参数名字。
>>> class A:
... def __init__(hahaha,v):
... hahaha.value=v
... def show(hahaha):
... print(hahaha.value)
...
...
>>> a=A(3)
>>> a.show()
3
>>> a=A() #有初始化函数,必须传参数
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
a=A()
TypeError: A.__init__() missing 1 required positional argument: 'v'
>>> class A:
... def init(hahaha,v):
... hahaha.value=v
... def show(hahaha):
... print(hahaha.value)
...
...
>>> a=A() #先定义对象再传参数,此时必须没有初始化函数
>>> a.init(8)
>>> a.show()
8
二、数据成员与成员方法
类的成员及表示:类包含数据成员及成员方法,统称为类的成员,创建类时设定。成员有公有成员、私有成员、受保护成员、特殊成员等之分。
- 数据成员(attribute):创建类时,用变量形式表示的对象特征(属性)称为数据成员
- 成员方法(method):创建类时,用函数形式表示的对象行为称为成员方法
1.私有成员与公有成员
python并没有对私有成员提供严格的访问保护机制(因为还是可以用下面方法访问!)
- 在定义类的成员时,如果成员名以两个下划线“__”或者更多下划线开头而不以两个或者更多下划线结束则表示是私有成员
- 私有成员在类的外部不能直接访问,需要通过调用对象的公有成员方法来访问,也可以通过python支持的特殊方式来访问,如“对象名._类名__***”。
公有成员既可以在类的内部进行访问,也可以在外部程序中使用。
在python中,以下划线开头的变量名和方法名有特殊的含义,尤其是在类的定义中:
- _***:受保护成员;不能用“from module import *”导入,但可在模块中用“__all__”变量指明能导入时,可用此方法导入
- __***__:系统定义的特殊成员;
- __***:私有成员,只有类对象自己能访问,子类对象不能直接访问到这个成员,但在对象外部可以通过“对象名._类名__***”这样的特殊方式来访问
【注】python中不存在严格意义上的私有成员
>>> class A:
... def __init__(self,value1=0,value2=0):
... self._value1=value1
... self.__value2=value2
... def setValue(self,value1,value2): #修改值
... self._value1=value1
... self.__value2=value2
... def show(self):
... print(self._value1)
... print(self.__value2)
...
...
>>> a=A()
>>> a._value1
0
>>> a.__value2 #在外部访问对象的私有数据成员
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
a.__value2
AttributeError: 'A' object has no attribute '__value2'. Did you mean: '_A__value2'?
>>> a._A__value2
0
>>> a.setValue(3,3)
>>> a._value1
3
>>> a._A__value2
3
下面的代码演示了对公有成员、私有成员的访问与修改的方法:
>>> class Fruit: #定义类Fruit
... def __init__(self):
... self.__color='Red' #定义一个私有成员
... self.price=1 #定义一个公有成员
...
...
>>> apple=Fruit() #实例化一个对象
>>> apple.price #显示对象公有数据成员的值
1
>>> apple.price=2 #修改对象公有数据成员的值
>>> apple.price
2
>>> print(apple.price,apple._Fruit__color) #显示对象私有数据成员的值
2 Red
>>> apple._Fruit__color="Blue" #修改对象私有数据成员的值
>>> print(apple.price,apple._Fruit__color)
2 Blue
>>> print(apple.__color) #不能直接访问对象的私有数据成员,出错
Traceback (most recent call last):
File "<pyshell#76>", line 1, in <module>
print(apple.__color)
AttributeError: 'Fruit' object has no attribute '__color'
2.数据成员
数据成员可以大致可以分为两类:属于对象的数据成员和属于类的数据成员。
- 属于对象的数据成员一般在构造方法__init__()中定义,当然也可以在其他成员方法中定义,在定义中访问和在成员方法中访问数据成员时以self作为前缀,同一个类的不同对象的数据成员之间互不影响
- 属于类的数据成员是该类所有对象共享的,不属于任何一个对象,在定义类时这类数据成员一般不在任何一个成员方法的定义中
利用类数据成员的共享性,可以实时获得该类的对象数量,并且控制该类创建的对象最大数量。
>>> class SingleInstance:
... num=0 #定义一个类数据成员
... def __init__(self):
... if SingleInstance.num>0: #在类中成员方法可通过‘类名.类数据成员’来调用类数据成员
... raise Exception('只能创建一个对象')
... #关键字raise用于抛出异常,后面的语句不执行
... SingleInstance.num+=1
...
...
>>> t1=SingleInstance() #实例化对象t1
>>> SingleInstance.num
1
>>> t2=SingleInstance() #实例化对象t2抛出异常,因为只能创建一个对象
Traceback (most recent call last):
File "<pyshell#90>", line 1, in <module>
t2=SingleInstance()
File "<pyshell#84>", line 5, in __init__
raise Exception('只能创建一个对象')
Exception: 只能创建一个对象
3.成员方法
所有实例方法都必须至少有一个名为self的参数,并且必须是方法的第一个形参(如果有多个形参的话),self参数代表当前对象。
在实例方法中访问实例成员时需要以self为前缀,但在外部通过对象名调用对象方法时并不需要传递这个参数。
如果在外部通过类名调用属于对象的公有方法,需要显式为该方法的self参数传递一个对象名,用来明确指定访问哪个对象的成员。
静态成员和类方法都可以通过类名和对象名调用,但不能直接访问属于对象的成员,只能访问属于类的成员。
静态方法和类方法不属于任何实例,不会绑定到任何实例,当然也不依赖于任何实例的状态,与实例方法相比减少很多开销。
类方法一般以cls作为类方法的第一个参数表示该类自身,在调用类方法时不需要为该参数传递值,静态方法则可以不接收任何参数。
静态方法和类方法是(经过修饰)为能在外部调用私有成员的属于类的方法。
>>> class Root: #定义类Root
... __total=0 #类的私有数据成员__total
... def __init__(self,v): #定义构造方法__init__()
... self.__value=v #定义实例的私有数据成员__value
... Root.__total+=1 #在构造方法中调用类的私有数据成员
... def show(self): #定义普通实例方法(公有方法)
... print('self.__value:',self.__value) #调用实例数据成员__value
... print('Root.__total:',Root.__total) #调用类数据成员__total
... @classmethod #修饰器,声明类方法
... def classShowTotal(cls): #定义类方法(以cls作为类方法的第1个参数,调用时不用传值)
... print(cls.__total) #调用类数据成员__total(带前缀cls)
... @staticmethod #修饰器,声明静态方法
... def staticShowTotal(): #定义静态方法(可以没有参数)
... print(Root.__total) #调用类数据成员__total
...
...
>>> r=Root(3) #实例化第一个对象r
>>> r.classShowTotal() #通过对象r来调用类方法
1 #实例对象数为1
>>> r.staticShowTotal() #通过对象r来调用静态方法
1
>>> r.show() #通过对象r来调用普通实例方法
self.__value: 3
Root.__total: 1
>>> rr=Root(5) #实例化第2个对象rr
>>> Root.classShowTotal() #通过类名调用类方法
2 #实例对象数为2
>>> Root.staticShowTotal() #通过类名调用静态方法
2
>>> Root.show() #试图通过类名直接调用实际方法,失败(不知调用谁?r还是rr)
Traceback (most recent call last):
File "<pyshell#116>", line 1, in <module>
Root.show()
TypeError: Root.show() missing 1 required positional argument: 'self'
>>> Root.show(r) #但是可以通过这种方法来调用方法并访问实例成员
self.__value: 3
Root.__total: 2
>>> Root.show(rr) #通过类名调用实例方法时为self参数显式传递对象名
self.__value: 5
Root.__total: 2
4.属性
属性是一种特殊形式的成员方法,综合了公有数据成员和成员方法的优点。
在python3.x中,属性得到了较为完整的实现,支持更加全面的保护机制。
使用@property或property()来声明一个属性。
(1)只读属性
>>> class Test:
... def __init__(self,value):
... self.__value=value #定义一个私有数据成员
... @property #修饰器,定义属性
... def value(self): #只读,无法修改和删除
... return self.__value
...
...
>>> t=Test(3)
>>> t.value #在类Test中value好像是一个成员方法,但修饰后无需加()了
3
>>> t.value=5 #只读属性不允许改值
Traceback (most recent call last):
File "<pyshell#128>", line 1, in <module>
t.value=5
AttributeError: can't set attribute 'value'
>>> t.v=5 #动态增加新成员
>>> t.v
5
>>> del t.v
>>> del t.value
Traceback (most recent call last):
File "<pyshell#132>", line 1, in <module>
del t.value
AttributeError: can't delete attribute 'value'
>>> t.value
3
>>> t=Test(8)
>>> t.value
8
>>> t.value=5
Traceback (most recent call last):
File "<pyshell#136>", line 1, in <module>
t.value=5
AttributeError: can't set attribute 'value'
>>> t._Test__value=10 #修改了值
>>> t.value
10
(2)可读,可写属性
>>> class Test:
... def __init__(self,value):
... self.__value=value
... def __get(self): #定义一个读取私有数据私有成员的方法
... return self.__value
... def __set(self,v): #定义一个修改私有数据私有成员方法
... self.__value=v
... value88=property(__get,__set)
... #定义一个属于类的公有成员方法value88(此称为可读可写属性)
... def show(self):
... print(self.__value)
...
...
>>> t=Test(3)
>>> t.value88 #允许读取属性值
3
>>> t.value88='gg' #允许修改属性值
>>> t.value88
'gg'
>>> t.show() #属性对应的私有变量也得到了相应的修改
gg
>>> del t.value88 #试图删除属性,失败
Traceback (most recent call last):
File "<pyshell#155>", line 1, in <module>
del t.value88
AttributeError: can't delete attribute 'value88'
(3)可读、可修改、可删除的属性
>>> class Test:
... def __init__(self,value):
... self.__value=value
... def __get(self): #可读
... return self.__value
... def __set(self,v): #可写
... self.__value=v
... def __del(self): #可删
... del self.__value
... value=property(__get,__set,__del) #可读可写可删属性
... def show(self):
... print(self.__value)
...
...
>>> t=Test(3)
>>> t.show()
3
>>> t.value
3
>>> t.value=5
>>> t.show()
5
>>> t.value
5
>>> del t.value #删除属性
>>> t.value #对应的私有数据成员已删除
Traceback (most recent call last):
File "<pyshell#176>", line 1, in <module>
t.value
File "<pyshell#168>", line 5, in __get
return self.__value
AttributeError: 'Test' object has no attribute '_Test__value'. Did you mean: '_Test__del'?
>>> t.show()
Traceback (most recent call last):
File "<pyshell#177>", line 1, in <module>
t.show()
File "<pyshell#168>", line 12, in show
print(self.__value)
AttributeError: 'Test' object has no attribute '_Test__value'. Did you mean: '_Test__del'?
>>> t.value=1 #为对象动态增加属性和对应的私有数据成员
>>> t.show()
1
>>> t.value
1
三、继承
1.介绍
继承是用来实现代码复用和设计复用的机制,是面向对象程序设计的重要特性之一。设计一个新类时,如果可以继承一个已有的设计良好的类然后进行二次开发,无疑会大幅度减少开发工作量。
在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类。派生类可以继承父类的公有成员,但是不能继承其私有成员。如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过“基类名.方法名()”的方式来实现这一目的。
python支持多继承,如果父亲中有相同的方法名,而在子类中使用时没有指定父亲名,则python解释器将从左向右按顺序进行搜索。
2.举例
>>> class Person(object): #创建类Person,作为子类Teacher的基类
... def __init__(self,name='',age=20,sex='man'):
... self.setName(name) #通过调用方法进行初始化,这样可以对参数进行更好的控制
... self.setAge(age)
... self.setSex(sex)
... def setName(self,name):
... if not isinstance(name,str):
... raise Exception('name must be string.')
... self.__name=name
... def setAge(self,age):
... if type(age)!=int:
... raise Exception('age must be integer.')
... self.__age=age
... def setSex(self,sex):
... if sex not in ('man','women'):
... raise Exception('sex must be "man" or "women".')
... self.__sex=sex
... def show(self):
... print(self.__name,self.__age,self.__sex,sep='\n')
...
...
>>> class Teacher(Person): #派生类,子类要想用到super(),基类中必须以object为基类
... def __init__(self,name='',age=30,sex='man',department='Computer'):
... super(Teacher,self).__init__(name,age,sex)
... #通过基类构造方法初始化积累的私有数据成员
... #person.__init__(self,name,age,sex) #也可以这样初始化基类的私有数据成员
... self.setDepartment(department) #调用自己的方法初始化派生类的数据成员
... def setDepartment(self,department): #在派生类中新增加的方法
... if type(department)!=str:
... raise Exception('department must br a string.')
... self.__department=department
... def show(self): #覆盖了从父类中继承来的方法
... super(Teacher,self).show()
... #先调用父亲的同名方法,显示从父亲中继承来的数据成员
... print(self.__department) #显示派生类中的私有数据成员
...
...
>>> if __name__=='__main__':
... #创建基类(实例化)对象
... zhangsan=Person('Zhang San',10,'man')
... zhangsan.show()
... print('='*30)
... #创建派生类(实例化)对象
... lisi=Teacher('Li Si',32,'man','Math')
... lisi.show()
... #调用继承的方法修改年龄
... lisi.setAge(40)
... lisi.show()
...
...
Zhang San
10
man
==============================
Li Si
32
man
Math
Li Si
40
man
Math
四、特殊方法
1.介绍
python类有大量地特殊方法,其中比较常见的是构造函数和析构函数,除此之外,python还支持大量地特殊方法,运算符重载就是通过重写特殊方法实现的。
- python中类的构造函数是__init__(),一般用来为数据成员设置初值或进行其他必要的初始化工作,在创建对象时被自动调用和执行。如果用户没有设计构造函数,python将提供一个默认的构造函数用来进行必要的初始化工作
- python中类的析构函数是__del__(),一般用来释放占用的资源,在python删除对象和收回对象空间时被自动调用和执行。如果用户没有编写析构函数,python将提供一个默认的析构函数进行必要的清理工作
2.举例
>>> x=5
>>> dir(x)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_count', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
>>> x='gg'
>>> dir(x)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> x=[]
>>> dir(x)
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> x=set()
>>> dir(x)
['__and__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
3.表格
方法 | 功能说明 |
__new__() | 类的静态方法,用于确定是否要创建对象 |
__init__() | 构造方法,创建对象时自动调用 |
__del__() | 析构方法,释放对象时自动调用 |
__add__() | + |
__sub__() | - |
__mul__() | * |
__truediv__() | / |
__floordiv__() | // |
__mod__() | % |
__pow__() | ** |
__eq__(),__ne__(),__lt__() __le__(),__gt__(),__ge__() | ==,!=,<,<=,>,>= |
__lshift__(),__rshift__() | <<,>> |
__and__(),__or__() __invert__(),__xor__() | &,|,~,^ |
__iadd__(),__isub__() | +=,-+,很多其他运算符也有与之对应的复合赋值运算符 |
__pos__() | 一元运算符+,正号 |
__neg__() | 一元运算符-,负号 |
__contains__() | 与成员测试运算符in对应 |
__radd__(),__rsub__ | 反射加法、反射减法,一般与普通加法和减法具有相同的功能,但操作数的位置或顺序相反,很多其他运算符也有与之对应的反射运算符 |
__abs__() | 与内置函数abs()对应 |
__bool__() | 与内置函数bool()对应,要求该方法必须返回False或True |
__bytes__() | 与内置函数bytes()对应 |
__complex__() | 与内置函数complex()对应,要求该方法必须返回复数 |
__dir__() | 与内置函数dir()对应 |
__divmode__() | 与内置函数divmode()对应 |
__float__() | 与内置函数float()对应,要求该方法必须返回实数 |
__hash__() | 与内置函数hash()对应 |
__int__() | 与内置函数int()对应,要求该方法必须返回整数 |
__len__() | 与内置函数len()对应 |
__next__() | 与内置函数next()对应 |
__reduce__() | 提供对reduce()函数的支持 |
__reversed__() | 与内置函数reversed()对应 |
__round__() | 与内置函数round()对应 |
__str__() | 与内置函数str()对应,要求该方法必须返回str类型的数据 |
__repr__() | 打印、转换、要求该方法必须返回str类型的数据 |
__getitem__() | 按照索引获取值 |
__setitem__() | 按照索引赋值 |
__delattr__() | 删除对象的指定属性 |
__getattr__() | 获取对象指定属性的值,对应成员访问运算符“.” |
__getattribute__() | 获取对象指定属性的值,如果同时定义了该方法与__getattr__(),那么__getattr__()将不会被调用,除非在__getattribute__()中显式调用__getattr__()或者抛出AttributeError异常 |
__setattr__() | 设置对象指定属性的值 |
__base__ | 该类的基类 |
__class__ | 返回对象所属的类 |
__dict__ | 对象所包含的属性与值的字典 |
__subclasses__() | 返回该类的所有子类 |
__call__() | 包含该特殊方法的类的实例可以像函数一样调用 |
__get__() | 定义了这三个特殊方法中任何一个的类称作描述符(descriptor),描述符对象一般作为其它类的属性来使用,这三个方法分别在获取属性、修改属性或者删除属性时被调用 |
__set__() | |
__delete__() |