[Python]Calling method(self) - python

I can not understand following commented line.
It's a python program.
class B:
def bbb(self):
method = self.commands[0]
method(self) #I can't umderstand this line
class A(B):
def aaa(self):
print 'aaa was called'
commands = [aaa]
c = A()
c.bbb()
Output:
aaa was called
I think above aaa method takes no arguments.
But to run this code, I need to pass "self" to aaa argument. Why? Are there any docs explaining this?What category this problem belongs?
Any simple codes are very welcome.
Because my English skill is too low.
So improving this question is welcome too.
I encountered this problem, when I was reading cpython/Lib/distutils/cmd.py:Command.get_sub_commands().
Thank you for reading.

Wow, this is confusingly written. Working backward from the code itself:
c = A()
Creates an instance of A. Looking at A:
def aaa(self):
print 'aaa was called'
commands = [aaa]
This is a bit confusingly written; it makes more sense like this:
def aaa(self):
print 'aaa was called'
commands = [aaa]
Defines a method aaa, then a class variable commands which contains aaa as an element. Now, looking at the next line of the program:
c.bbb()
Since A has no bbb and A inherits from B, we consult B:
class B:
def bbb(self):
method = self.commands[0]
method(self)
Since we've established that commands is [aaa], the first line means method = aaa. So the second line is effectively aaa(self).

This line:
method(self) #I can't umderstand this line
Calls the function aaa(). In your function declaration:
def aaa(self):
aaa does takes an argument (self). That's why you have to call it with method(self).
Since self.commands[0] is a function, calling method(self) is equal to:
aaa(self)
Comment if you have something else to ask!

The way the code sample is done makes it a little harder to tell what's going on. However, it's equivalent to:
child_methods = [] # a list of all the methods in `Child`
class Parent(object):
def parent_method(self):
print "parent_method() called"
method = child_methods[0]
method(self)
class Child(Parent):
def child_method(self):
print "child_method() called"
# add child_method to child_methods
child_methods.append(Child.child_method)
As you can see, child_methods[0] will actually be the function Child.child_method, which is a plain function, and not a bound method. It's not associated with an instance of Child, which is why you can and have to pass in the self yourself. You'd get a bound method from a Child instance with:
child_obj = Child()
bound_child_method = child_obj.child_method
This is made unclear by the fact Python will look up attributes in the type of an object if they're not found in the instance. For example:
# A dummy class to hold attributes
class Foo(object):
pass
Foo.bar = 123 # we're adding an attribute to the type itself
foo1 = Foo()
print foo1.bar # prints 123
foo1.bar = 456 # this `bar` attribute "hides" the one on the type
print foo1.bar # prints 456
foo2 = Foo()
print foo2.bar # prints the 123 from the type again
This is why, in your code sample, commands is really a "global" variable, it just gets accessed confusingly through an instance of B. (This is not necessarily a bad practice if only objects of B or its children access this variable, but the lookup rules are a minor gotcha.)

