Question

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.

Was it helpful?

Solution 3

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.)

OTHER TIPS

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!

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top