在阅读一些python模块时,我遇到了这个装饰器类:
# this decorator lets me use methods as both static and instance methods
class omnimethod(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return functools.partial(self.func, instance)
我对装饰器的了解是,可以扩展功能(例如,用于功能)。有人可以这么善良并向我解释为什么上面的课程是有用的,它是如何工作的?
它以这种方式用于代码:
@omnimethod:
def some_function(...):
pass
另一个问题:
I encountered this piece of code in the same file:
@property
def some_other_function(...):
pass
@property
未在文件中的任何位置定义。这是一些标准的装饰者吗?如果是的话,它会做什么?谷歌无法帮助我解决这个问题。
顺便说一下,这里是我找到代码的来源:http://code.xster.net/pygeocoder/src/c9460febdbd1/pygeocoder.py
答案 0 :(得分:5)
全方位非常聪明。它使用一些非常微妙的技巧来完成它的工作。让我们从头开始。
你可能已经知道decorator syntax只是功能应用的糖,即:
@somedecorator
def somefunc(...):
pass
# is the same thing as
def somefunc(...):
pass
somefunc = somedecorator(somefunc)
所以somefunc
实际上是omnimethod
实例,而不是已定义的函数。有趣的是,omnimethod
也实现了descriptor
interface.如果一个类属性定义了一个__get__
方法,那么只要提到该属性,解释器就会调用__get__
对象,并返回而不是返回属性本身。
始终使用instance作为第一个参数调用__get__
方法,并将该实例的类作为第二个参数调用。如果实际从类本身查找属性,则实例将为None
。
最后一点技巧是functools.partial
,它是函数currying的python方式。当你使用partial
时,你传递一个函数和一些参数,然后它返回一个新函数,当被调用时,除了你稍后传入的参数之外,还将使用原始参数调用原始函数。 omnimethod
使用此技术将self
参数填充到它包装的函数中。
这就是它的样子。当您从实例中读取它时,可以调用regular method,但不能在类本身中使用它。你得到一个未绑定的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提供了一个bultin装饰器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
>>>
答案 1 :(得分:1)
class B:
@omnimethod
def test(self):
print 1
@property
def prop(self):
return 2
>>> b = B()
>>> b.test()
1
>>> B.test()
1
>>> b.prop
2