Python中常用魔术方法
阅读别人编写的Python代码时,经常会在他们定义的类中看到以“__”为开头和结尾的方法,经过进一步学习后才知道类中实现的这类方法被称为“魔术方法”。“魔术方法”在一些情况下会被自动的调用,通过一些简单的定义就可以实现比较神奇的功能。如果你希望根据自己的需求去实现具有“特殊”功能的类,那么就需要对这些方法进行重写。下面内容将对一些常用的“魔术方法”进行介绍。
1、__init__方法
__init__方法功能有点类似于其它面向对象语言中的构造函数,在类实例化对象时它会被自动的调用。一般情况下,在定义的类中都会实现__init__方法,在__init__方法内根据创建类对象时传入参数对类对象的属性进行初始化操作。
class student(object):def__init__(self, _name, _age):self.name
= _nameself.age
= _agedef get_info(self):print("%s is %d years old" %(self.name, self.age))
测试结果:
>>> stu = student("Michael", 12)>>> stu.get_info()Michael
is 12 years old
2、__new__方法
前面的__init__方法承担了类实例化对象后对类对象属性必要的初始化操作,而__new__方法则是在__init__方法之前被调用创建类对象。与__init__方法不同的是__new__方法必须返回一个值,返回所创建对象的实例。
__new__方法定义形式:
def__new__(cls, *args, **kw):pass
__new__方法的首个参数是cls,因此,它是属于一个类方法,这也是我们可以通过object.__new__来调用它的原因。
不过,一般情况下,在定义的类中很少去重写__new__方法,但在实现单例设计模式时,可通过重写__new__方法实现。
class single(object):_instance
= Nonedef__new__(cls, *args, **kwargs):if cls._instance is None:cls._instance
= super(single, cls).__new__(cls, *args, **kwargs)return cls._instancedef__init(self):pass
上述single类,通过重写了__new__方法,实现了单例设计模式。_instance是single类的属性,用于描述是否已经创建了实例对象。在创建一个single对象时,首先根据类属性_instance判断是否是第一次创建对象,如果是调用父类的__new__方法创建对象,如果不是,就返回之前创建的对象。
测试结果:
>>> obj1 = single()>>> obj2 = single()>>> obj1<__main__.single object at 0x0000000003D44F08>>>> obj2
<__main__.single object at 0x0000000003D44F08>
3、__call__方法
该方法的功能类似于在类中重载()运算符,使得类实例对象可以像调用普通函数那样,以“类对象名()”形式使用,调用的结果即调用到__call__方法。
class call_cls(object):def__call__(self):print("__call__ function...")
测试结果:
>>> obj = call_cls()>>> obj()__call__ function...
4、__str__方法
如果类中实现了__str__方法,当使用print输出对象时,那么就会打印出从这个方法中返回的数据
class cat(object):def__init__(self, _name, _hobby):self.name
= _nameself.hobby
= _hobbydef__str__(self):return ("%s hobby is %s" %(self.name, self.hobby))
测试结果:
>>> Tom = Cat("Tom", "eat fish")>>> print(Tom)Tom hobby
is eat fish
5、__iter__和__next__方法
如果一个类想像list、tuple那样,可以用于for...in循环,那么它就要在内部实现一个__iter__方法,该方法返回一个迭代对象。然后Python的for循环不断的调用该迭代对象的__next__方法来获取循环的下一个值,直到遇到StopIteration异常时退出循环。
现在我们来写一个可用于for...in循环的类,这个类用来计算斐波那契数列
先来看第一种写法:
class Fib_Calc(object):def__init__(self):self.a, self.b
= 0, 1 # 初始化两个计数器a,bdef__next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
class Fib(object):
def__iter__(self):
return Fib_Calc()
Fib类中实现__iter__方法,该方法中要返回一个可迭代对象。该对象是Fib_Calc类的实例化,所以,Fib_Calc中还应包含__next__方法
Fib_Calc类中的__next__方法根据斐波那契数列特点,计算一次结果
测试结果:
>>> fib = Fib()>>> for i in fib:print(i)11
2
3
5
8
13
21
34
55
89
再来看第二种写法:
class Fib(object):def__init__(self):self.a, self.b
= 0, 1 # 初始化两个计数器a,bdef__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 # 返回下一个值
我们可以不像第一种写法那样,直接将__iter__和__next__方法在同一个类中实现。一个类包含__next__方法,这个类就是一个可迭代类,在__iter__方法中只需要返回这个对象自身,那么返回的结果就是一个可迭代对象。
这里同时实现__iter__和__next__方法的对象,也就是我们所说的“迭代器”。
6、__getitem__方法
上面使用__iter__和__next__方法,实现了类能像list和tuple一样使用for...in循环,那么类是否能像list那样按下标取出元素呢?
当然是可以的,如果类要表现得像list那样按照下标取出元素,需要在类中实现__getitem__方法。仍然以斐波拉契数列为例进行演示
class Fib(object):def__getitem__(self, n):a, b
= 1, 1for x in range(n):
a, b = b, a + b
return a
现在,就可以按下标访问数列的任意一项了:
>>> fib = Fib()>>> fib[2]2>>> fib[4]
5
已经实现了下标取数据,但是要像list一样使用切片功能,还需要在__getitem__方法中加入判断。
class Fib(object):def__getitem__(self, n):if isinstance(n, int): # n是索引a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
__getitem__()中检测到以切片方式访问时,获取切片开始和结束位置,计算开始至结束位置范围对应的斐波拉契数组值,并将其放入到一个列表中,待循环结束后返回这个列表。
测试结果:
>>> fib = Fib()>>> fib[4]5>>> fib[:5]
[1, 1, 2, 3, 5]
7、__getattr__方法
一般情况下,如果我们访问到一个对象中不存在的成员属性时,会发生异常
def student(object):def__init__(self, _name):self.name
= _name
>>> stu = student("Li Ming")>>> print(stu.name)Li Ming
>>> print(stu.age)Traceback (most recent call last):
File
"<pyshell#19>", line 1, in <module>print(stu.age)
AttributeError: "student" object has no attribute "age"
很明显,这是因为类中没有age这个属性引起的。除了在类中添加age属性外,Python中还提供了另外一种机制,在类实现__getattr__方法,动态返回一个属性。
>>> stu = student("Li Ming")>>> print(stu.age)100
小结
这里仅介绍的最常用的几个“魔术方法”,通过例子演示,我们可以看到Python编程时使用“魔术方法”去定制自己类的优势所在。Python中还有很多“魔术方法”可供我们去使用,后续接触到时再对本文的内容进行补充!
以上是 Python中常用魔术方法 的全部内容, 来源链接: utcz.com/z/537915.html