Python有一些定制类的特殊方法,如__str__()
、__iter__()
、__getitem__()
,其中一些具有动态特性的方法可以用来很方便地处理某些动态状况。
<h2>Duck-typing
<blockquote>
<p dir="auto">When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.
<p dir="auto"><code>duck-typing是一种编程风格,它的含义是:一个对象的语义,不是由于它继承自特定的类或者实现某个接口,而是由它的属性和方法的集合所决定。也就是说,我们在使用一个对象的时候,不在乎它是什么类型、是否实现了特定的接口,而是在意它有没有我们需要的属性和方法。<br />
其实这就是在没有语言约束的情况下来实现多态,不像C++使用继承和虚函数在语言上设置约束来实现多态,所以就需要程序员来进行约束,好的文档、代码、测试都是很需要的。<br />
在用该风格编码时不要使用像<code>type()、<code>isintance()这样的方法去测试函数中参数的类型,而是直接使用参数来表述行为,如果该参数没有应有的属性或方法,就会报错。<br />
使用<code>__getitem__()来使自己的类表现得和Python内建的<code>list、<code>tuple、<code>dict一样时,就依靠了这种风格,下面给出Wiki上关于<code>duck-typing的Python示例代码:
<pre><code>class Duck:
def quack(self):
print("Quaaaaaack!")
def feathers(self):
print("The duck has white and gray feathers.")
class Person:
def quack(self):
print("The person imitates a duck.")
def feathers(self):
print("The person takes a feather from the ground and shows it.")
def name(self):
print("John Smith")
def in_the_forest(duck):
duck.quack()
duck.feathers()
def game():
donald = Duck()
john = Person()
in_the_forest(donald)
in_the_forest(john)
game()
<p dir="auto"><code>in_the_forest(duck)方法不管duck参数是Duck类型还是Person类型,只要该类型的实例由quack和feathers方法就可以。
<h2>动态化属性和方法的调用
<ul>
<li><code>__getattr__,当调用不存在的属性时,如果存在<code>__getattr__方法,就会调用<code>__getattr方法来尝试获得属性。
<li><code>__call__,使实例本身变成可调用的。<br />
这种完全动态的调用可以应对一些动态情况,例如实现REST API。
<pre><code>class Chain(object):
def __init__(self, path=''):
self._path = path
def __getattr__(self, path):
return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
def __call__(self, attr):
return Chain('%s/%s' % (self._path, attr))
<p dir="auto">这样我们就不用给每个URL对应的API写方法了,采用链式的调用就可以,如<code>schools/status/users,就可以用<code>Chain().schools.status.users。某些REST API会在URL中添加参数,如<code>/schools/users/ID/report,其中<code>ID就是一个参数,是某个学生实际的学号,这时就可以利用<code>__call__将对象变成可调用的,便可完成此功能,调用方式就是<code>Chain().schools.users(ID).report。
<h2>参考资料
<ul>
<li><a href="http://www.liaoxuefeng.com/" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">廖雪峰的Blog
<li><a href="https://www.python.org/doc/" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Python官方文档