4.4 对象的方法
1.方法引用
本节我们详细探讨对象的方法,类的方法和对象的方法是一样。我们在定义类的方法时程序没有为类的方法分配内存,而在创建具体实例对象的程序才会为对象的每个数据属性和方法分配内存。我们已经知道定义类的方法是def定义的,具体定义格式与普通函数相似,只不过类的方法的第一个参数需要为self参数。我们可以用普通函数实现对对象函数的引用:
>>>pokemon1 = Charmander('Bang','male',5) >>>getStatus1 = pokemon1.getStatus >>>print getStatus1() [20, 10, 10, 10, 10, 10]
虽然这看上去似乎是调用了一个普通函数,但是getStatus1()这个函数是引用pokm-emon1.getStatus()的,意味着程序还是隐性地加入了self参数。
2.私有化
另外我们再谈谈私有化。使用代码清单4-3,我们发现如果要获取对象的数据属性并不需要通过getName(),getType()等方法,直接在程序外部调用数据属性即可:
>>> print pokemon1.type , pokemon1.getType() ('fire', None) ('fire', None) >>> print pokemon1.gender , pokemon1.getGender() male male
虽然这似乎很方便,但是却违反了类的封装原则。对象的状态对于类外部应该是不可访问的。为什么要这样做?我们查看Python的模块的源码时会发现源码里面定义的很多类,模块中的算法通过使用类实现是很常见的,如果我们使用算法时能够随意访问对象中的数据属性,那么很可能在不经意中修改了算法中已经设置的参数,这是十分糟糕的。尽管我们不会刻意这么做,但是这种无意的改动是常有的事。一般封装好的类都会有足够的函数接口供程序员使用,程序员没有必要访问对象的具体数据属性。
为防止程序员无意地修改了对象的状态,我们需要对类的数据属性和方法进行私有化。Python不支持直接私有方式,但可以使用一些小技巧达到私有特性的目的。为了让方法的数据属性或方法变为私有,只需要在它的名字前面加上双下划线即可,修改Charmander类代码,如代码清单4-3所示:
代码清单4-3 自定义类3
class Charmander: def __init__(self,name,gender,level): self.__type = ('fire',None) self.__gender = gender self.__name = name self.__level = level self.__status = [10+2*level,5+1*level,5+1*level,5+1*level,5+1*level,5+1*level] # 最大 HP,攻击,防御,特攻,特防,速度 def getName(self): return self.__name def getGender(self): return self.__gender def getType(self): return self.__type def getStatus(self): return self.__status def level_up(self): self.__status = [s+1 for s in self.__status] self.__status[0]+=1 # HP每级增加 2点,其余 1点 def __test(self): pass
*代码详见:示例程序/code/4-4.py
>>> pokemon1 = Charmander('Bang','male',5) >>> print pokemon1.type Traceback (most recent call last): File "C:/Users/faker/Desktop/class3.py", line 24, in <module> print pokemon1.type AttributeError: Charmander instance has no attribute 'type' >>>print pokemon1.getType() ('fire', None) >>>pokemon1.test() Traceback (most recent call last): File "C:/Users/faker/Desktop/class3.py", line 26, in <module> pokemon1.test() AttributeError: Charmander instance has no attribute 'test'
现在在程序外部直接访问私有数据属性是不允许的,我们只能通过设定好的接口函数去调取对象的信息。不过通过双下划线实现的私有化实际上是“伪私有化”,实际上我们还是可以做到从外部访问这些私有数据属性。
>>>print pokemon1._Charmander__type ('fire', None)
Python使用的是一种name_mangling技术,将__membername替换成_class__mem-bername,在外部使用原来的私有成员时,会提示无法找到,而上面执行pokemon1._Charmander__type是可以访问。简而言之,确保其他人无法访问对象的方法和数据属性是不可能的,但是使用这种name_mangling技术是一种程序员不应该从外部访问这些私有成员的强有力信号。
可以看到代码中还增加了一个函数level_up(),这个函数用于处理精灵升级时能力的提升。我们不应该在外部修改pokemon的status,所以应准备好接口去处理能力发生变化的情景。函数level_up()仅是一个简单的例子,在工业代码中,这样的函数接口是大量的,程序需要对它们进行归类并附上相应的文档说明。
3.迭代器
我们前面接触到的Python容器对象都可以用for遍历,如代码清单4-4所示:
代码清单4-4 迭代器
for element in [1, 2, 3]: print element for element in (1, 2, 3): print element for key in {'one':1, 'two':2}: print key for char in "123": print char for line in open("myfile.txt"): print line
*代码详见:示例程序/code/4-4.py
这种风格十分简洁方便。for语句在容器对象上调用了iter(),该函数返回一个定义了next()方法的迭代器对象,它将在容器中逐一访问元素。当容器遍历完毕,next()找不到后续元素时,next()会引发一个StopIteration异常,告知for循环终止。例如:
>>> L = [1 , 2 , 3] >>> it = iter (L) >>> it <listiterator object at 0x0302E050> >>> it.next() 1 >>> it.next() 2 >>> it.next() 3
当知道迭代器协议背后的机制后,我们便可以把迭代器加入到自己的类中。我们需要定义一个__iter__()方法,它返回一个有next方法的对象。如果类定义了next(),__iter__()可以只返回self。再次修改类Charmenda的代码,通过迭代器能输出对象的全部信息,如代码清单4-5所示。
代码清单4-5 自定义类4
class Charmander: def __init__(self,name,gender,level): self.__type = ('fire',None) self.__gender = gender self.__name = name self.__level = level self.__status = [10+2*level,5+1*level,5+1*level,5+1*level,5+1*level,5+1*level] self.__info = [self.__name,self.__type,self.__gender,self.__level,self. __status] self.__index = -1 #最大 HP,攻击,防御,特攻,特防,速度 def getName(self): return self.__name def getGender(self): return self.__gender def getType(self): return self.__type def getStatus(self): return self.__status def level_up(self): self.__status = [s+1 for s in self.__status] self.__status[0]+=1 # HP每级增加 2点,其余 1点 def __iter__(self): print '名字 属性 性别 等级 能力 ' return self def next(self): if self.__index ==len(self.__info)-1: raise StopIteration self.__index += 1 return self.__info[self.__index]
*代码详见:示例程序/code/4-4.py
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论