On Fri, 2009-08-28 at 12:24 -0400, Dave Angel wrote: > > Thank you Dave, very helpful as ever. I made a few tests and experiments > > to understand better, and I feel I am understanding how it works. > > Although the mechanic of this is increasingly clear, the logic behind is > > still a bit obscure: here comes a silly test on which results I have > > questions about > > > > ====================================================== > > > > class A(object): > > variable = 0 > > @classmethod > > def cm(cls): > > cls.variable += 3 > > > > class B(A): > > pass > > > > class C(B): > > pass > > > > a = A() > > b = B() > > c = C() > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > print '---' > > a.cm() > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > print '---' > > b.cm() > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > print '---' > > c.cm() > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > print '---' > > a.variable = 7 > > A.variable = 4 > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > print '---' > > B.variable = 'x' > > print A.variable, a.variable > > print B.variable, b.variable > > print C.variable, c.variable > > > > ====================================================== > > > > Now, the output of this test is as follows (I manually added the numbers > > on the right for reference in the remaining of the post): > > > > 0 0 # 1 > > 0 0 > > 0 0 > > --- > > 3 3 # 2 > > 3 3 > > 3 3 > > --- > > 3 3 # 3 > > 6 6 > > 6 6 > > --- > > 3 3 # 4 > > 6 6 > > 9 9 > > --- > > 4 7 # 5 > > 6 6 > > 9 9 > > --- > > 4 7 # 6 > > x x > > 9 9 > > > > #1 is plain obvious. > > > > #2 came as a bit of surprise: "Ah-ah!... so the class variable is the > > same for all the hierarchy of classes! I would have guessed each class > > had its own variable..." > > > > #3 and #4 are bigger surprises: "Uh? let me understand better, so... it > > must be like branches... as soon as I say that B.variable is different > > than its ancestors, all the descendants of B get updated... Yet, it's > > strange: this very thread on the mailing list has started with me asking > > about the order of declaration for classes, and I have been told that > > class variables are processed as soon as the interpreter hits the class > > definition... so I would have expected that C.variable would have been > > initialised already and would not dynamically change when B.variable > > does..." > > > > #5 confused me: it seems that a.variable can refer to both the class > > variable or a newly created object property... that sounds like a > > never-ending source of bugs to me: it is me who has then to remember if > > a given syntax refers to a class variable or to an object method? > > > > #6 really make no sense to me: it seems that the class variable of C has > > not been changed this time (as it did in #3)... > > > > The points above confuse me even more about the "design purposes" of > > classmethods and staticmethods... > > > > Any help/feedback, very much appreciated. > > > > mac. > > > > > > > Great questions. I love a person who is organized as you are. And as > willing to learn. > > #3 and #4 - First let me point out that these are not class variables, > but class attributes. It's unfortunate that you called the attributes > with the label 'variable'. I frequently make the same mistake (call it > sloppy mistake), but it might matter somewhere in the following > discussion. A class variable is simply a "variable" which references > the class. Think of it as an alias for the class. Just like a list > variable is a variable which references a list. If you do: > newclass = A > > then you can use newclass in exactly the same way as A. a = > newclass(), print newclass.variable, etc. > > A class attribute, on the other hand, is what other languages would call > a field of the class. And it definitely does get initialized when the > class is executed. That's important in the earlier discussion because > the *right-hand-side* has to be valid at that time, which is why you had > the forward referencing problem. So in the following code: > > n = 12 > class A(object): > attr = n > > n = 42 > > > the attribute A.attr is a reference to 12, not 42. The confusion in > this #3 and #4 case is that when some later expression tries to use a > particular class attribute there are some rules for lookup. I don't > know the correct terminology, but I think of this as the "." operator. > When I say C.variable, the first search is in the classes dictionary. > If it's not found there, then it searches in the parent class' > dictionary, and so on. The attribute is not copied, there's just a > search order when it's accessed. > > #5 - It's search order again (on what I call the dot operator). When > you reference c.variable, it looks first in the dictionary for the > instance object c, and then if it doesn't find it, it looks in the > parent, which is the class. And if it doesn't find it there, it again > looks in the parent, and so on. > > #6 - by this time, there is a class attribute C.variable, so changing > B.variable has no effect Probably the key thing that misleads people > is that the += operator may actually create a new attribute. That > happened when you called b.cm() and c.cm(). > > You might be helped by using help(B) before and after the call to > b.cm(). It says a lot that you might not care about, but it makes clear > what attribute are "defined here" versus "inherited from..." > > > HTH > DaveA
Well, thank you a lot for the explanation. Now it makes perfectly sense and I am an happy man. :) BTW, your appreciation for good learners is totally matched by my appreciation for good teachers... thank you again! :) Mac. _______________________________________________ Tutor maillist - [email protected] http://mail.python.org/mailman/listinfo/tutor
