Issue with monkeypatching methods and references - python

I was wondering if anyone could explain and offer a solution to this issue:
$ cat object-override-methods.py
class A:
def foo(self):
return 1
class B:
def foo(self):
return 1
for klass in A, B:
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
A().foo()
B().foo()
$ python object-override-methods.py
Traceback (most recent call last):
File "object-override-methods.py", line 15, in <module>
A().foo()
File "object-override-methods.py", line 12, in foo
return orig_foo(self) * 2
TypeError: unbound method foo() must be called with B instance as first argument (got A instance instead)
Thanks in advance.

orig_foo is a global variable which changes value with each pass through the loop. After the loop is done, orig_foo refers to B.foo.
The inner functions foo (one or each pass through the loop) both use the global value for orig_foo when they are called. So they both call B.foo(self).
When calling an "unbound method" like orig_foo, Python2 checks that the first argument is an instance of the appropriate class. A().foo() does not pass this check. (Interestingly, this check was removed in Python3, so there would be no TypeError raised, and this bug may become harder to find.)
To fix this, you must bind the value of orig_foo to the appropriate klass.
You can do that by making orig_foo a local variable of foo. One way to do that is to make orig_foo an argument of foo with a default value. Python binds default values at the time a function is defined. So orig_foo=orig_foo binds the local variable orig_foo to the current value of the klass.foo:
for klass in A, B:
orig_foo = klass.foo
def foo(self, orig_foo=orig_foo):
return orig_foo(self) * 2
klass.foo = foo

Because orig_foo is defined at global scope, you're trampling on its value each time round the loop. That trampled value is then shared by each of your new foo methods.
A simple fix is to move the code into a function, like this:
def rebind_foo(klass):
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
for klass in A, B:
rebind_foo(klass)
That ensures that each new foo method gets its own value of orig_foo.

Related

Why calling a function inside a Python class __init__ can be both Attribute and Method?

I am quite confused with the method and attribute of a Python class. Suppose we have a Python class like this:
# case 1
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
self.fun()
def fun(self):
value = self.first + '---' + self.last
self.fun = value
return value
person_1 = Person('A', 'B')
person_1.fun
---> "A---B"
As we can see, in case_1 we initialize an instance person_1. And we can get the result we want by calling fun as an attribute. However, if we change our code to the following, fun becomes a method instead.(case_2)
# case 2
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
self.fun()
def fun(self):
value = self.first + '---' + self.last
return value
person_1 = Person('A', 'B')
person_1.fun
---> <bound method Person.fun of <__main__.Person object at 0x7fd4f79168d0>>
We still contain the init process in the class. But now fun becomes a method but not an attribute. (case_2)
If we remove the self.fun() in init but keep the self.fun = value, it is still a method. (case_3)
# case 3
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
def fun(self):
value = self.first + '---' + self.last
self.fun = value
return value
person_1 = Person('A', 'B')
person_1.fun
---> <bound method Person.fun of <__main__.Person object at 0x7fd4f797f390>>
Would you mind giving me some instructions about why this happens? And what is the proper way to use the function as an attribute inside a Python Class? Thank you so much in advance!
In case 1, your constructor calls fun() which has a line inside of it to overwrite itself with an attribute value. This is confusing and not a good thing to do because it is confusing.
In case 2, your fun method does not include the line to overwrite itself so it doesn't get overwritten.
In case 3, you never actually call your fun method so it never has a chance to overwrite itself. If you called it with person_1.fun() i.e. with parentheses, then it would execute and overwrite itself and from that point on, person_1.fun would be an attribute value.
Remember that in python, a function/method ONLY executes if it is called with parentheses. If you don't express it with parentheses, then the result of evaluation is not the output of the function, but instead the expression produces a reference to the function itself, which can be put in another variable or in a data structure and called later.
To illustrate this:
>>> def my_func():
... print('got called')
... return 42
...
>>> x = my_func #no parentheses, x becomes an alias to my_func
>>> y = my_func() #parentheses means actually execute
got called
>>> y
42
>>> x
<function my_func at 0x765e8afdc0>
>>> x() #x is a reference to my_func and can be called itself
got called
42
>>>
Aha, I think I figure it out!
In case 1, we simply run the function fun() when we init the instance. And because it defines the attribute self.fun = value inside the fun(), hence fun can be used as an attribute. (It cannot be used as the method anymore, because it has been replaced as an attribute.)
In case 2, we only call and run this function. But fun is not been defined as an attribute inside the class. That's why it remains as a method.
In case 3, fun is a method, but in this method, we define an attribute fun. Hence we can first init an instance, then run the function fun. After that, the attribute fun is added to this instance, and then we can call it as person_1.fun.

