魔术方法
特殊属性
属性 | 含义 |
---|---|
__name__ | 类,函数,方法等名字 |
__module__ | 类,函数,实例,方法等,所在的模块名 |
__class__ | 对象或类所属的类 |
__bases__ | 类的基类元组,顺序为他们在基类列表中出现的顺序 |
__doc__ | 类,函数的文档字符串,如果没有定义则为None |
__mro__ | 类的mro,class.mro()返回的结果保存在__mro__ 中。(方法查找顺序) |
__dict__ | 类或实例的属性,可写的字典 |
查看属性
方法 | 意义 |
---|---|
__dir__ | 返回类或者对象的所有成员名称列表。 dir()函数操作实例就是调用 __dir__() 方法 |
如果dir([obj])参数obj包含方法__dir__()
,该方法就将被调用,如果参数obj不包含该方法,那么它将最大限度的搜集属性信息。
dir(obj)对于不同类型的对象obj具有不同的行为:
- 如果对象是模块对象,返回的列表包含魔魁啊的属性名和变量名
- 如果对象是类型或者是类对象,返回的列表包含类的属性名,及他的祖先类的属性名
- 如果是类的实例
- 有
__dir__
方法,返回可迭代对象的返回值 - 没有
__dir__
方法,则尽可能收集是的属性名,类的属性和祖先类的属性名
- 有
- 如果obj不写,返回列表包含内容也有不同
- 在模块中,返回模块的属性和变量名
- 在函数中,返回本地作用于的变量名
- 在方法中,返回本地作用域的变量名
内建函数
- locals()返回当前作用于中的变量字典
- globals()当前模块全局变量的字典
魔术方法
分类:
-
创建,初始化,销毁
__new__
__init__
__del__
-
可视化
-
hash
-
bool
-
运算符重载
-
容器和大小
-
可调用对象
-
反射
-
描述器
-
其他杂项
实例化
方法 | 意义 |
---|---|
__new__ | 实例化一个对象,该方法需要返回一个值,如果该值不是cls的实例,则不会调用__init__ ,该方法永远是静态方法 |
class A:
def __new__(cls,*args,**kwargs):
print(args,kwargs)
print(cls)
return super().__new__(cls)
该方法很少使用,即使创建了该方法,也会使用return super().__new__(cls)
基类object的方法来创建实例并返回。
构造器
方法 | 意义 |
---|---|
__init__ | 实例化后会做出厂配置,一般继承类自身实现了该方法,还应调用父类的该方法 |
class P:
def __init__(self):
self.a = 50
class A(P):
def __init__(self):
super().__init__()
a = A()
a.__dict__#{'a':50}
析构器
方法 | 意义 |
---|---|
__del__ | 对象销毁时会调用该方法,做清理工作 |
可视化
方法 | 意义 |
---|---|
__str__ | str,format,print,函数调用需要返回对象的字符串表达,如果没有定义,就去调用__repr__ 方法返回字符串表达,如果__repr__ 也没有定义,就直接返回对象的内存地址信息 |
__repr__ | 内建函数repr()对uige对象获取字符串表达 调用 __repr__ 方法返回字符串表达,如果__repr__ 也没有定义,就直接返回对象的内存地址信息 |
__bytes__ | bytes()函数调用,返回一个对象的bytes表达,即返回bytes对象 |
class A:
def __init__(self):
self.a = 100
def __repr__(self):
return f"repr {self.a}"
def __str__(self):
return f"str {self.a}"
def __bytes__(self):
return self.a.encode()
a = A()
print(a,[a])
print('{}'.format(a))
print(bytes(a))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RO8v82bW-1572778904434)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571889091345.png)]
注意不能通过是否带有引号来判断输出值类型,类型判断需要使用type或isinstance
hash
方法 | 意义 |
---|---|
__hahs__ | 内建函数hash()调用的返回值,返回一个整数,如果定义这个方法该类的实例就可以hash,如果只有hash没有eq,那么遇到哈希冲突时就不知道两个对象是否相等,此时就不能够去重,只能作为set或dict的key |
__eq__ | 对应==操作符,判断2个对象内容是否相等,返回bool值 定义了这个方法,如果不提供 __hahs__ ,那么实例将不可hash |
思考:
1.list类实例为什么不可hash?
- 所有类都继承object,而该类实现了hash,所以list类就覆盖了obj的hash方法,实现
__hash__ = None
2.functools.lru_cache使用到的functools._HashedSeq类继承自list,为什么可以hash?
- 该类中实现的hash返回值为哈希一个元组的值
练习
设计二位坐标类Point,使其可以成为hash的类型,不比较两个坐标的实例是否相等
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x,self.y))
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __repr__(self):
return f"{self.x,self.y}"
p1 = Point(4,5)
p2 = Point(4,5)
{p1,p2}#->{(4,5)}
bool
方法 | 意义 |
---|---|
__bool__ | 内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。没有定义__bool__() ,就找__len__() 返回长度,非零为真。如果没有__len__() 那么所有实例返回真 |
运算符重载
operator模块提供以下的特殊方法,可以将类的实例使用下面的操作符来操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBZSN8JB-1572778904436)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1571900449500.png)]
实现两个实例相减
class A:
def __init__(self,x,y):
self.x = x
self.y = y
def __sub__(self,other):
return A(self.x-other.x,self.y-other.y)
def __repr__(self):
return f"{self.x,self.y}"
a = A(4,5)
a - a#->(0, 0)
__isub__
方法定义,一般会in-place就地修改
如果没有定义,则会调用__sub__
实现了__eq__
可以推断出不等
实现了__gt__
可以推断出小于
实现了__ge__
可以推断出小于等于
也就是用了3个方法,就可以把剩下的推断出结果。
运算符重载应用场景
往往是用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达式,例如上例中的对 - 进行了运算符重载,实现了类的二元操作
提供运算符重载,比直接提供加法要更加适合该领域内使用的习惯。
int类,几乎实现了所有的操作符,可以作参考。
容器相关方法
方法 | 意义 |
---|---|
__len__ | 内建函数len(),返回对象的长度(>=0的整数),如果把对象当作容器类型看,就如同list或者dict bool()函数调用的时候,如果没有实现 __bool__() 则会调用该方法, |
__iter__ | 迭代容器时,调用,返回一个新的迭代器对象 |
__contains__ | in 成员运算符,没有实现,就调用__iter__ 方法遍历 |
__getitem__ | 实现self[key]访问,序列对象,key接受整数为索引,或者切片,对于set或者dict,key为hashable。key不存在引发KeyError |
__setitem__ | 和__getitem__ 的访问类似,是设置值的方法 |
__missing__ | 字典或其子类使用__getitem__ 调用时,key不存在执行该方法 |
可调用对象
方法 | 意义 |
---|---|
__call__ | 类中定义一个该方法,实例就可以像函数一样调用 |
可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用
练习:
定义一个fib数列类,方便调用,计算第n项,增加迭代方法,返回数列长度,和索引
class Fib:
def __init__(self):
self.items = [0,1,1]
def __iter__(self):
return iter(self.items)
def __len__(self):
return len(self.items)
def __call__(self,index):
if index < 0:
raise IndexError
for i in range(len(self),index + 1):
self.items.append(self.items[i-1] + self.items[i-2])
return self.items[index]
def __str__(self):
return str(self.items)
f = Fib()
print(f(6))
raise IndexError
for i in range(len(self),index + 1):
self.items.append(self.items[i-1] + self.items[i-2])
return self.items[index]
def __str__(self):
return str(self.items)
f = Fib()
print(f(6))