I’ve been reading the article on the data model of Python on its Reference website, and have been confused about this part:
When the attribute is a user-defined method object, a new method
object is only created if the class from which it is being retrieved
is the same as, or a derived class of, the class stored in the
original method object; otherwise, the original method object is used
as it is.
Essentially, I cannot really conjure up two scenarios where in one the method object is is the same as the original method object, and in the other a new method object is created. Here’s the closest I can come:
class TestClass:
def TestFunc():
pass
class TestClass2:
x_attr = TestClass().TestFunc
y_attr = TestClass.TestFunc
def __init__(self):
print "x's class is " + repr(TestClass2.x_attr.__class__)
print "y's class is " + repr(TestClass2.y_attr.__class__)
if __name__ == '__main__':
tc = TestClass()
tc2 = TestClass2()
print "tc.TestFunc: ".ljust(20) + str(id(tc.TestFunc)) # retrieved from TestClass
print "TestClass.TestFunc: ".ljust(20) + str(id(TestClass.TestFunc))# retrieved from TestClass
print "tc2.x_attr: ".ljust(20) + str(id(tc2.x_attr)) # retrieved from TestClass2
print "tc2.y_attr: ".ljust(20) + str(id(tc2.y_attr)) # retrieved from TestClass2
However, the output of the different test cases is not as I would expect by reading the passage from the Reference:
x's class is <type 'instancemethod'>
y's class is <type 'instancemethod'>
tc.TestFunc: 140591510137584
TestClass.TestFunc: 140591510137584
tc2.x_attr: 140591509970288
tc2.y_attr: 140591510137424
Specifically, I was expecting TestClass.TestFunc
and tc2.y_attr
(i.e. TestClass2.y_attr
) to be the same based on what is cited from the Reference.
Furthermore, I was expecting to see the same outcome for the <tc.TestFunc
, TestClass.TestFunc
> comparison pair and the <tc2.x_attr
, tc2.y_attr
> comparison pair (i.e. each pair the same or neither the same).
Could you please clarify why this is and what exactly the Reference is trying to say?
Thank you!
P.S. Using Python 2.7.6 on Ubuntu 14.04.
If i understand it properly, i think you are looking at inheritance, composting methods from another class. Sometimes you need to override existing method if sed method is not utilizing the full scope of some class.
Have in mind that sometimes this type of overriding,inheritance and composting can differ from version to version of python.
I think example would be the best way to explain this.
so we have classes test and test2:
class test(object):
def testF(self):pass
inheritance:>
class test2(test):pass #> inherited testF() function from test
>>> test().testF() is test().testF()
True
>>> test2().testF() == test().testF()
True
>>> #but is test2 the same as test ?
>>> test2() is test()
False
>>> id( test2() ) == id( test() )
True
Which is logical, if you think about it. Since they may have the same code, but they have different names so in globals()
they have different identities, and they have the same ID in memory too since they are the same, aka inheritance. But the moment you start adding other methods to test2 they will stop being the same, and test2 will have pointer to all methods of test. In short, inheritance is used to specialize some classes. If you have class car, and a class Yugo, the Yugo class is just specialized class of car.
Now here comes the overriding, since classes can be inherited you can override the methods from parent class, and those methods become user-defined methods. If you have :
class car(object):
maxGear = 5
def getSpeed(self,gearValue):
if self.maxGear < gearValue: raise WrongCarDudeError
else: return gearValue*30 # km/h
And now you have Yugo car which is very slow car ( built for expenses not for speed ) 30 km per hour is to big a shift for Yugo car, what should we do now? Make another class of Yugo ? Than we have 2 classes at 2 memory addresses in computer ( loosing valuable space in computer and time of execution). But what can we do, we can override the getSpeed method, and don’t copy the whole class.
class Yugo(car):
def getSpeed(self,gearValue):
if self.maxGear < gearValue: raise WrongCarDudeError
else: return gearValue*20 # km/h
So now Yugo car class has maxGear as the other car class, but getSpeed method is not the same.
Now that said, the link you supplied is for overriding system methods __add__,__doc__,__bool__
etc. So if your class inherits from class int
and you change the __add__
( the + operator ) method.The method of your class will not be the same as __add__
method in int class.
If you have not learned yet inheritance vs composting i would suggest some researching. Since you have composted the test.testFunc()
in global class test2
attribute. Think about it like this, if attribute has self and it is declared within __init__
function it is private ( it is unique for every new instance of that class ) if it is declared inside class but outside methods it is global, so it will pile up or be overwritten or just use memory as you create new instances.
So don’t declare it inside class and outside of methods unless you really need to. Declaring global attributes is often used when storing IDs of specific instances like chassis number of the car (or bar code from a chocolate bar) . Then you would have yugoCar = Yugo(chassisNumber)
and chevyCar = car(chassisNumber)
and car.chassisNumbers
would list the all chassis numbers from all your instances of Yugo and Car.
I hope this helped.
Specifically, I was expecting TestClass.TestFunc and tc2.y_attr (i.e.
TestClass2.y_attr) to be the same based on what is cited from the
Reference.
You have two different appearances of the expression: “TestClass.TestFunc” one in your __main__
, and one in your class
. Each of those expressions evaluates to a different instance of the method object, so they aren’t equal. However, you’ll find that TestClass2.y_attr is the same object as tc2.y_attr, as specified by the reference.
Furthermore, I was expecting to see the same outcome for the
comparison pair and the comparison pair (i.e. each pair the same or neither the
same).
The first pair only appears the same. In actual fact, the first print line constructs and then throws away a method object. The second print line creates a new method object using the exact same memory, and thus get the same id. But they aren’t actually the same object.