By the way it is better to use new-style classes, class A(object):...
All methods of class in python have self as first argument, except of class methods.
Here is example about self:
def x(first, arg):
print "Called x with arg=",arg
print first
class A(object):
some_method = x
a = A()
a.some_method("s")`
http://docs.python.org/2/tutorial/classes.html#random-remarks

Related

Can Monkey patching replace existing function definition in a class?

I know how fierce the SO community is so I'll try my best to keep the question minimal, complete and verifiable.
What I simply want to know is can monkey patching be used to replace the definition of an existing function?
for example:
class A():
def foo():
print '2'
def foo():
print '5'
A.foo = foo
This way doesn't seem to work also as to why I don't just add a new function instead of replacing an existing one, I call these functions in other classes and it is my understanding that monkey patching adds those functions at run-time and I need my python code to run on an Apache spark server which throws an error deeming the calls to that function unreferenced.
So please be nice and help me out or suggest a work around.
Thanks.
Edit: The goal of the code is to print 5 when A.foo is called.
Your only problem is that you aren't defining foo correctly in the first place. It needs to take an explicit argument for the instance calling it.
class A(object):
def __init__(self)
self.x = 2
def foo(self):
print(self.x)
def foo(this):
print(this.x + 3)
A.foo = foo
a = A()
a.foo() # outputs 5 in Python 2 and Python 3
In a very real sense, monkey patching is how classes are created in the first place. A class statement is almost just syntactic sugar for the following code:
def foo(self):
print(self.x)
A = type('A', (object,), {'foo': foo})
del foo
It's not too much of a simplification to image the definition of type being something like
def type(name, bases, d):
new_class = magic_function_to_make_a_class()
new_class.name = name
new_class.bases = bases
for k, v in d.items():
setattr(new_class, k, v)
return new_class
I hope I understand what you are trying to do here. This would work in Python 3:
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo() # Print '2'
foo() # Assign the new method
A.foo() # Prints '5'
In Python 2 however there are several caveats.
print is not a method as it is in Python 3 (see here: Why doesn't print work in a lambda?)
You can't just call unbound messages (see here: In Python, can you call an instance method of class A, but pass in an instance of class B?)
So you have to do it like this:
from __future__ import print_function
class A():
def foo():
print('2')
def foo():
A.foo = lambda: print('5')
A.foo.__func__() # Print '2'
foo() # Assign the new method
A.foo.__func__() # Prints '5'
Edit:
After seeing your question in the comment I think you actually want something different. Which is this:
class A():
def foo(self):
print '2'
def foo(self):
print '5'
a = A()
a.foo() # Print '2'
A.foo = foo # Assign the new method
a.foo() # Prints '5'
This works just fine in Python 2.
The self is a reference to the current instance the method is bound to. It is not used when you just call something like print which access any properties or methods attached to that instance. But for a different case please have a look at the following example:
class A():
msg = "Some message"
def foo(self):
print self.msg
def bar(self):
self.msg = "Some other message"
a = A()
a.foo() # Print old msg
A.bar = bar # Assign the new method
a.bar() # Assigns new message
a.foo() # Prints new message
Also as chepner points out in a comment under his post:
The name self isn't special; it's just a convention. You could use
this if you really wanted to, and it doesn't need to be the same name
in both functions defined here. What is important is that the first
argument to a function used as an instance method will be a reference
to the calling object. a.foo() is almost exactly the same as A.foo(a)

Storing reference to unbound method

I was trying to store reference to unbound method and noticed that it is being automatically bound. See example below. Is there more elegant way to store unbound method in the class without binding it?
def unbound_method():
print("YEAH!")
class A:
bound_method = unbound_method
unbound_methods = [unbound_method]
a = A()
a.unbound_methods[0]() # succeeds
a.bound_method() # fails
# TypeError: unbound_method() takes 0 positional arguments but 1 was given
This is not a standard "do you know about #staticmethod?" question.
What I'm trying to achieve is provide a way for children of the class provide another handler or certain situations. I do not control the unbound_method itself, it is provided from some library.
def unbound_method_a():
print("YEAH!")
def unbound_method_b():
print("WAY MORE YEAH!")
class A:
bound_method = unbound_method_a
class B(A):
bound_method = unbound_method_b
a = A()
a.bound_method() #fails
# print("YEAH!")
b = B()
b.bound_method() #fails
# print("WAY MORE YEAH!")
It can be achieved by wrapping the unbound method some dummy object like array, or in a bound method, just to drop self reference like this:
def unbound_method_a():
print("YEAH!")
def unbound_method_b():
print("WAY MORE YEAH!")
class A:
def call_unbound_method(self):
return unbound_method_a()
class B(A):
def call_unbound_method(self):
return unbound_method_b()
a = A()
a.call_unbound_method()
# print("YEAH!")
b = B()
b.call_unbound_method()
# print("WAY MORE YEAH!")
Not as far as I know. Would it be so bad if you just replace
a.bound_method()
with
A.bound_method()
?
I can't think of a situation in which the first one can't be replaced by the second one.

How to update the the class type and methods in an existing object

If I have an object of a certain type, and I would like to get the unbound method, should I use type(obj).method_name or obj.__class__.method_name? I got confused upon seeing the following result:
class ClassA(object):
def Test(self):
pass
obj_a = ClassA()
print obj_a.__class__ is type(obj_a)
print obj_a.__class__.Test is type(obj_a).Test
The first returns True and the second False. So what is the difference of the two in the last statement?
UPDATE:
My use case is that I have some class in a playground notebook. The class objects may be heavy, for example, they contain stuff after long time of training. During the time I would like to make updates to the functions and keep use the existing objects. So I would like something like this to be working:
# In cell 1 I define the following class.
class ClassA(object):
def Test(self):
print 'haha'
# In cell 2 I create an object and use it for a while.
obj_a = ClassA()
obj_a.Test()
# After some time I modified the ClassA in cell 1 and re-executed the cell:
class ClassA(object):
def Test(self):
print 'hoho'
# Then I want to replace a method and call Test again:
obj_a.__class__.Test = ClassA.Test
obj_a.Test() # Should print 'hoho'
Unfortunately the above code does not work. The last call obj_a.Test() uses the unbound method Test.
The answer to your question, you need to assign to the bound method, e.g.:
import types
obj_a.Test = types.MethodType(ClassA.Test, obj_a)
obj_a.Test()
Would give the result you expect, i.e. 'hoho'
Updated: Here's an example:
import types
class ClassA(object):
def Test(self):
print 'haha'
obj = ClassA()
obj.Test()
# haha
Update ClassA to hoho:
obj.__class__ = ClassA
obj.Test()
# hoho
You can try also :
obj_a.__class__.Test is obj_a.__class__.Test
type(obj_a).Test is type(obj_a).Test
which both are equivalent to ClassA.Test is ClassA.Test, but all of them returns False.
Explanation for this is the particular behavior unbounded methods, see here.

bound methods in python

>>> class Class:
... def method(self):
... print 'I have a self!'
...
>>> def function():
... print "I don't..."
...
>>> instance = Class()
>>> instance.method()
I have a self!
>>> instance.method = function
>>> instance.method()
I don't...
Okay the book quotes 'The self parameter (mentioned in the previous section) is, in fact, what distinguishes methods
from functions. Methods (or, more technically, bound methods) have their first parameter
bound to the instance they belong to: you don’t have to supply it. So while you can certainly
bind an attribute to a plain function, it won’t have that special self parameter:'
I am not able to understand what the author is trying to convey here ! I am new to oop in python . Please explain me .
Methods only exist on the class; assigning the function to the instance attribute as your example does creates an instance attribute containing the function, and not a method.
It means that affect of
class A:
def a(self):
print 'a'
def b(self, arg):
print arg
can be roughly represented by:
def A_a(self):
print a
def A_b(self, arg):
print arg
class A:
def __init__(self):
self.a = lambda: A_a(self)
self.b = lambda arg: A_b(self, arg)
So instance.a is not original function a which is written in class A, but another function which calls original with additional self argument.

Is it safe to replace a self object by another object of the same type in a method?

I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>

Categories

Resources