Defining __getattr__ and __getitem__ on a function has no effect

。_饼干妹妹 提交于 2019-12-22 04:48:26

问题


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?


回答1:


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



回答2:


At least on new-style classes (which are the only kind in Python 3 and the kind you should be using in Python 2), Python only looks for magic methods on the class (and its ancestors), never on the instance. Docs here.

And of course you can't modify the function type, or derive from it. As you've found, however, any class with a __call__() method makes callable instances, so that's the way to do it.




回答3:


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!


来源:https://stackoverflow.com/questions/10803384/defining-getattr-and-getitem-on-a-function-has-no-effect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!