魔术方法
- 创建、初始化与销毁
- hash
- bool
- 可视化
- 运算符重载
- 容器和大小
- 可调用对象
- 上下文管理
- 反射
- 描述器
- 其它杂项
创建、初始化与销毁
__init__方法
__new__方法
__del__方法
class A:
def __new__(cls, *args, **kwargs):
print(cls)
print(args)
print(kwargs)
# return None
return super().__new__(cls)
def __init__(self, name):
print('init')
self.name = name
a = A('tom')
print(a)
print(a.name)
__new__方法
实例化一个对象
该方法返回一个值,如果该值不是cls的实例,则不会调用__init__该方法永远是静态方法
__new__方法很少使用,即使创建了该方法,也会使用return super().new(cls)基类object的方法来创建实例并返回
__init__方法
初始化方法
__del__方法
一般用于结束时归还系统资源,手动调用并不会删除指定实例,只有当引用计数为零时进行清理工作
hash
__hash__
内建函数hash()调用的返回值,返回一个整数(int)。
如果定义这个方法该类实例就可hash。
__eq__
对应==操作符,判断2个对象是否相等,返回bool值
print(hash(1))
print(hash(2))
print(hash('abc'))
print(hash('abc'))
print(hash('abcd'))
print(hash('123'))
print(hash((1,)))
print(hash((1,'a')))
hash(x) x都一样 求得hash应该不变的 幂等性 一般来说 x 不一样 hash应该不同
不同的hash算法 hash冲突 不同的x求得同样的hash值
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
def __repr__(self):
return self.name
print(hash(A('tom')))
print((A('tom'), A('tom')))
print([A('tom'), A('tom')])
print('~~~~~~~')
s = {A('tom'), A('tom')}
print(s) # 没有去重
print({tuple('t'), tuple('t')})
print({('tom',),('tom',)})
print({'tom', 'tom'})
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return self.name
print(hash(A('tom')))
print((A('tom'), A('tom')))
print([A('tom'), A('tom')])
print('~~~~~~~')
s = {A('tom'), A('tom')}
print(s)
__hash__方法只是返回一个hash值座位set的key,但是去重需要__eq__来判断2个对象是否相等,hash值相等,只是hash冲突,不能说明两个对象是相等的。
因此,一般来说提供__hash__方法是为了作为set或者dict的key,所以去重要同时提供__eq__方法。
不可hash对象isinstance(p1, collections.Hashable)一定为False
from collections import Hashable
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
p1 = Point(4, 5)
p2 = Point(4, 5)
print(hash(p1))
print(hash(p2))
print(p1 is p2)
print(p1 == p2)
print(hex(id(p1)), hex(id(p2)))
print(set((p1, p2)))
print(isinstance(p1, Hashable))
bool
__bool__
内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。
没有定义__bool__(),就找__len__()返回长度,非0为真。
如果__len__()也没有定义,那么所有实例都返回真。
class A: pass
print(bool(A()))
if A():
print('real A')
class B:
def __bool__(self):
return False
print(bool(B))
print(bool(B()))
if B():
print('real B')
class C:
def __len__(self):
return 0
print(bool(C()))
if C():
print('real C')
class A:
def __bool__(self):
return True
def __len__(self):
return 0
if A():
print('True')
可视化
__repr__
内建函数repr()对一个对象获取字符串表达。
调用__repr__方法返回字符串表达,如果__repr__也没有定义,直接返回object的定义
就是现实内存地址信息
__str__
str()函数、format()函数、print()函数调用,需要返回相对的字符串表达。如果没有定义,就去调用__repr__方法返回字符串表达,如果__repr__没有定义,直接返回对象的内存地址信息
__bytes__
bytes()函数调用,返回一个对象的bytes表达 即返回bytes对象
class A:
def __init__(self, name):
self.name = name
def __repr__(self):
return 'repr name={}'.format(self.name)
def __str__(self):
return 'str name={}'.format(self.name)
def __bytes__(self):
# return self.name.encode()
import json
return json.dumps(self.__dict__).encode()
print(A)
print(A('tom'))
print(str(A('tom')))
print('{}'.format(A('jerry')))
print(repr(A('tom')))
print(repr('{}'.format(A('jerry'))))
print('----')
a = A('tom')
print(a)
print([a, a])
print(str({a, a}))
print('{}'.format(a))
print('-----')
print('{}'.format(*{a, a}))
print('{}'.format({a, a}))
print('~~~~')
print(bytes(a))
s = 1
print(s)
s1 = '2'
print(s1)
print([s, s1])
运算符重载
__lt__: <
__le__: <=
__eq__: ==
__gt__: >
__ge__: >=
__ne__: !=
__add__: + __iadd__: +=
__sub__: - __isub__: -=
__mul__: * __imul__: *=
__truediv__: / __itruediv__: /=
__mod__: % __imod__: %=
__floordiv__: // __ifloordiv__: //=
__pow__: ** __ipow__: **=
__divmod__: divmod
class A:
def __init__(self, name, age=18):
self.name = name
self.age = age
def __sub__(self, other):
return self.age - other.age
def __isub__(self, other):
# return 5
# self.age -= other.age
# return self # 返回自身 id不变
return self.__class__(self.name, self - other) # 重新构建实例 id变化
tom = A('tom')
jerry = A('jerry', 16)
print(tom - jerry)
print(id(tom))
# tom = tom - jerry
# print(tom)
tom -= jerry
print(tom)
print(id(tom))
运算符重载应用场景
往往是用面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式。例如,上例中对运算符进行了重载,实现了新的操作。