Python中常用魔术方法

Python中常用魔术方法[Python基础]

阅读别人编写的Python代码时,经常会在他们定义的类中看到以“__”为开头和结尾的方法,经过进一步学习后才知道类中实现的这类方法被称为“魔术方法”。“魔术方法”在一些情况下会被自动的调用,通过一些简单的定义就可以实现比较神奇的功能。如果你希望根据自己的需求去实现具有“特殊”功能的类,那么就需要对这些方法进行重写。下面内容将对一些常用的“魔术方法”进行介绍。

1、__init__方法

__init__方法功能有点类似于其它面向对象语言中的构造函数,在类实例化对象时它会被自动的调用。一般情况下,在定义的类中都会实现__init__方法,在__init__方法内根据创建类对象时传入参数对类对象的属性进行初始化操作。

class student(object):

def__init__(self, _name, _age):

self.name = _name

self.age = _age

def 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 = None

def__new__(cls, *args, **kwargs):

if cls._instance is None:

cls._instance = super(single, cls).__new__(cls, *args, **kwargs)

return cls._instance

def__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 = _name

self.hobby = _hobby

def__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,b

def__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)

1

1

2

3

5

8

13

21

34

55

89

再来看第二种写法:

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 # 返回下一个值

我们可以不像第一种写法那样,直接将__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, 1

for 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

回到顶部