文本将介绍一些Python
类中的一些内部函数,他们的名字叫做Magic Method
代码先行 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import sys
import traceback
import inspect
from functools import total_ordering
@total_ordering
class home (object) :
total_item=[]
num=0
def __init__ (self,name) :
self.name=name
self.myitem=[]
self.instance_name=traceback.extract_stack()[0 ][-1 ].split('=' )[0 ]
def add_item (self,item) :
home.total_item.append(item)
self.myitem.append(item)
def my_num (self) :
print self.name+' has ' +str(len(self.myitem))+' items'
def my_what (self) :
if len(self.myitem)==0 :
print 'Nothing'
else :
for i in self.myitem:
print i,
print '\n'
def who (self) :
return self.name
def __len__ (self) :
return len(self.myitem)
def __getattribute__ (self,name) :
if name=='name' :
print '<you have called ' +object.__getattribute__(self,name)+'>'
return object.__getattribute__(self,name)
def __gt__ (self,other) :
if len(self)>len(other):
print 'you stupid ' +self.name+', you buy the most thing'
return True
elif len(self)<len(other):
print 'you stupid ' +other.name+', you buy the most thing'
return False
else :
return self.__eq__(other)
def __eq__ (self,other) :
if len(self)==len(other):
print 'you guys buy the same'
return True
else :
self.__gt__(other)
return False
def __setattr__ (self,name,value) :
if name=='ex' :
print 'you don\'t need a ex'
elif name=='current' :
print 'right, you can set a current value, which is ' +value
self.__dict__[name]=value
else :
self.__dict__[name]=value
def __str__ (self) :
return 'hey, i am ' +self.name
def __iter__ (self) :
self._index=0
return self
def next (self) :
if self._index<len(self.myitem):
self._index+=1
return self.myitem[self._index-1 ]
else :
raise StopIteration
@staticmethod
def num () :
print 'total item: ' ,len(home.total_item)
@staticmethod
def what () :
if len(home.total_item)==0 :
print 'No item yet'
elif len(home.total_item)==1 :
print 'only one item: ' ,home.total_item[0 ]
else :
print 'items are: ' ,
for i in home.total_item:
print i,',' ,
print '\n'
woman=home('may' )
man=home('xuxs' )
woman.add_item('watch' )
woman.add_item('bag' )
woman.add_item('lip_stick' )
man.add_item('phone' )
man.add_item('apple' )
print 'How many items that we bought together?'
home.num()
print 'What are they'
home.what()
print 'The name of the woman is ' , woman.who()
print 'The woman has bought ' ,len(woman),' items, which are below'
man.my_what()
print 'Let us check who bought more'
print man<woman
print 'this class is iterable, the output below is under list(man)'
print list(man)
print 'and iter it again'
print list(man)
man.ex='XXX'
man.current='may'
print man.current
print man
运行的输出如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
total item: 5
items are: watch , bag , lip_stick , phone , apple ,
<you have called may>
3
phone apple
<you have called may>
you stupid may, you buy the most thing
<you have called may>
you stupid may, you buy the most thing
True
children
this class is iterable
['phone', 'apple']
and iter it again
['phone', 'apple']
you don't need a ex
right, you can set a current value, which is may
may
<you have called xuxs>
hey, i am xuxs
步步为营 这段代码包含的东西比较杂,但是大部分的还是很有用,下面是对这里用到的知识点的总结和提炼,以代码为准绳,步步为营。这段代码主要是在讲两个人去买东西,他们都是类home
的实例,只不过一个是家里的男人,一个是家里的女人。他们要各自记住自己买了什么东西,同时作为一个家庭,他们也要知道一共买了多少东西,两个人之间还需要比较一下,提纲挈领的大概就是这么回事。但是中间穿插了很多知识点,在以后的实际开发中可能会用到。
构造函数 __init__
这是我们接触到的第一个Magic Method
,有名字可知,其是一个初始化函数,在类实例化的时候首先自动运行的一个函数(严格来说不是第一个)。举个栗子1
2
3
4
5
6
7
8
9
10
11
12
13
class One :
def __init__ (self,par=None) :
if par == None :
print 'No parameter'
else :
print 'Follow me:' ,par
one1=One()
one2=One('Houa!' )
从输出结果我们看出,在示例化对象一时,自动调用了类里面的__init__
函数,由于这里我们没有传入参数,所以直接输出No parameter
。需要额外注意的是,在这个__init__
函数里,我们使用了默认参数的用法,par=None
,这是函数定义时经常使用的,表示我们不传入该参数时,该参数使用的默认值就是定义时所给定的这个None
,当然我们也可以None
设为我们想设的其他值。我们示例化对象one2
时,我们传入了参数,所以自动调用__init__
并输出了Parameter is Houa!
全局变量和静态方法 如代码中的第8、9行
我们在类的初始化方法(后面介绍)__init__
之前定义了两个变量total_item
和num
分别表示整个家庭所购买的物品和总数,这两个变量在实例化后不同的对象访问都是允许的,且不同的对象内部的这些全局变量都是公共使用的,举个简单的栗子来说1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Two :
a=0
def __init__ (self) :
Two.a=Two.a+1
print Two.a
two1=Two()
two2=Two()
Two()
two1.a=0
Two()
切记,在类内部使用这些变量时,要在变量前写上类名,如Two.a
,由结果可知,各个对象之间没有什么关联,但是类全局变量a
在不同的对象里却是同一个变量,所以才会出现上面的累加效果。但是,我们发现,当我们在类的外部使用像two1.a=0
这样的语句来修改这个全局变量时,并没有成功,最有一个Two()
输出的4
。所以这里我们使用静态方法 来实现,但这不是必须的,首先看栗子,我们在上面的类中加入静态方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Two :
a=0
def __init__ (self) :
Two.a=Two.a+1
print Two.a
@staticmethod
def set_a (a) :
Two.a=a
print Two.a
two1=Two()
Two()
two1.set_a(10 )
Two.set_a(100 )
print two1.a
静态方法由@staticmethod
来修饰,即加在所定义的方法前面,在这里使用静态方法的好处是,我们可以直接使用类名.静态方法
的方式来调用,当然对象名.静态方法
也能调用,但是对于对象的方法就不能使用类名.方法
来调用了。
长度函数 __len__
定义此函数后我们就知道度量长度的内置函数len()
作用在这个对象上式什么意思啦,比如在这里我们是想测量此对象买了多少东西,所以,入代码中的37、38行所定义1
2
def __len__ (self) :
return len(self.myitem)
那么在后面测试中,直接可以使用print len(man)
来打印这个家里的男人买了多少东西,这里输出为2
。简单的测试样例如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Three :
def __init__ (self, data=[]) :
self.data=data
def __len__ (self) :
print 'you involved __len__'
return len(self.data)
three=Three([1 ,2 ,3 ])
print len(three)
调用属性函数 __getattribute__
这个函数是在类的属性,如变量、函数等等被调用时都会自动运行的一个函数,其中传入的参数为这个属性的名称。此函数是Python新类才引入的,所以在定义类时要继承基类object
,这方面知识超出本文范围,请大家自行谷歌 $\leftarrow$点一下就可以哦。1
2
3
4
def __getattribute__ (self,attr) :
if attr=='name' :
print '<you have called ' +object.__getattribute__(self,attr)+'>'
return object.__getattribute__(self,attr)
如上代码段,我们简单实现了当类里面的name
这个变量被调用时就打印<you have called XXX>
这样一个功能,虽然并没有什么卵用。为了防止循环调用,我们需要使用object.__getattribute__(self,attr)
这种形式来调用这些变量。
比较函数 __gt__
和__eq__
这两个分别是大于和等于的比较,主要是实现当两个对象直接使用大于号>
和等于号==
进行比较时会产生什么效果,当然还有<,<=,>=,!=
这些都可以定义,在这里就省略啦!当定义完成之后我们就可以直接来比较对象了,在上述代码中我们想比较谁买的东西多,所以比较的内容就是个子所买东西的数量,直接引用print man<woman
,输出结果则为1
2
3
>>><you have called may>
>>>you stupid may, you buy the most thing
>>>True
第一行输出是因为我们调用了self.name
来打印谁买的多,从而触发了__getattribute__
函数而产生的,第二行输出是比较函数内部输出,第三行是打印返回值。
这是属性函数 __setattr__
这个函数在设置类的变量的值是自定调用,比如说实例化对象时,我们要定义self.name=name
,这里改变了变量的值,所以就会触发此函数,这个函数有变量名和变量的值两个输入参数。利用这一特性我们可以控制哪些值可以更改那些不可以(其他功能大家自己脑洞开发),具体代码段如下1
2
3
4
5
6
7
8
def __setattr__ (self,name,value) :
if name=='ex' :
print 'you don\'t need a ex'
elif name=='current' :
print 'right, you can set a current value, which is ' +value
self.__dict__[name]=value
else :
self.__dict__[name]=value
从这里我们可以看出,当我们要设置ex
这个变量是,是不被允许的,直接打印出你不能有ex
,当然设置current
是被允许的,这就实现了你能有current
不能有ex
。对于其他不需要考虑的变量,我们直接将其加入类内部的变量字典里,以供使用,具体就是self.__dict__[name]=value
对象的字符串表达式 __str__
在没有定义此函数的情况下,当我们打印一个对象时,输出的可能是这个对象的地址,如<__main__.Three instance at 0x104c622d8>
,但是有的时候我们不想要打印这个地址而是其他一些信息,那么我们只要定义这个函数即可。如下代码段1
2
def __str__ (self) :
return 'hey, i am ' +self.name
那么当你打印女人这个对象时print woman
,就会输出hey, i am may
,是不是很好玩啊。
迭代器 __iter__
我们知道Python中for
循环用的相当多,而这些所要循环的对象都是可迭代的,如for i in range(100)
中的range(100)
是一个list,是可迭代的,其实这些都是定义了__iter__
和next
两个函数实现的(前者返回可迭代的对象,后者定义迭代的下一步要干什么)。对于自定义的类,我们也可以使之成为可迭代的,如我们在这里想使得我们的对象man
和woman
都是可迭代的,即可以直接拿到循环上去用,那么我们可以定义这两个函数。如下我们要实现直接使用对象名来迭代产生对象所购买的物品1
2
3
4
5
6
7
8
9
10
def __iter__ (self) :
self._index=0
return self
def next (self) :
if self._index<len(self.myitem):
self._index+=1
return self.myitem[self._index-1 ]
else :
raise StopIteration
其中第二行初始化迭代的位置,next
函数告诉我们下一步是返回当前对象的当前_index
所对应的物品,当迭代完成就会返回一个迭代到结尾这样一个错误。那么当我们调用如下代码段是就明白为什么有相应的输出了1
2
3
4
5
6
7
8
9
10
print 'this class is iterable, the output below is under list(man)'
print list(man)
print 'and iter it again'
print list(man)
这了我们直接使用list(man)
来产生迭代结果的列表这样一个事实来说明我们的对象可迭代。
总结 我们通过一个两人购物的示例来说明了Python中Magic Method
的使用方法,当然这些都是简单粗暴 的例子,只能起到说明问题的作用,具体的灵活使用还有待在具体实践中来体现。
注:代码中14~17行无关紧要,感兴趣的可以自己学习学习。