魔法方法: 构造和析构
__init__(self[,…])— 返回值一定是none.
class A:
def __init__(self):
return 2022
a2 = A()
Traceback (most recent call last):
File "\<pyshell#64>", line 1, in \<module>
a2 = A()
TypeError: __init__() should return None, not 'int'
-
__new__(cls[, …])— 实例化时真正第一个被调用的方法,它跟其他魔法方法不同,它的第一个参数不是 self 而是这个类(cls),而其他的参数会直接传递给__init__方法的 一般不会去重写,只有在特殊的情况下,eg 继承了一个不可变的类,但是又需要做出修改时.__new__方法主要任务时返回一个实例对象.a.>>> class CapStr(str): def __new__(cls, string): string = string.upper() #将调用字符串的upper()方法并赋给string return str.__new__(cls, string) #将新的string传给老的str的__new__方法,返回的对象给我们新的__new__()方法 >>> str1 = CapStr('i am just not capitalized!') >>> str1 'I AM JUST NOT CAPITALIZED!' b.''' Celsius to Fahrenheit ''' class C2F(float): def __new__(cls, arg=0.0): return float.__new__(cls, arg * 1.8 + 32) >>> print(C2F(32)) 89.6 c.定义一个类继承于 int 类型,并实现一个特殊功能:当传入的参数是字符串的时候,返回该字符串中所有字符的 ASCII 码的和(使用 ord() 获得一个字符的 ASCII 码值)。 class Nint(int): def __new__(cls, arg=0): if isinstance(arg, str): total = 0 for each in arg: total += ord(each) arg = total return int.__new__(cls, arg) d. Word继承str但是可以比较输入单词的长度,重写运算,有空格时取空格前面的单词。 class Word(str): def __new__(cls,string): if ' ' in string: new_str = string[:string.index(' ')] #切片得到前面的单词 if new_str: prompt = 'The value contains spaces, truncating to first space!' string = new_str else: #如果第一个单词前面有空格 prompt = 'Oh my gosh, you have space in the front!' print(prompt) return str.__new__(cls, string) # if执行完成后,最后执行return -
__del__(self)— 垃圾回收机制使用, 当del删除实例对象时,如果这个对象的所有引用都被删除时就会被垃圾回收机制干掉,这个时候才会调用内置的__del__方法。__del__方法是当垃圾回收机制回收这个对象的时候调用的>>> class C: def __init__(self): print('This is init method, I am called') def __del__(self): print('This is del method, I am called') >>> c1 = C() This is init method, I am called >>> c2 = c1 >>> c3 = c2 >>> del c1 >>> del c2 >>> del c3 # 最后一个引用被删除时触发 This is del method, I am called -
__str__() and __repr__()__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。解决办法是再定义一个
__repr__()。但是通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法, 直接赋值如下。>>> class Student(object): ... def __init__(self, name): ... self.name = name ... def __str__(self): # 重新定义__str__ ... return 'Student object (name: %s)' % self.name ... >>> print(Student('Michael')) # 这样打印出来的实例,不但好看,而且容易看出实例内部重要的数据。 Student object (name: Michael) >>> s = Student('Michael') >>> s <__main__.Student object at 0x109afb310> # 直接打印出来的实例还是不好看 # 重写__str__ 和 __repr__就好 class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name=%s)' % self.name __repr__ = __str__ # 偷懒写法,定义好__str__()后直接赋值给__repr__()
魔法方法: 算数运算
类 - 属性和方法的封装
类型:整型,字符串,浮点型。。。
-
python 2.2 后作者对两者进行统一,将类型这些BIF函数变为工厂函数(实际是类对象,type(list)–> ‘class’ type)
-
实际上对象是可以相加的(a, b 就是int的实例化对象)
a = int('123')
b = int('234')
a + b
357

- 通过自定义下面的魔法方法可以自定义计算行为

-
举例
__add__ 和 __sub__方法,自己定义的时候注意无限递归的情形>>> 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(6) >>> a + b -3 >>> a - b 9 如果改成下面的形式 class New_int(int): def __add__(self, other): return self + other def __sub__(self, other): return self + other >>> a = New_int(3) >>> b = New_int(6) >>> a + b # 当a调用add的时候返回的self就是a实例, other是b实例,所以self + other 还是a+b 这样又会去调用add方法导致无限递归 Traceback (most recent call last): File "<pyshell#23>", line 1, in <module> a + b File "<pyshell#20>", line 3, in __add__ return self + other File "<pyshell#20>", line 3, in __add__ return self + other File "<pyshell#20>", line 3, in __add__ return self + other [Previous line repeated 1022 more times] RecursionError: maximum recursion depth exceeded # 加上int把对象变成数值就不会了 class New_int(int): def __add__(self, other): return int(self) + int(other) def __sub__(self, other): return int(self) + int(other) -
Divmod() – 得到a//b的余数,eg 5//3 --> 2
divmod(5, 3)
(1, 2)
Eg: 反运算 radd 重写 ---- 注意参数的顺序
>>> a = Nint(3)
>>> b = Nint(5)
>>> a + b
8
>>> 1 + b
6
class Nint(int):
def __radd__(self, other):
return int.__sub__(self, other)
>>> a = Nint(3)
>>> b = Nint(5)
>>> a + b
8
>>> 1 + b # 当前面没有__add__方法时会调用后面的b的__radd__方法进行运算,由于这里我们重写了__radd__, 在这种情况下 int__sub__(self, other) 中self ==b, other == 1, 所以结果是5-1==4
4
魔法方法: 属性访问
- getattr(func, ‘str’, ‘default_message’)
- property — 通过属性设置属性
- 魔法方法控制属性访问
__getattr__(self, name)– 定义当用户试图获取一个不存在的属性时的行为__getattribute__(self, name)– 定义当该类的属性被访问时的行为__setattr__(self, name, value)– 定义当一个属性被设置时的行为__delattr__(self, name)– 定义当一个属性被删除时的行为
行为:首先会访问__getattribute__,如果在属性字典找不到的话就调用__getattr__
class D:
def __getattr__(self, name):
print('getattr')
def __getattribute__(self, name):
print('getattribute')
return super().__getattribute__(name)
def __setattr__(self, name, value):
print('setattr')
super().__setattr__(name, value)
def __delattr__(self,name):
print('delattr')
super().__delattr__(name)
>>> d1 = D()
>>> d1.size
getattribute
getattr
>>> d1.size = 10
setattr
>>> d1.size
getattribute
10
>>> del d1.size
delattr
>>> d1.size
getattribute
getattr

class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def __setattr__(self, name, value):
if name == "square":
self.width = value
self.height = value
else:
(x)self.name = value ==>super().__setattr__(name, value) (最优解,使用基类的魔法方法)
or
(x)self.name = value ==>self.__dict__[name] = value (使用字典中的属性赋值)
# self.name = value 会造成死循环recursion, 在__init__初始化的时候会调用setattr,但是else的语句会继续做赋值运算然后又调用setattr
def getArea(self):
return self.width * self.height
continue…
1938




被折叠的 条评论
为什么被折叠?



