Search code examples
pythongetattr

Determine if __getattr__ is method or attribute call


Is there any way to determine the difference between a method and an attribute call using __getattr__?

I.e. in:

class Bar(object):
    def __getattr__(self, name):
        if THIS_IS_A_METHOD_CALL:
            # Handle method call
            def method(**kwargs):
                return 'foo'
            return method
        else:
            # Handle attribute call
            return 'bar'

foo=Bar()
print(foo.test_method()) # foo
print(foo.test_attribute) # bar

The methods are not local so it's not possible to determine it using getattr/callable. I also understand that methods are attributes, and that there might not be a solution. Just hoping there is one.


Solution

  • You cannot tell how an object is going to used in the __getattr__ hook, at all. You can access methods without calling them, store them in a variable, and later call them, for example.

    Return an object with a __call__ method, it'll be invoked when called:

    class CallableValue(object):
        def __init__(self, name):
            self.name = name
        def __call__(self, *args, **kwargs):
            print "Lo, {} was called!".format(self.name)
    
    class Bar(object):
        def __getattr__(self, name):
            return CallableValue(name)
    

    but instances of this will not be the same thing as a string or a list at the same time.

    Demo:

    >>> class CallableValue(object):
    ...     def __init__(self, name):
    ...         self.name = name
    ...     def __call__(self, *args, **kwargs):
    ...         print "Lo, {} was called!".format(self.name)
    ... 
    >>> class Bar(object):
    ...     def __getattr__(self, name):
    ...         return CallableValue(name)
    ... 
    >>> b = Bar()
    >>> something = b.test_method
    >>> something
    <__main__.CallableValue object at 0x10ac3c290>
    >>> something()
    Lo, test_method was called!