How are arguments passed to a function through __getattr__
Question:
Consider the following code example (python 2.7):
class Parent:
def __init__(self, child):
self.child = child
def __getattr__(self, attr):
print("Calling __getattr__: "+attr)
if hasattr(self.child, attr):
return getattr(self.child, attr)
else:
raise AttributeError(attr)
class Child:
def make_statement(self, age=10):
print("I am an instance of Child with age "+str(age))
kid = Child()
person = Parent(kid)
kid.make_statement(5)
person.make_statement(20)
it can be shown, that the function call person.make_statement(20)
calls the Child.make_statement
function through the Parent
‘s __getattr__
function. In the __getattr__
function I can print out the attribute, before the corresponding function in the child instance is called. So far so clear.
But how is the argument of the call person.make_statement(20)
passed through __getattr__
? How am I able to print out the number ’20’ in my __getattr__
function?
Answers:
You are not printing 20
in your __getattr__
function. The function finds the make_statement
attribute on the Child instance and returns that. As it happens, that attribute is a method, so it is callable. Python thus calls the returned method, and that method then prints 20
.
If you were to remove the ()
call, it would still work; we can store the method and call it separately to get 20
printed:
>>> person.make_statement
Calling __getattr__: make_statement
<bound method Child.make_statement of <__main__.Child instance at 0x10db5ed88>>
>>> ms = person.make_statement
Calling __getattr__: make_statement
>>> ms()
I am an instance of Child with age 10
If you have to see the arguments, you’d have to return a wrapper function instead:
def __getattr__(self, attr):
print("Calling __getattr__: "+attr)
if hasattr(self.child, attr):
def wrapper(*args, **kw):
print('called with %r and %r' % (args, kw))
return getattr(self.child, attr)(*args, **kw)
return wrapper
raise AttributeError(attr)
This now results in:
>>> person.make_statement(20)
Calling __getattr__: make_statement
called with (20,) and {}
I am an instance of Child with age 20
For people who found the best answer somewhat confusing like me. I found that __getattr__
just expects to return callable function which it invokes, and sends the *args and **kwargs.
def printf(name, *args, **kwargs):
print(name)
print(args)
print(kwargs)
class MyClass:
def __getattr__(self, name, *args, **kwargs):
# *args and **kwargs are available here as lists and dictionaries, respectively
# You can use them just like any other argument
# For example, you can pass them to another function
return printf
t = MyClass()
t.get("hello", "wow", headers ={"token": "123456789"})
Output:
hello
('wow',)
{'headers': {'token': '123456789'}}
Which is what I wanted, so you would need to wrap your function with another function to pass *args and *kwargs for that matter.
Consider the following code example (python 2.7):
class Parent:
def __init__(self, child):
self.child = child
def __getattr__(self, attr):
print("Calling __getattr__: "+attr)
if hasattr(self.child, attr):
return getattr(self.child, attr)
else:
raise AttributeError(attr)
class Child:
def make_statement(self, age=10):
print("I am an instance of Child with age "+str(age))
kid = Child()
person = Parent(kid)
kid.make_statement(5)
person.make_statement(20)
it can be shown, that the function call person.make_statement(20)
calls the Child.make_statement
function through the Parent
‘s __getattr__
function. In the __getattr__
function I can print out the attribute, before the corresponding function in the child instance is called. So far so clear.
But how is the argument of the call person.make_statement(20)
passed through __getattr__
? How am I able to print out the number ’20’ in my __getattr__
function?
You are not printing 20
in your __getattr__
function. The function finds the make_statement
attribute on the Child instance and returns that. As it happens, that attribute is a method, so it is callable. Python thus calls the returned method, and that method then prints 20
.
If you were to remove the ()
call, it would still work; we can store the method and call it separately to get 20
printed:
>>> person.make_statement
Calling __getattr__: make_statement
<bound method Child.make_statement of <__main__.Child instance at 0x10db5ed88>>
>>> ms = person.make_statement
Calling __getattr__: make_statement
>>> ms()
I am an instance of Child with age 10
If you have to see the arguments, you’d have to return a wrapper function instead:
def __getattr__(self, attr):
print("Calling __getattr__: "+attr)
if hasattr(self.child, attr):
def wrapper(*args, **kw):
print('called with %r and %r' % (args, kw))
return getattr(self.child, attr)(*args, **kw)
return wrapper
raise AttributeError(attr)
This now results in:
>>> person.make_statement(20)
Calling __getattr__: make_statement
called with (20,) and {}
I am an instance of Child with age 20
For people who found the best answer somewhat confusing like me. I found that __getattr__
just expects to return callable function which it invokes, and sends the *args and **kwargs.
def printf(name, *args, **kwargs):
print(name)
print(args)
print(kwargs)
class MyClass:
def __getattr__(self, name, *args, **kwargs):
# *args and **kwargs are available here as lists and dictionaries, respectively
# You can use them just like any other argument
# For example, you can pass them to another function
return printf
t = MyClass()
t.get("hello", "wow", headers ={"token": "123456789"})
Output:
hello
('wow',)
{'headers': {'token': '123456789'}}
Which is what I wanted, so you would need to wrap your function with another function to pass *args and *kwargs for that matter.