在函数上定义__getattr__和__getitem__无效

时间:2012-05-29 16:48:24

标签: python metaprogramming

免责声明这只是元编程的练习,它没有实际意义 目的

我在函数对象上分配了__getitem____getattr__方法,但是 没有效果......

def foo():
  print "foo!"

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

我们可以为某个功能分配属性的完整性检查:

>>> foo.baz
'baz'

纯。 “神奇的吸气者”怎么样?

>>> 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'

是否可以在函数对象上使用“魔术吸气剂”?

3 个答案:

答案 0 :(得分:6)

都能跟得上!将__getitem__分配给实例不适用于任何类型的对象:

>>> 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'

您无法在内置函数类型中定义__getattr__

>>> 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'

您无法继承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

答案 1 :(得分:3)

至少在新式类(它是Python 3中唯一的类,以及你应该在Python 2中使用的类)中,Python只在类(及其祖先)上寻找魔术方法,而不是在实例上。 Docs here

当然,您无法修改函数类型,也无法从中派生。但是,正如您所发现的,任何具有__call__()方法的类都会生成可调用的实例,因此这是实现它的方法。

答案 2 :(得分:1)

AHHA!使用__call__,并将功能包装在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!