那个全能方法非常聪明。它使用了一些非常微妙的技巧来完成它的工作。让我们从头开始。
你可能已经知道
装饰器语法只是函数应用的简写,即:
@somedecorator
def somefunc(...):
pass
def somefunc(...):
pass
somefunc = somedecorator(somefunc)
因此,somefunc
实际上是一个 omnimethod
实例,而不是已定义的函数。有趣的是,omnimethod
还实现了 descriptor
接口。如果类属性定义了 __get__
方法,则每当提到该属性时,解释器会调用该对象上的 __get__
方法,并返回该方法而不是返回属性本身。
__get__
方法始终使用实例作为第一个参数,并使用该实例的类作为第二个参数进行调用。如果属性实际上是从类本身查找的,则实例将为 None
。
最后一个诡计是
functools.partial
,这是Python中函数
柯里化的方式。当使用
partial
时,您将传递给它一个函数和一些参数,它会返回一个新函数,当调用它时,它将调用原始函数并附加您稍后传递的任何参数。
omnimethod
使用此技术来填充包装的函数的
self
参数。
这是它的样子。可以从实例中读取
常规方法并调用它,但无法从类本身使用它。您会得到一个未绑定的TypeError。
>>> class Foo(object):
... def bar(self, baz):
... print self, baz
...
>>> f = Foo()
>>> f.bar('apples')
<__main__.Foo object at 0x7fe81ab52f90> apples
>>> Foo.bar('quux')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with
Foo instance as first argument (got str instance instead)
>>> Foo.bar(None, 'quux')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with
Foo instance as first argument (got NoneType instance instead)
>>>
Python提供了一个内置装饰器
classmethod
(还有
staticmethod
,但不用在意),它允许您在类级别使用它,但它从未看到实例。它始终作为第一个参数接收类。
>>> class Foo(object):
... @classmethod
... def bar(cls, baz):
... print cls, baz
...
>>> f = Foo()
>>> Foo.bar('abc')
<class '__main__.Foo'> abc
>>> f.bar('def')
<class '__main__.Foo'> def
>>>
凭借其巧妙的设计,
omnimethod
可以让您兼顾两者。
>>> class Foo(object):
... @omnimethod
... def bar(self, baz):
... print self, baz
...
>>> f = Foo()
>>> Foo.bar('bananas')
None bananas
>>> f.bar('apples')
<__main__.Foo object at 0x7fe81ab52f90> apples
>>>
property
是什么,那么你的Google技能需要提高:搜索“python property”,你很快就会找到像http://docs.python.org/library/functions.html#property这样的东西。从那里,你可以找到像http://docs.python.org/glossary.html#term-decorator这样的东西。 - Chris Morgan