面向对象特殊方法¶
跟运算符无关的特殊方法
类别 | 方法名 |
---|---|
字符串/字节序列表示形式 | __repr__ ,__str__ ,__
format__ ,__bytes__ |
__call__
__len__
__repr__
,__str__
__getitem__
,__setitem__
,__delitem__
__dict__
,dir()
__slots__
__iter__
__getattr__
,__getattribute__
__mro__
,super()
__call__
¶
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
class SpeciaMembers:
# 类的构造方法
def __init__(self):
print("My name is yang")
# 对象的构造方法
def __call__(self):
print("My age is 18")
# 创建一个对象,并且执行类的构造方法
obj = SpeciaMembers()
# 执行对象的构造方法
obj()
# 先执行类的构造方法,然后再执行对象的构造方法
SpeciaMembers()()
输出
➜ python_test python3 024-exercise-1.py
My name is yang
My age is 18
My name is yang
My age is 18
实例2
class Dog(object):
def __init__(self,name):
self.name = name
self.__food = "骨头"
def __call__(self, *args, **kwargs):
print("running call ",args,kwargs)
d = Dog("xxx")()
执行结果
running call () {}
修改成
d = Dog("xxx")
d(1,2,3,name="xxx")
执行结果则为
running call (1, 2, 3) {'name': 'xxx'}
__len__
¶
当要使用内建函数len(),而参数是DictDemo的实例的时候,那一定要实现类型中的__len__()
方法
__repr__
,__str__
¶
__repr__
__str__
# 字符串表示形式, 把一个对象用字符串的形式表达出来以便辨认
# repr 通过 __repr__ 这个特殊方法来得到一个对象的字符串表示形式
# 如果没有实现 __repr__ , 我们在控制台打印一个向量的实例时, 得到的可能就是地址
# __repr__ 和 __str__ 的区别在于, 后者是在str()调用的时候被使用, 或是在用print函数打印一个对象的时候才被调用
# 如果你只想实现两个特殊方法中的一个, __repr__ 会是更好的选择, 因为如果一个对象没有 __str__ 函数, 而Python需要调用它的时候, 解释器会用 __repr__ 代替
class Dog(object):
def __init__(self,name):
self.name = name
self.__food = "骨头"
def __call__(self, *args, **kwargs):
print("running call ",args,kwargs)
def __str__(self):
return "<obj: %s>" % self.name
d = Dog("xxx")
print(d) # __str__
__getitem__
,__setitem__
,__delitem__
¶
用于索引操作,如字典。以上分别表示获取、设置、删除数据
__getitem__
__setitem__
__delitem__
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
class SpecialMembers:
# 当执行obj['value']的时候就会自动执行 __getitem__ 方法, 并且把对象括号内的值当做__getitem__的值
def __getitem__(self,item):
print(item)
def __setitem__(self,key,value):
print(key,value)
def __delitem__(self,key):
print(key)
# 创建一个对象
obj = SpecialMembers()
# 自动执行__getitem__方法
obj['value']
# 自动执行__setitem__方法
obj['k1'] = "values"
# 自动执行__delitem__方法
del obj['key']
输出
➜ python_test python3 024-exercise-2.py
value
k1 values
key
特殊的
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
class SpecialMembers:
# 当执行obj['value']的时候就会自动执行__getitem__方法,并且把对象括号内的值当做__getitem__的值
def __getitem__(self,item):
print(item,type(item),"__getitem__")
def __setitem__(self,key,value):
print(key,value)
def __delitem__(self,key):
print(key)
obj = SpecialMembers()
obj[1:3] # __getslice__/__getitem__
obj[1:3] = [11,22,33] # __setslice__/__setitem__
del obj[1:3] # __delslice__/__delitem__
输出
➜ python_test python3 024-exercise-3.py
slice(1, 3, None) <class 'slice'> __getitem__
slice(1, 3, None) [11, 22, 33]
slice(1, 3, None)
实例2
class Foo(object):
def __init__(self):
self.data = {}
def __getitem__(self, item):
print('__getitem__',item)
return self.data.get(item)
def __setitem__(self, key, value):
print('__setitem__',key,value)
self.data[key] = value
def __delitem__(self, key):
print('__delitem__',key)
f = Foo()
res = f['k1']
f['k2'] = 'xxx'
del f['k1']
print(type(f)) # <class '__main__.Foo'>
print(type(Foo)) # <class 'type'> 类是由type类实例化产生的
__dict__
,dir()¶
__dict__
dir()
__dict__
是一个字典, 用来存储对象属性,其键为属性名,值为属性的值。
dir()
是一个函数, 返回的是一个list
dir()
函数会自动寻找一个对象的所有属性,包括__dict__
中的属性。
__dict__
是dir()
的子集,dir()
包含__dict__
中的属性。
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
class SpeciaMembers:
"""
类的注释
"""
def __init__(self):
self.Name = "yang"
self.Blog = "http://yjj.top"
# 获取类中的成员
print(SpeciaMembers.__dict__)
# 创建一个对象
obj = SpeciaMembers()
# 获取对象中的成员
print(obj.__dict__)
执行结果
{'__doc__': '\n 类的注释\n ', '__dict__': <attribute '__dict__' of 'SpeciaMembers' objects>, '__weakref__': <attribute '__weakref__' of 'SpeciaMembers' objects>, '__module__': '__main__', '__init__': <function SpeciaMembers.__init__ at 0x1024029d8>}
{'Name': 'yang', 'Blog': 'http://yjj.top'}
实例2
class Dog(object):
def __init__(self,name):
self.name = name
self.__food = "骨头"
def __call__(self, *args, **kwargs):
print("running call ",args,kwargs)
print(Dog.__dict__) # 类调用,打印类里面的所有属性,不包括实例属性
d = Dog("xxx")
print(d.__dict__) # 实例调用,打印所有实例属性,不包括类属性
__slots__
¶
如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name
和age
属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性:
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
__iter__
¶
一个对象如果可以被for
循环迭代时,说明对象中有__iter__
方法,
且方法中有yield
值
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
class SpecialMembers:
def __iter__(self):
yield 1
yield 2
yield 3
# 创建一个对象
obj = SpecialMembers()
# 如果执行for循环对象时,自动执行对象的__iter__方法,此时的__iter__就是一个生成器
for i in obj:
print(i)
输出
➜ python_test python3 024-exercise-5.py
1
2
3
MRO列表, super()¶
我们定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表:
>>> C.mro() # or C.__mro__ or C().__class__.mro()
[__main__.C, __main__.A, __main__.B, __main__.Base, object]
MRO列表顺序是通过C3 线性化算法来实现的, 一个类的MRO列表就是合并所有父类的MRO列表, 并遵循以下规则
- 子类永远在父类前面
- 如果有多个父类, 会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择, 选择第一个父类
super原理
def super(cls, inst):
mro = inst.__class__.mro()
return mro[mro.index(cls) + 1]
cls
代表类, inst
代表实例, 上面代码做了两件事
- 获取
inst
的MRO列表 - 查找
cls
在当前MRO列表中的index
, 并返回它的下一个类, 即mro[index + 1]
当我们使用super(cls, inst)
时,
Python会在inst
的MRO列表上搜索cls的下一个类