1)构造和析构
(1) 为什么使用__init__()
'''需要初始化对象时就需要重写__init__()方法'''
>>> class Rectangle:
'''定义一个矩形类,
需要长和宽两个参数,
拥有计算周长和面积两个方法。
所以我们需要对象在初始化的时候拥有长宽两个参数,
因此需要用__init__()方法'''
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self):
return (self.x+self.y)*2
def getArea(self):
return self.x * self.y
>>> rect = Rectangle(3, 4)
>>> rect.getPeri()
14
>>> rect.getArea()
12
>>> class A:
def __init__(self):
return 'a'
'''__init__()方法的返回值一定是None,不能是其他'''
>>> a = A()
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
a = A()
TypeError: __init__() should return None, not 'str'
(2) __new__(cls[,...])
事实上,__new__()才是在一个对象实例化的时候调用的第一个方法。它与其他魔法方法不同,它的第一个参数不是self而是这个类(cls),而其他的参数会直接传递给__init__()方法。 __new__()方法需要返回一个实例对象,通常是cls这个类实例化的对象,当然也可以返回其他对象。 __new__()方法平时很少去重写它,一般让Python用默认的方案执行就可以了。但是有一种情况需要重写这个魔法方法,就是当继承一个不可变的类型的时候,它的特性就显得尤为重要了。
(没搞明白)
>>> class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)
>>> a = CapStr('I love chill moon')
>>> a
'I LOVE CHILL MOON'
(3) __del__(self)
如果说__init__()和__new__()方法是对象的构造器的话,那么Python也提供了一个析构器,称为__del__()方法。当对象将要被销毁的时候,这个方法就会被调用。但一定要注意的是,并非del x就相当于自动调用x.__del__(),__del__()方法是当垃圾回收机制回收这个对象的时候调用的。
>>> class C:
def __init__(self):
print('我是__init__()方法,我被调用了')
def __del__(self):
print('我是__del__()方法,我被调用了')
>>> c1 = C()
我是__init__()方法,我被调用了
>>> c2 = c1
>>> c3 = c2
>>> del c1
>>> del c2
>>> del c3
我是__del__()方法,我被调用了
>>> b1 = C()
我是__init__()方法,我被调用了
>>> b2 = b1
>>> a = C()
我是__init__()方法,我被调用了
>>> del a
我是__del__()方法,我被调用了
>>> del b1
>>> del b2
我是__del__()方法,我被调用了
'''猜测:一个实例对象及其衍生出来的(即不是直接由类创造的)
被删干净了才会调用__del__()方法'''
2)算术运算
工厂函数:Python2.2以后对类和类型进行了统一,做法就是将int()、float()、str()、list()、tuple()这些BIF转换为工厂函数:
>>> type(len)
<class 'builtin_function_or_method'> # 普通BIF
>>> type(int)
<class 'type'> # 工厂函数
>>> type(dir)
<class 'builtin_function_or_method'>
>>> type(list)
<class 'type'>
# <class 'type'>其实就是一个类
>>> class A:
pass
>>> type(A)
<class 'type'> # 类对象
'''所谓工厂函数,其实就是一个类对象。调用它们的时候,
事实上就是创建一个相应的实例对象'''
>>> a = int('123')
>>> b = int('456')
>>> a + b
579
'''对象是可以进行计算的。当在求a + b等于多少的时候,
事实上Python就是将两个对象进行相加操作。'''
(1)常见的算术运算
__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) # 定义按位左移位的行为:<<
__rshift__(self, other) # 定义按位右移位的行为:>>
__and__(self, other) # 定义按位与操作的行为:&
__xor__(self, other) # 定义按位异或操作的行为:^
__or__(self, other) # 定义按位或操作的行为:|
>>> class New_int(int):
def __add__(self, other):
return int.__sub__(self, other)
def __sub__(self, other):
return int.__add__(self, other)
>>> a = New_int(3)
>>> b = New_int(5)
>>> a + b
-2
>>> a - b
8
# 也可以自己写代码,不通过调用Python默认的方案
>>> class Try_int(int):
def __add__(self, other):
return self + other
def __sub__(self, other):
return self - other
>>> a = Try_int(1)
>>> b = Try_int(3)
>>> a + b
Traceback (most recent call last):
File "<pyshell#166>", line 1, in <module>
a + b
File "<pyshell#163>", line 3, in __add__
return self + other
File "<pyshell#163>", line 3, in __add__
return self + other
File "<pyshell#163>", line 3, in __add__
return self + other
[Previous line repeated 327 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
'''上面出现了无限递归,因为 return self+other 相当于返回对象本身加另一个对象,
又自动触发调用__add__()方法,就形成了无限递归'''
# 下面这样写就不会触发无限递归了
>>> class New_int(int):
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)
>>> a = New_int(1)
>>> b = New_int(2)
>>> a + b
3
>>> a - b
-1
'''有关算术运算的魔法方法,意思是当对象进行了相关的算术运算,
自然而然就会自动触发对应的魔法方法'''
>>> class int(int):
def __add__(self, other):
return int.__sub__(self, other)
>>> a = int('5')
>>> b = int('3')
>>> a + b
2
(2)反运算
# 以下方法均为 当左操作数不支持相应的操作时被调用
__radd__(self, other) # 定义加法的行为:+
__rsub__(self, other) # 定义减法的行为:-
__rmul__(self, other) # 定义乘法的行为:*
__rtruediv__(self, other) # 定义真除法的行为:/
__rfloordiv__(self, other) # 定义整数除法的行为://
__rmod__(self, other) # 定义取模算法的行为:%
__rdivmod__(self, other) # 定义当被divmod()调用时的行为
__rpow__(self, other) # 定义当被power()调用调用或**运算时的行为
__rlshift__(self, other) # 定义按位左移位的行为:<<
__rrshift__(self, other) # 定义按位右移位的行为:>>
__rand__(self, other) # 定义按位与操作的行为:&
__rxor__(self, other) # 定义按位异或操作的行为:^
__ror__(self, other) # 定义按位或操作的行为:|
什么是反运算:a + b这里a是加数, b是被加数,是a主动。如果a对象的__add__()方法没有实现或者不支持相应的操作,那么Python就会自动调用b的__radd__()方法。
>>> class Nint(int):
def __radd__(self, other):
return int.__sub__(other, self)
>>> a = Nint(5)
>>> b = Nint(3)
>>> a + b
8
# 由于a对象默认有__add__()方法,所以b的__radd__()没有执行
# 于是就有了:
>>> 1 + b
-2
# 注意:对于a+b来说,b的__radd__(self, other)中的self是b对象,other是a对象
# 所以不能这么写:
>>> class Nint(int):
def __rsub__(self, other):
return int.__sub__(self, other)
>>> a = Nint(5)
>>> 3 - a
2
'''因此,对于注重操作数顺序的运算符(如减法、除法、移位),
在重写反运算魔法方法的时候,就一定要注意顺序问题了'''