在python中,有一些内置好的特定的方法(总是被双下划线包围,如__init__),这些方法在进行特定的操作时会自动被调用,称之为魔法方法
1. 构造 __init__ 方法,相当于Java中的构造方法,在实例化的时候会自动调用。__new__方法,在__init__之前被调用,返回的是对象,极少去重写它。当继续一个不可变类型,但是又需要对它进行修改时,可以重新__new__
2. __del__ 析构,销毁对象。垃圾回收(即对某个对象的所有引用都被删除)时才会调用__del__方法,del x只是删除x的引用
3. 对象的算术运算
4. 简单定制: 类的方法名和属性名一样时,属性会覆盖方法。
import time as t
class MyTimer:
def __init__(self):
self.prompt = '未开始计时!'
self.lasted = []
self.start = 0
self.stop = 0
def __str__(self):
return self.prompt
__repr__ = __str__
# 开始计时
def start(self):
self.start = t.localtime()
print('计时开始...')
# 停止计时
def stop(self):
self.stop = t.localtime()
print('计时结束...')
# 内部方法,计算运行时间
def _calc(self):
self.lasted = []
self.prompt = '总共运行了'
for index in range(6):
self.lasted.append(self.stop[index] - self.start[index])
self.prompt += str(self.lasted[index])
5. 属性方法
class C:
def __init__(self, size=10):
self.size = size
def getSize(self):
return self.size
def setSize(self,value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
class C:
def __getattribute__(self, name):
print("getattribute")
return super().__getattribute__(name)
def __getattr__(self,name):
print("getattr")
def __setattr__(self,name,value):
print("setattr")
super().__setattr__(name, value)
def __delattr__(self, name):
print('delattr')
super().__delattr__(name)
注意:在python中实例的属性访问都会经过__getattribute__,如果属性找不到则就会调用__getattr__
死循环陷阱
class Rectangle:
def __init__(self, width=0, height=0):
self.width = width # 自动触发__setattr__
self.height = height
def __setattr__(self, name, value):
if name == 'square':
self.width = value
self.height = value
else:
self.name = value # 再次触发__setattr__,无限递归
def getArea(self):
return self.width * self.width
解决方法:
class Rectangle:
def __init__(self, width=0, height=0):
self.width = width
self.height = height
def __setattr__(self, name, value):
if name == 'square':
self.width = value
self.height = value
else:
super().__setattr__(name,value) # 调用基类的__setattr__
# self.__dict__[name] = value
def getArea(self):
return self.width * self.width
6. 描述符
class MyDecriptor:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
print('getting...')
return self.fget(instance)
def __set__(self, instance, value):
print('setting...')
self.fset(instance, value)
def __delete__(self, instance):
print('deleting...')
self.fdel(instance)
class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x
x = MyDecriptor(getX, setX, delX)
7. 定制容器
class CountList:
def __init__(self, *args):
self.values = [x for x in args]
self.count = {}.fromkeys(range(len(self.values)),0)
def __len__(self):
return len(self.values)
def __getitem__(self,key):
self.count[key] += 1 # 某元素被访问一次,则计数加1
return self.values[key]
c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)
8. 迭代器
class Fibs:
def __init__(self, n=10):
self.n = n
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a+self.b
if self.a > self.n:
raise StopIteration
return self.a
fibs = Fibs(20)
for each in fibs:
print(each)
1
1
2
3
5
8
13
9. __call__方法
对象通过提供__call__(slef, [,*args [,**kwargs]])方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样使用它,也就是说x(arg1, arg2...) 等同于调用x.__call__(self, arg1, arg2)。
class DistanceForm(object):
def __init__(self, origin):
self.origin = origin
print("origin :"+str(origin))
def __call__(self, x):
print("calling, x :"+str(x+1))
本文参考:小甲鱼python基础教程