python魔术方法一
实例化
方法 |
意义 |
__new__ |
实例化一个对象,该方法需要返回一个值,如果该值不是cls 的实例,则不会调用__ini__ ,该方法永远都是一个静态方法 |
| class A: |
| |
| def __new__(cls, *args, **kwargs): |
| print(cls) |
| print(args) |
| print(kwargs) |
| |
| return super().__new__(cls) |
| def __init__(self,x,y): |
| print('init ~~~') |
| self.x = x |
| self.y = y |
| |
| |
| t = A(4,5) |
| print(t.x) |
可视化
方法 |
意义 |
__str__ |
str() 函数、format() 函数、print() 函数调用,需要返回对象的字符串表达。如果没有定义,就去调用__repr__ 方法返回字符串表达,如果__repr__ 没有定义,就直接返回对象的内在地址信息 |
__repr__ |
内建函数repr() 对一个对象获取字符串表达。调用__repr__ 方法返回字符串表达,如果__repr__ 也没有定义,就直接返回object 的定义就是显示内存地址信息 |
__bytes__ |
bytes() 函数调用,返回一个对象的bytes 表达,即返回bytes对象 |
| class Point: |
| def __init__(self,x,y): |
| self.x = x |
| self.y = y |
| def __str__(self): |
| return 'Point({},{})'.format(self.x,self.y) |
| |
| t = Point(4,5) |
| print(type(t)) |
| print(t) |
| print(str(t)) |
| class Point: |
| def __init__(self,x,y): |
| self.x = x |
| self.y = y |
| def __str__(self): |
| return 'Point({},{})'.format(self.x,self.y) |
| |
| def __repr__(self): |
| return 'Point({},{})'.format(self.x,self.y) |
| |
| |
| t = Point(4,5) |
| print(type(t)) |
| print(t) |
| print(str(t)) |
| print([t,str(t)],"{}".format(t)) |
| print(repr(t), [t, str(t)]) |
bool
方法 |
意义 |
__bool__ |
内建函数bool() ,或者对象放在逻辑表达式的位置,调用这个函数返回布尔值。没有定义__bool__() ,就找__len__() 返回长度、非0为真。如果__len__() 也没有定义,那么所有实例都返回真 |
| class B: |
| def __bool__(self): |
| |
| |
| return bool(0) |
| |
| print(bool(B())) |
| class A: pass |
| print(bool(A())) |
| class B: |
| def __len__(self): |
| return 0 |
| |
| print(bool(B())) |
| class B: |
| def __bool__(self): |
| return bool(len(self)) |
| |
| def __len__(self): |
| return 0 |
| |
| |
| print(bool(B())) |
| class B: |
| def __bool__(self): |
| print('bool...') |
| return False |
| def __len__(self): |
| print('len...') |
| return 100 |
| |
| t = B() |
| print(bool(t)) |
| print(len(t)) |
运算符重载
operator
模块提供以下的特殊方法,可以将类的实例使用下面的操作符来操作
运算符 |
特殊方法 |
含义 |
< , <= , == , > , >= , != |
__lt__ , __le__ , __eq__ , __gt__ , __ge__ , __ne__ |
比较运算符 |
* , / , % , ** , divmod |
__mul__ , __truediv__ , __mod__ , __pow__ , __divmod__ |
算数运算符 |
+= , -= , *= , /= , %= , **= |
__iadd__ , __isub__ , __imul__ , __itruediv__ , __imod__ , __ifloordiv__ , __ipow__ |
赋值运算符 |
| class Student: |
| def __init__(self,name,age=20): |
| self.name = name |
| self.age = age |
| |
| def __gt__(self,other): |
| print(self, other) |
| return self.age > other.age |
| |
| def __ge__(self,other): |
| return self.age >= other.age |
| |
| def __lt__(self,other): |
| return self.age < other.age |
| |
| def __eq__(self,other): |
| return self.age == other.age and self.name == other.name |
| |
| def __str__(self): |
| print('-' * 30) |
| return "<Student {} {}>".format(self.name,self.age) |
| |
| t1 = Student('Tom',22) |
| t2 = Student('Jerry') |
| print(t1 > t2) |
| print(t1 < t2) |
| print(t1 >= t2) |
| print(t1 <= t2) |
| print(t2 >= t1) |
| t3 = Student('Tom',22) |
| print(t1 == t3) |
| |
| |
| class Student: |
| def __init__(self,name,score): |
| self.name = name |
| self.score = score |
| |
| def __repr__(self): |
| return "<Student {} {}>".format(self.name,self.score) |
| def __sub__(self,other): |
| print(self) |
| print(other) |
| return self.score - other.score |
| |
| def __isub__(self,other): |
| print('isub...') |
| self.score -= other.score |
| return self |
| |
| t1 = Student('Tom',100) |
| t2 = Student('Jerry',90) |
| print(t1 - t2) |
| tom = Student('Tom',100) |
| jerry = Student('Jerry',90) |
| |
| tom -= jerry |
| print(type(tom)) |
| print(tom) |
| class Student: |
| def __init__(self,name,score): |
| self.name = name |
| self.score = score |
| |
| def __repr__(self): |
| return "<Student {} {}>".format(self.name,self.score) |
| def __sub__(self,other): |
| print(self) |
| print(other) |
| return self.score - other.score |
| |
| def __isub__(self,other): |
| print('isub...') |
| self.score -= other.score |
| return self |
| |
| t1 = Student('Tom',100) |
| t2 = Student('Jerry',90) |
| print(t1 - t2) |
| tom = Student('Tom',100) |
| jerry = Student('Jerry',90) |
| |
| tom -= jerry |
| print(type(tom)) |
| print(tom) |
| |
| |
| |
| |
| |
| |
| |
容器相关的魔术方法
方法 |
意义 |
__len__ |
内建函数 len() ,返回对象的长度(>=0的整数)。如果把对象当做容器类型看,就如同list或者dict。 |
__bool__ |
当使用 bool() 函数调用的时候,如果没有 __bool__() 方法,则会看 __len__() 方法是否存在,存在返回非0为真。 |
__iter__ |
迭代容器时调用,返回一个新的迭代器对象。 |
__contains__ |
in 成员运算符,没有实现,就调用 __iter__ 方法遍历。 |
__getitem__ |
实现 self[key] 访问。对于序列对象,key 接受整数为索引,或者切片。对于set和dict,key 为可哈希的。key 不存在引发 KeyError 异常。 |
__setitem__ |
和 __getitem__ 的访问类似,是设置值的方法。 |
__missing__ |
字典或其子类使用__getitem__() 调用时,key 不存在执行该方法 |
| class A(dict): |
| def __missing__(self,key): |
| print(key) |
| return 0 |
| |
| t = A(a=1,b='abc') |
| print(t,type(t),isinstance(t,dict)) |
| print(t['k']) |
| class Cart: |
| def __init__(self): |
| self.__items = [] |
| |
| def additem(self,item): |
| self.__items.append(item) |
| return self |
| |
| |
| def __len__(self): |
| return len(self.__items) |
| |
| def __repr__(self): |
| return str(self.__items) |
| |
| def __iter__(self): |
| |
| yield from self.__items |
| |
| def __getitem__(self,index): |
| print(index, '+++') |
| return self.__items[index] |
| |
| def __setitem__(self,index,value): |
| self.__items[index] = value |
| |
| def __add__(self,other): |
| |
| return self.additem(other) |
| |
| |
| cart = Cart() |
| cart.additem('apple') |
| cart.additem('banana') |
| cart.additem(3) |
| print(len(cart)) |
| print(cart) |
| |
| for i in cart: |
| print(i) |
| |
| |
| |
| |
| print(3 in cart) |
| print(2 in cart) |
| print(cart[1]) |
| cart[1] = 'banana2' |
| print(cart) |
| |
| cart.additem('orange').additem('pear') |
| print(cart) |
| |
| print(cart + 300 + 200 ) |
方法 |
意义 |
__call__ |
类中定义一个该方法,实例 就可以像函数一样使用 |
| class Fib: |
| def __init__(self): |
| self.items = [0,1,1] |
| |
| def __str__(self): |
| return str(self.items) |
| |
| def __len__(self): |
| return len(self.items) |
| |
| def __iter__(self): |
| return iter(self.items) |
| |
| def __getitem__(self,index): |
| if index < 0: |
| raise IndexError("Index out of range") |
| |
| for i in range(len(self.items),index+1): |
| self.items.append(self.items[i-1] + self.items[i-2]) |
| |
| return self.items[index] |
| |
| |
| |
| |
| |
| |
| __call__ = __getitem__ |
| |
| f = Fib() |
| print(f[10]) |
| print(str(f)) |
| for i in f: |
| print(i) |
| print(len(f)) |
| print('---') |
| print(f[11]) |
| |
| print(f(11)) |
上下文管理
当一个对象同时实现了__enter__()
和__exit__()
方法,它就属于上下文管理的对象
方法 |
意义 |
__enter__ |
进入此对象下关的上下文。如果存在该方法,with 语法会把该方法的返回值作为绑定到as 子句中指定的变量上 |
__exit__ |
退出与此对象的上下文 |
| with open('test') as f: |
| pass |
那么对with
执行顺序的描述
AOP
面向切面编程
| class A: |
| def __init__(self): |
| print(1,'init start ----') |
| |
| def __enter__(self): |
| print(2,'enter start ----') |
| |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| print(3,'exit start ----') |
| |
| with A(): |
| print('4, with start ----') |
| import time |
| time.sleep(3) |
| print('5, with end ----') |
| |
| |
| |
| |
| |
| class A: |
| def __init__(self): |
| print(1,'init start ----') |
| |
| def __enter__(self): |
| return self |
| print(2,'enter start ----') |
| |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| print(3,'exit start ----') |
| |
| t1 = A() |
| |
| with t1 as t2: |
| print(t1," ", t2) |
| print( t1 == t2) |
| print( t1 is t2) |
| import time |
| import datetime |
| def add(x ,y): |
| time.sleep(3) |
| return x +y |
| |
| class A: |
| def __init__(self,fn): |
| print(1,'init start ----') |
| self.__fn = fn |
| |
| def __enter__(self): |
| print(2,'enter start ----') |
| self.start = datetime.datetime.now() |
| return self.__fn |
| |
| def __exit__(self, exc_type, exc_val, exc_tb): |
| print(3,'exit start ----') |
| delta = (datetime.datetime.now() - self.start).total_seconds() |
| print('{} took {}s'.format(self.__fn.__name__,delta)) |
| |
| with A(add) as t: |
| print(t(100,200)) |
- 增强功能
- 在代码执行的前后增加代码,以增强其功能。类似装饰器的功能。
- 资源管理
- 打开了资源需要关闭,例如文件对象、网络连接、数据库连接等。
- 权限验证
- 在执行代码之前,做权限的验证,在
__enter__中处理
| from contextlib import contextmanager |
| import time |
| import datetime |
| |
| def add(x, y): |
| time.sleep(3) |
| return x + y |
| |
| @contextmanager |
| def timeit(fn): |
| print('之前的调用') |
| start = datetime.datetime.now() |
| try: |
| yield fn |
| finally: |
| print('之后的调用') |
| delta = (datetime.datetime.now() - start).total_seconds() |
| print('{} took {}s'.format(fn.__name__,delta)) |
| |
| with timeit(add) as t: |
| print(t(100,200)) |
| |
| |
| |
| |
利用简单的yeild
一次的生成器管理