1.构造和析构 _ _ init_ (self[,…]),在类定义时有时写__init_()方法,有时不写,只有当我们需要对一个对象进行初始化操作时,才会重写__init__()方法。 init方法必须返回一个None对象,不能使用return语句.init 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。(前面一篇讲过,这里就不再细说)
new(cls[,…]) ,__new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化, __new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。只有__new__执行完后,开辟好地址后,__init__才能工作,结合到代码,也就是__new__的返回值正是__init__中self。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, name, age):
if age > 0 and age >> from datetime import date
>>> today = date.today() #创建对象
>>> print(today)
2021-01-18
>>> today
datetime.date(2021, 1, 18)
直接输出 today 对象和调用 print 函数打印 today 对象的输出是不一样的。直接输出 today 对象的结果为 datetime.date(2021, 1, 18) ,调用 print 函数打印的输出为 2021-01-18 。这是因为**调用 print 函数打印 today 对象隐式调用了 str() 方法,**而 str() 方法会隐式地调用对象的 str() 方法。直接输出对象会隐式的调用对象的 repr() 方法。
直接调用 str() 方法和 repr() 方法进行输出。
>>> from datetime import date
>>> today = date.today()
>>> str(today)
'2021-01-18'
>>> repr(today)
'datetime.date(2021, 1, 18)'
类中不包含 str() 和 repr()
>>> class Dog:
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
>>> my_dog = Dog("willie", 3)
>>> my_dog
>>> print(my_dog)
在 Dog 类中,我们没有定义方法 __str__ 和 __repr__ 。可以看到在没有定义 __str__ 和 __repr__ 方法的情况下,不管是直接输出对象还是调用 print() 函数进行输出,输出结果都是 。在这种情况下使用的是缺省的 __str__() 和 __repr__() 。
类中包含 str()
class Dog:
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
...
... def __str__(self):
... return f"{self.__class__.__name__}({self.name}, {self.age})"
...
...
>>> my_dog = Dog("willie", 3)
>>> my_dog
>>> print(my_dog)
Dog(willie, 3)
在添加 __str__ 方法之后,对对象直接进行输出的结果和没有添加方法 __str__() 是一样的。但是调用 print() 函数进行输出时,输出结果变成了 Dog(willie, 3),这是因为在定义了 __str__() 方法之后,调用 print() 函数进行输出时,调用了类的 __str__() 方法。
类中包含 str() 和 repr()
>>> class Dog:
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
...
... def __str__(self):
... return f"{self.__class__.__name__}({self.name}, {self.age}),__str__()"
...
...
... def __repr__(self): # 采用f-string
... return f"{self.__class__.__name__}({self.name}, {self.age}),__repr__()"
...
...
>>> my_dog = Dog("willie", 3)
>>> my_dog
Dog(willie, 3),__repr__()
>>> print(my_dog)
Dog(willie, 3),__str__()
类中包含 repr()
class Dog:
... def __init__(self, name, age):
... self.name = name
... self.age = age
...
...
... def __repr__(self):
... return f"{self.__class__.__name__}({self.name}, {self.age})"
...
...
>>> my_dog = Dog("willie", 3)
>>> my_dog
Dog(willie, 3)
>>> print(my_dog)
Dog(willie, 3)
在去掉 str() 方法之后,不管是直接输出对象还是调用 print() 函数进行输出,输出结果都是 Dog(willie, 3)。这表明,当类中只包含 repr() 方法时,不管是直接输出还是调用 print() 函数进行输出,都会调用类的 repr() 方法。
小结:当自定义类中没有定义 str() 和 repr() 时,在进行对象的输出时,会调用默认的 str() 和 repr() ;当类中只包含 str() 时,调用 print() 函数进行对象的输出,会调用 str(),直接输出调用默认的 repr();当类中既包含 str() 又包含 repr() 时,调用 print() 函数进行对象的输出,会调用 str(),直接输出会调用 repr();当类中只包含 repr() 时,调用 print() 函数进行对象的输出和直接输出都会调用 repr()。str() 用于为最终用户创建输出,而 repr() 主要用于调试和开发。为任何自定义的类添加 repr() 方法。
访问属性的魔法方法 getattr(self,name):定义当用户试图获取一个不存在的属性时的行为; getattribute(self,name):定义当该类的属性被访问时的行为; setattr(self,name,value):定义当一个属性被设置时的行为;delattr(self,name):定义当一个属性被删除时的行为;
在访问属性的方法调用的时候,会先调用__getattribute__(self,name)方法,当属性不存在时再调用__getattr__(self,name)方法,
class Test:
def __getattr__(self, name):
print('__getattr__')
def __getattribute__(self, name):
print('__getattribute__')
def __setattr__(self, name, value):
print('__setattr__')
def __delattr__(self, name):
print('__delattr__')
>>> t=Test()
>>> t.x
__getattribute__
上述代码所示,x并不是Test类实例t的一个属性,首先去调用__getattribute__() 方法,得知该属性并不属于该实例对象;但是,按照常理,t.x应该打印__getattribute__和__getattr__,但实际情况并非如此,为什么呢?难道以上Python的规定无效吗? 原因:实例对象属性寻找的顺序如下:
① 首先访问__getattribute__()魔法方法(隐含默认调用,无论何种情况,均会调用此方法)
② 去实例对象t中查找是否具备该属性:t.__dict__中查找,每个类和实例对象都有一个 __dict__的属性
③ 若在t.__dict__中找不到对应的属性, 则去该实例的类中寻找,即 t.class.dict
④ 若在实例的类中也招不到该属性,则去父类中寻找,即 t.class.bases.__dict__中寻找
⑤ 若以上均无法找到,则会调用 __getattr__方法,执行内部的命令(若未重载 getattr 方法,则直接报错:AttributeError)
以上几个流程,即完成了属性的寻找。
但是,以上的说法,并不能解释为什么执行 t.x 时,不打印 getattr 啊?
问题就出在了步骤的第④步,因为,一旦重载了__getattribute__()方法,如果找不到属性,则必须要手动加入第④步,否则无法进入到 第⑤步 (getattr)的。
class Test:
def __getattr__(self, name):
print('__getattr__')
def __getattribute__(self, name):
print('__getattribute__')
object.__getattribute__(self, name) # super().__getattribute__(self, name)也可以
def __setattr__(self, name, value):
print('__setattr__')
def __delattr__(self, name):
print('__delattr__')
>>> t=Test()
>>> t.x
__getattribute__
__getattr__
基本的魔法方法
__new__(cls[, ...])
1. __new__ 是在一个对象实例化的时候所调用的第一个方法
2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法
3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用
4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string
__init__(self[, ...]) 构造器,当一个实例被创建的时候调用的初始化方法
__del__(self) 析构器,当一个实例被销毁的时候调用的方法
__call__(self[, args...]) 允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b)
__len__(self) 定义当被 len() 调用时的行为
__repr__(self) 定义当被 repr() 调用时的行为
__str__(self) 定义当被 str() 调用时的行为
__bytes__(self) 定义当被 bytes() 调用时的行为
__hash__(self) 定义当被 hash() 调用时的行为
__bool__(self) 定义当被 bool() 调用时的行为,应该返回 True 或 False
__format__(self, format_spec) 定义当被 format() 调用时的行为
有关属性
__getattr__(self, name) 定义当用户试图获取一个不存在的属性时的行为
__getattribute__(self, name) 定义当该类的属性被访问时的行为
__setattr__(self, name, value) 定义当一个属性被设置时的行为
__delattr__(self, name) 定义当一个属性被删除时的行为
__dir__(self) 定义当 dir() 被调用时的行为
__get__(self, instance, owner) 定义当描述符的值被取得时的行为
__set__(self, instance, value) 定义当描述符的值被改变时的行为
__delete__(self, instance) 定义当描述符的值被删除时的行为
比较操作符
__lt__(self, other) 定义小于号的行为:x = y 调用 x.__ge__(y)
算数运算符
__add__(self, other) 定义加法的行为:+
__sub__(self, other) 定义减法的行为:-
__mul__(self, other) 定义乘法的行为:*
__truediv__(self, other) 定义真除法的行为:/
__floordiv__(self, other) 定义整数除法的行为://
__mod__(self, other) 定义取模算法的行为:%
__divmod__(self, other) 定义当被 divmod() 调用时的行为
__pow__(self, other[, modulo]) 定义当被 power() 调用或 ** 运算时的行为
__lshift__(self, other) 定义按位左移位的行为:
__and__(self, other) 定义按位与操作的行为:&
__xor__(self, other) 定义按位异或操作的行为:^
__or__(self, other) 定义按位或操作的行为:|
反运算
__radd__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rsub__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rmul__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rtruediv__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rfloordiv__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rmod__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rdivmod__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rpow__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rlshift__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rrshift__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rand__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__rxor__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
__ror__(self, other) (与上方相同,当左操作数不支持相应的操作时被调用)
增量赋值运算
__iadd__(self, other) 定义赋值加法的行为:+=
__isub__(self, other) 定义赋值减法的行为:-=
__imul__(self, other) 定义赋值乘法的行为:*=
__itruediv__(self, other) 定义赋值真除法的行为:/=
__ifloordiv__(self, other) 定义赋值整数除法的行为://=
__imod__(self, other) 定义赋值取模算法的行为:%=
__ipow__(self, other[, modulo]) 定义赋值幂运算的行为:**=
__ilshift__(self, other) 定义赋值按位左移位的行为:=
__iand__(self, other) 定义赋值按位与操作的行为:&=
__ixor__(self, other) 定义赋值按位异或操作的行为:^=
__ior__(self, other) 定义赋值按位或操作的行为:|=
一元操作符
__pos__(self) 定义正号的行为:+x
__neg__(self) 定义负号的行为:-x
__abs__(self) 定义当被 abs() 调用时的行为
__invert__(self) 定义按位求反的行为:~x
类型转换
__complex__(self) 定义当被 complex() 调用时的行为(需要返回恰当的值)
__int__(self) 定义当被 int() 调用时的行为(需要返回恰当的值)
__float__(self) 定义当被 float() 调用时的行为(需要返回恰当的值)
__round__(self[, n]) 定义当被 round() 调用时的行为(需要返回恰当的值)
__index__(self) 1. 当对象是被应用在切片表达式中时,实现整形强制转换
2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__
3. 如果 __index__ 被定义,则 __int__ 也需要被定义,且返回相同的值
上下文管理(with 语句)
__enter__(self) 1. 定义当使用 with 语句时的初始化行为
2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定
__exit__(self, exc_type, exc_value, traceback) 1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么
2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作
容器类型
__len__(self) 定义当被 len() 调用时的行为(返回容器中元素的个数)
__getitem__(self, key) 定义获取容器中指定元素的行为,相当于 self[key]
__setitem__(self, key, value) 定义设置容器中指定元素的行为,相当于 self[key] = value
__delitem__(self, key) 定义删除容器中指定元素的行为,相当于 del self[key]
__iter__(self) 定义当迭代容器中的元素的行为
__reversed__(self) 定义当被 reversed() 调用时的行为
__contains__(self, item) 定义当使用成员测试运算符(in 或 not in)时的行为