How to use a function outside a class as a property inside a class?

I'm having some problems. How we can define a function outside of a function that can be used in a class property? Also, how we can insert the self parameter into the function signature? I would like to visualize it like this:
>>> def a(self, x): #I thought maybe class will give "self" to this property function
... print(self)
...
>>> class aa:
... def __init__(self):
... pass
... #a
... def p():
... print('in it')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in aa
TypeError: a() missing 1 required positional argument: 'x'
I want to define a function outside but to use inside of a class. Like a class's method as a property. How can I do this?
It's not really clear what you want your out-of-class function to do. There are a bunch of possibilities, but you may not know the terminology yet to describe it to us.
Here's the three I think are most likely:
You may want your function to be a decorator. That means you can apply it to a method with #decorator syntax to other functions, including methods in a class.
For this to work, your function needs to be written to accept a function object as its only argument. Whatever it returns is what will replace the function or method it was being called on, so usually you want to return a callable, but you could instead return a descriptor like property does. Try something like this:
def decorator(func):
def wrapper(self, *args, **kwargs):
print("in the wrapper")
result = func(self, *args, **kwargs)
print("wrapper is done")
return result
return wrapper
class Foo:
#decorator
def foo(self, x):
print("in foo(), x is", x)
f = Foo()
f.foo(1) # prints three messages
When you call the foo method, you're actually going to be calling the wrapper method that the decorator returned after it was applied to the original method (func). Because of how we wrote the wrapper, it will call func so the original method prints out its message too.
You may want to use property (a descriptor type) to call your out-of-class function. This is a less common way of using property than applying it as a decorator on a method, but it's not impossible. You could even have two different functions, one to be called when requesting the attribute, the other than will be called when setting it (but I'll demonstrate with just the getter):
def getter(obj):
print("in the getter")
return 1
class Foo2:
foo = property(getter)
f2 = Foo2()
print(f2.foo) # prints a message from the getter function first, then prints 1
Note that you can't use #decorator syntax when building a property this way. That is only legal syntax immediately before a function definition, and we're not defining any functions that way inside our class.
You may just want to copy a function defined outside of the class into it, without any decorator or property nonsense. This is the easiest one to do, it's just a simple assignment:
def func(self, x):
print("x is", x)
class Foo3:
method = func # just assign the global to a name in the class body
func = func # you can even use the same name if you don't mind confusing people
f3 = Foo3()
f3.method(1)
f3.func(2)
If you want to create a property that uses a function defined outside your class, it would be something like this:
def myfunc(self):
return self._p
class Foo:
def __init__(self, p):
self._p = p
p = property(myfunc)
f = Foo("Alpha")
f.p # gives "Alpha"
property accepts a function as its (first) argument. The function should have self as a parameter, and should return the value that you want the property to evaluate to.

__getattr__ returning lambda function requiring one argument does not work

