参考:小甲鱼视频
作用:对类进行“刷机”级的修改
魔法方法的标志:①被__xxx__两条下划线包围:如典型的__init__
问:在定义类的时候,为什么有的时候有这个魔法方法,有的时候没有呢?
答:一般都会有,但是如果不需要传入类的属性参数,那么就不需要有啊
另外注意 在__init__方法的里面不可以写return返回任何东西
一般很少修改,但是有一种情况下:
>>> class Calstr(str):
def __new__(cls,string): #在这里 cls的位置是填str类的别名可以随意取,不构成参数,第二个string参数则特质str类里的传入字符串不能改
string=string.upper()
return str.__new__(cls,string) # 改变父类的__new__ 参数string 同时也是 __init__(self,string)的参数
>>> a=Calstr('aaaaaa')
>>> a
'AAAAAA'
①优先运行:这里看到运行Calstr()就自动执行new方法了,不用a.__new__什么的。
②重写不可改变的方法:继承str这个不可改变的类,所以不可以在init里修改str类,但是我们可以在之前的new里面重写 返回新的 str.__new__( )这个方法执行的结果。也可以在参数赋值给init属性之前,判断参数是不是合理的先行函数。
③_注意在使用new方法的时候,调用了父类的new方法,并且返回了这个值,使用return语句
当不使用return的时候,那么此值会变成为None,也就是默认情况下返回值为None。
>>> class new_int(int):
def __add__(self,other): #当有__add__的类遇到+自动调用此方法 因为+ 就是__add__魔法方法
return int.__sub__(self,other) # 这里一定要加 int.
>>> a =new_int(2)
>>> b=a+1
>>> b
1
>>> #这里说明类内置工厂函数的使用方式
内置工厂函数每个都有__radd__,__rsub__等对应的反运算函数,它表示在a + b的过程中如果a类里面没有定义 +操作,自动转向b,就相当于 b+a
>>> class new_int(int):
def __radd__(self,other): #当有__add__的类遇到+自动调用此方法 因为+ 就是__add__魔法方法
return int.__sub__(self,other) # 这里一定要加 int.
>>> 1 + new_int(2) # 1 就是一个数,不是一个类,所以它自己没有 +方法 但是我又发现int(1)+new_int(2)=1 why???
1
回答:官方文档指出下面两种情况调用:
1. 左操作数不支持相关运算 并且 两个操作数是不同类型时才被调用。(好像后半句是废话)
2.如果右操作数的类型是左操作数类型的子类,并且该子类提供了操作的反射方法,反射方法优先使用!!!(最新官方文档)
另外:getattr(c,’x‘,'如果没有这个属性就显示这里的字符串') 绅士的访问。
以上示例说明访问任何属性之前,都会先执行以上函数。参数都是接受你写入的参数或者值(setattr)
另外:在附加完操作之后,还需要继承Object的属性。
property函数是python标准的描述符,我们也可以自定义自己的描述符(至少含有上面三个函数的一个):
下面代码就是property的原理:
# propperty 描述符到底是怎么实现的??
#它其实也是一个类
class my_property(): #针对一个属性的控制类
def __init__(self,get,set1,delete_): #给这个类输入 获取、修改、删除 等原来针对这个属性操作的方法名字
self.get=get
self.set1=set1
self.delete=delete_
def __get__(self,instance,owner): #在这里可以就是把原来类的修改函数和工厂函数联系起来而__get__下的self.get等形式就是调用原来的方法
return self.get(instance)
#但要注意这里的instance参数是必须要加上的。
def __set__(self,instance,value):
self.set1(instance,value) ##
print(instance,value)
def __delete__(self,instance):
self.delete_(instance)
class C():
def __init__(self):
self._x=None
def get(self):
return self._x
def set1(self,value): # 对_x属性为什么不直接修改呢?还弄个set1函数修改。。
self._x=value # 因为 如果你要限制_x的范围,直接修改你怎么限制,必然是把x设置为私有变量_x再去设置一个函数,去专门修改它。
def delete_(self):
del self._x
x =my_property(get,set1,delete_) #把本来直接修改不能控制范围的缺点,通过设置专门的函数,并把函数还给了原有的属性,是从简单--复杂--简单
## 这就是property的巨大作用
c=C()
c.x='哈哈哈'