Python的魔术方法一般以__methodname__的形式命名,如:__init__
(构造方法)、 __getitem__
、 __setitem__
、__delitem__
(调用del obj[key]
时对应触发的函数)、 __len__
(对类实例调用len(…)
时对应触发的函数)等。
魔术方法具体有:
__init__(self)
:构造方法__del__
:析构函数,释放对象时使用__getitem__(self,key)
:返回键对应的值(按照索引获取值)__setitem__(self,key,value)
:设置给定键的值(按照索引赋值)__delitem__(self,key)
:删除给定键对应的元素__len__()
:对类实例调用len(…)
时对应触发的函数__cmp_
: 比较运算__call_
:调用__add__
:加运算__sub__
:减运算__mul__
:乘运算__div__
:除运算__mod__
:求余运算__pow__
:幂
需要注意的是,这些成员里面有些是方法,调用时要加括号,有些是属性,调用时不需要加括号。
# coding:utf-8
'''
desc:尝试定义一种新的数据类型
等差数列
'''
class ArithmeticSequence(object):
MAX = 10
def __init__(self, start=0, step=1):
print 'Call function __init__'
self.start = start
self.step = step
self.myData = {}
i = self.start
index = 0
while i <= ArithmeticSequence.MAX:
self.myData[index] = i
i = i + self.step
index += 1
# 定义获取值的方法
def __getitem__(self, key):
print 'Call function __getitem__'
try:
return self.myData[key]
except KeyError:
return self.start + key * self.step
# 定义赋值方法
def __setitem__(self, key, value):
print 'Call function __setitem__'
self.myData[key] = value
# 定义获取长度的方法
def __len__(self):
print 'Call function __len__'
return len(self.myData)
# 定义删除元素的方法
def __delitem__(self, key):
print 'Call function __delitem__'
del self.myData[key]
s = ArithmeticSequence(1, 2)
print s[3] # 9
print len(s)
del s[3] # 删除3这个key
输出结果:
Call function __init__
Call function __getitem__
7
Call function __len__
5
__init__(self)
- 构造方法
如果我们希望在创建某个特定类的任何一个实例时,都执行某些逻辑,我们可以将这个逻辑代码放在这个类的__init__
方法中,这个逻辑通常是一些初始化工作:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
注意到__init__
方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self,因为self就指向创建的这个类实例本身。
与普通的实例方法类似,如果子类不重写 __init__
,实例化子类时,Python interpreter 会自动先调用父类的__init__
;
如果子类重写了 __init__
,实例化子类时,则只会调用子类的 __init__
,此时如果想使用父类的 __init__
,可以使用super函数,如下:
class P(object):
def __init__(self, name, score):
self.name = name
self.score = name
class C(P):
def __init__(self, name, score, age):
# 显式地调用父类的构造函数
super(C, self).__init__(name, score)
self.age = age
c = C('cq', 100, 31)
__new__()
注意:__init__
是实例创建之后调用的第一个方法,而 __new__
更像构造函数,它在__init__
之前被调用。
另外,__new__
方法是一个静态方法,第一参数是cls,__new__
方法必须返回创建出来的实例。
例如,用__new__实现单例模式:
class Singleton(object):
def __new__(cls):
# 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = 'value1'
print obj1.attr1, obj2.attr1
print obj1 is obj2
__del__(self)
- 析构函数
class NewClass(object):
num_count = 0
def __init__(self,name):
self.name = name
self.__class__.num_count += 1
print name,NewClass.num_count
def __del__(self):
self.__class__.num_count -= 1
print "Del",self.name,self.__class__.num_count
a = NewClass("a")
b = NewClass("b")
c = NewClass("c")
del a
del b
del c
注意:用del删除一个对象的时候,不一定会调用__del__
,只有在对象的引用计数为零时,del()才会被执行。
__iter__(self)
和 next(self)
如果一个类想被用于for ... in
循环,类似list或tuple那样,就必须实现一个__iter__()
方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()
方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def next(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration();
return self.a # 返回下一个值
__call__()
- 实例可以像函数一样调用
class Student(object):
def __init__(self):
print '__init__ is called'
def __call__(self):
print '__call__ is called'
s = Student() # __init__ is called
s() # __call__ is called
__str__(self)
- 返回用户看到的字符串
__repr__(self)
- 返回开发者看到的字符串(用于调试)
# test.py
class P(object):
def __str__(self):
return "__str__ called"
def __repr__(self):
return "__repr__ called"
p = P()
可以看下__str__和__repr__的区别:
>>> from test import p
>>> p
__repr__ called
>>> print p
__str__ called
Reference
- https://blog.csdn.net/liweiblog/article/details/54907888
- https://infohost.nmt.edu/tcc/help/pubs/python/web/special-methods.html