I am in the process of learning Python 3 and just ran into the getattr function. From what I can tell, it is invoked when the attribute call is not found in the class definition as a function or a variable.
In order to understand the behaviour, I wrote the following test class (based on what I've read):
class Test(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __getattr__(self, itm):
if itm is 'test':
return lambda x: "%s%s" % (x.foo, x.bar)
raise AttributeError(itm)
And I then initate my object and call the non-existent function test which, expectedly, returns the reference to the function:
t = Test("Foo", "Bar")
print(t.test)
<function Test.__getattr__.<locals>.<lambda> at 0x01A138E8>
However, if I call the function, the result is not the expected "FooBar", but an error:
print(t.test())
TypeError: <lambda>() missing 1 required positional argument: 'x'
In order to get my expected results, I need to call the function with the same object as the first parameter, like this:
print(t.test(t))
FooBar
I find this behaviour rather strange, as when calling p.some_function(), is said to add p as the first argument.
I would be grateful if someone could shine some light over this headache of mine. I am using PyDev in Eclipse.
__getattr__ return values are "raw", they don't behave like class attributes, invoking the descriptor protocol that plain methods involve that causes the creation of bound methods (where self is passed implicitly). To bind the function as a method, you need to perform the binding manually:
import types
...
def __getattr__(self, itm):
if itm is 'test': # Note: This should really be == 'test', not is 'test'
# Explicitly bind function to self
return types.MethodType(lambda x: "%s%s" % (x.foo, x.bar), self)
raise AttributeError(itm)
types.MethodType is poorly documented (the interactive help is more helpful), but basically, you pass it a user-defined function and an instance of a class and it returns a bound method that, when called, implicitly passes that instance as the first positional argument (the self argument).
Note that in your specific case, you could just rely on closure scope to make a zero-argument function continue to work:
def __getattr__(self, itm):
if itm is 'test': # Note: This should really be == 'test', not is 'test'
# No binding, but referring to self captures it in closure scope
return lambda: "%s%s" % (self.foo, self.bar)
raise AttributeError(itm)
Now it's not a bound method at all, just a function that happens to have captured self from the scope in which it was defined (the __getattr__ call). Which solution is best depends on your needs; creating a bound method is slightly slower, but gets a true bound method, while relying on closure scope is (trivially, ~10ns out of >400ns) faster, but returns a plain function (which may be a problem if, for example, it's passed as a callback to code that assumes it's a bound method and can have __self__ and __func__ extracted separately for instance).
To get what you want, you need a lambda that doesn't take arguments:
return lambda: "%s%s" % (self.foo, self.bar)
But you should really use a property for this, instead.
class Test(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
#property
def test(self):
return "{}{}".format(self.foo, self.bar)
t = Test("Foo", "Bar")
print(t.test)
# FooBar
Note the lack of parentheses.
If you're absolutely determined that it must be a function, do this:
class Test(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
#property
def test(self):
return lambda: "{}{}".format(self.foo, self.bar)
t = Test("Foo", "Bar")
print(t.test())
# FooBar
You need to create something that behaves like a bound method, you could simply use functools.partial to bind the instance to the function:
from functools import partial
class Test(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
def __getattr__(self, itm):
if itm == 'test': # you shouldn't use "is" for comparisons!
return partial(lambda x: "%s%s" % (x.foo, x.bar), self)
raise AttributeError(itm)
The test:
t = Test("Foo", "Bar")
print(t.test)
# functools.partial(<function Test.__getattr__.<locals>.<lambda> at 0x0000020C70CA6510>, <__main__.Test object at 0x0000020C7217F8D0>)
print(t.test())
# FooBar
"I find this behaviour rather strange, as when calling
p.some_function(), is said to add p as the first argument."
some_function is actually a method, which is why it gets passed an instance implicitly when the method is "bound to an object." But plain functions don't work that way, only functions defined in the class body have this magic applied to them automagically. And actually, unbound methods (accessed via the class directly) function the same as normal functions! The terminology "bound and unbound" methods no longer applies, because in Python 3 we only have methods and functions (getting rid of the distinction between unbound methods and plain functions). When an instance is instantiated, accessing the attribute returns a method which implicitly calls the instance on invocation.
>>> class A:
... def method(self, x):
... return x
...
>>> a.method
<bound method A.method of <__main__.A object at 0x101a5b3c8>>
>>> type(a.method)
<class 'method'>
However, if you access the attribute of the class you'll see it's just a function:
>>> A.method
<function A.method at 0x101a64950>
>>> type(A.method)
<class 'function'>
>>> a = A()
Now, observe:
>>> bound = a.method
>>> bound(42)
42
>>> unbound = A.method
>>> unbound(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: method() missing 1 required positional argument: 'x'
But this is the magic of classes. Note, you can even add functions to classes dynamically, and they get magically turned into methods when you invoke them on an instance:
>>> A.method2 = lambda self, x: x*2
>>> a2 = A()
>>> a2.method2(4)
8
And, as one would hope, the behavior still applies to objects already created!
>>> a.method2(2)
4
Note, this doesn't work if you dynamically add to an instance:
>>> a.method3 = lambda self, x: x*3
>>> a.method3(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'
You have to do the magic yourself:
>>> from types import MethodType
>>> a.method4 = MethodType((lambda self, x: x*4), a)
>>> a.method4(4)
16
>>>
Notice that if you do print(t.__getattr__) you get something like <bound method Test.__getattr__ of <__main__.Test object at 0x00000123FBAE4DA0>>. The key point is that methods defined on an object are said to be 'bound' and so always take the object as the first parameter. Your lambda function is just an anonymous function not 'bound' to anything, so for it to access the object it needs to be explicitly passed in.
I presume you are only doing this to experiment with using `__getattr__', as what you are doing could be much more easily achieved by making your lambda a method on the object.

Call a functor in Python

Should be easy, but somehow I don't get it. I want to apply a given function. Background is copy a class and applying a given method on the newly created copy.
Major Edit. Sorry for that.
import copy
class A:
def foo(self,funcName):
print 'foo'
funcName()
def Bar(self):
print 'Bar'
def copyApply(self,funcName):
cpy = copy.copy()
# apply funcName to cpy??
a = A()
func = a.Bar()
a.foo(func) # output 'Bar'
b = a.copyApply(foo) # new copy with applied foo
Note that your A.foo does not take the name of a function, but the function itself.
class A:
def bar(self):
print 'Bar'
def apply(self, func):
func() # call it like any other function
def copyApply(self, func):
cpy = copy.copy(self)
func(cpy) # cpy becomes the self parameter
a = A()
func = a.bar # don't call the function yet
a.apply(func) # call the bound method `a.bar`
a.apply(a.bar) # same as the line above
a.copyApply(A.bar) # call the unbound method `A.bar` on a new `A`
In python, a.foo() is the same as A.foo(a), where a is of type A. Therefore, your copyApply method takes the unbound bar method as its argument, whereas foo takes a bound method.
If you want to call a method on a copy of the instance
class A (object):
def foo(self):
pass
def copyApply(self,func):
cpy = copy.copy(self)
func(cpy)
and call it like so
a = A()
a.copyApply(A.foo)
note I am getting the method foo from the class, not the instance, as A.foo expects an instance of A as the first argument, and a.foo takes no arguments.

Getting NameError when calling function in constructor

I ran the code below, by calling the function in the constructor
First --
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Chaitanya')
C
h
a
i
t
a
n
y
a
Once again I run this and I get this
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
NameError: global name 'printName' is not defined
Can I not call a function in the constructor? and whay a deviation in the execution of similar code?
Note: I forgot to call a function local to the class, by using self (ex: self.printName()). Apologize for the post.
You need to call self.printName since your function is a method belonging to the PrintName class.
Or, since your printname function doesn't need to rely on object state, you could just make it a module level function.
class PrintName:
def __init__(self, value):
self._value = value
printName(self._value)
def printName(value):
for c in value:
print c
Instead of
printName(self._value)
you wanted
self.printName(self._value)
It probably worked the first time because you had another function printName in a parent scope.
What you want is self.printName(self._value) in __init__, not just printName(self._value).
I know this is an old question, but I just wanted to add that you can also call the function using the Class name and passing self as the first argument.
Not sure why you'd want to though, as I think it might make things less clear.
class PrintName:
def __init__(self, value):
self._value = value
PrintName.printName(self, self._value)
def printName(self, value):
for c in value:
print(c)
See Chapter 9 of the python manuals for more info:
9.3.4. Method Objects
Actually, you may have guessed the answer: the special thing about methods is that the object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.

Categories

Resources