7

Disclaimer This is just an exercise in meta-programming, it has no practical purpose.

I've assigned __getitem__ and __getattr__ methods on a function object, but there is no effect...

def foo():
  print "foo!"

foo.__getitem__ = lambda name: name
foo.__getattr__ = lambda name: name
foo.baz = 'baz'

Sanity check that we can assign properties to a function:

>>> foo.baz
'baz'

Neat. How about the "magic getters"?

>>> foo.bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'bar'

>>> foo['foo']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'function' object is not subscriptable

>>> getattr(foo, 'bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'function' object has no attribute 'bar'

Is it possible to have a "magic getter" on a function object?

4

3 回答 3

6

Nope! Assigning __getitem__ to an instance doesn't work on any type of object:

>>> class A(object):
...   pass
...
>>> a = A()
>>> a.__getattr__ = lambda name: name
>>> a.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'foo'

And you can't define __getattr__ on the built-in function type:

>>> import types
>>> types.FunctionType.__getitem__ = lambda name: name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'function'

And you can't subclass types.FunctionType:

>>> import types
>>> class F(types.FunctionType):
...   pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
type 'function' is not an acceptable base type
于 2012-05-29T16:48:23.677 回答
3

至少在新式类(这是 Python 3 中唯一的一种,也是您应该在 Python 2 中使用的那种)上,Python 只在类(及其祖先)上寻找魔法方法,而不是在实例上。文档在这里

当然你不能修改函数类型,或者从它派生。然而,正如您所发现的,任何具有__call__()方法的类都会生成可调用的实例,所以这就是这样做的方法。

于 2012-05-29T17:14:49.803 回答
2

AHHA! Use __call__, and wrap the function in F()

class F(object):
    def __init__(self, fn):
        self.__dict__['fn'] = fn

    def __call__(self, *args, **kwargs):
        return self.fn(*args, **kwargs)

    def __getitem__(self, name):
        return name

    def __getattr__(self, name):
        return name

>>> foo = F(foo)
>>> f.bar
'bar'
>>> f['foo']
'foo'
>>> foo()
foo!
于 2012-05-29T16:58:30.747 回答