Re: Class variable inheritance
Duncan Booth wrote: Lie Ryan wrote: Terry Reedy wrote: Lie Ryan wrote: Note that when the python interpreter meets this statement: class B(P): def foo(self): print('ab') X = 'f' the compiler sees a class statement -> create a new blank class -> assign P as the new class' parent No, it saves the name 'B' and bases tuple P, and create a new *dict*, call it d here though it is anonymous as far as the class body is concerned. Neat, I'd never thought that it creates the ".__dict__" before the class itself. It has to be that way: some of the internal methods cannot be modified after the initial creation of the class, so you need to use a namespace that exists before the class itself exists. The situation changes slightly in Python 3 where the metaclass can hook into the creation of the dict and instead create any kind of object which exposes a dict-like interface. That opens the door to classes where the order in which the order attributes are defined is significant or even where you can give multiple definitions for the same attribute (e.g. to support overloaded methods). The documentation for this, with an example, is in RefMan 3.3.3, Customizing Class Creation. See the metaclass .__prepare__ method. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
Lie Ryan wrote: > Terry Reedy wrote: >> Lie Ryan wrote: >> >>> >>> Note that when the python interpreter meets this statement: >>> >>> class B(P): >>> def foo(self): >>> print('ab') >>> X = 'f' >>> >>> the compiler sees a class statement -> create a new blank class >>> -> assign P as the new class' >>> parent >> >> No, it saves the name 'B' and bases tuple P, and create a new *dict*, >> call it d here though it is anonymous as far as the class body is >> concerned. > > Neat, I'd never thought that it creates the ".__dict__" before the > class itself. > It has to be that way: some of the internal methods cannot be modified after the initial creation of the class, so you need to use a namespace that exists before the class itself exists. The situation changes slightly in Python 3 where the metaclass can hook into the creation of the dict and instead create any kind of object which exposes a dict-like interface. That opens the door to classes where the order in which the order attributes are defined is significant or even where you can give multiple definitions for the same attribute (e.g. to support overloaded methods). -- Duncan Booth http://kupuguy.blogspot.com -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
Terry Reedy wrote: Lie Ryan wrote: Note that when the python interpreter meets this statement: class B(P): def foo(self): print('ab') X = 'f' the compiler sees a class statement -> create a new blank class -> assign P as the new class' parent No, it saves the name 'B' and bases tuple P, and create a new *dict*, call it d here though it is anonymous as far as the class body is concerned. Neat, I'd never thought that it creates the ".__dict__" before the class itself. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
Lie Ryan wrote: Note that when the python interpreter meets this statement: class B(P): def foo(self): print('ab') X = 'f' the compiler sees a class statement -> create a new blank class -> assign P as the new class' parent No, it saves the name 'B' and bases tuple P, and create a new *dict*, call it d here though it is anonymous as far as the class body is concerned. -> *execute* the class' body with the new dict d as the local namespace. In other words, the equivalent of exec('''body''', globals(), {}) # new Py3 exec() form # new context the compiler sees a def statement -> *compile* the def's body to a code object which is then attached to a function object -> assign the compiled body to B.foo No, d['foo'] = the compiler sees X = 'f' statement -> assign 'f' to B.X No, d['X'] = 'f' # exit the new context Up to this point, there is no new class object. -> assign the new class to B It calls meta(name, bases, d), where meta is the metaclass 'type' by default but can be any callable which does anything, though the intention is that it be a subclass of type or at least something that creates a class object, and that d become the backstage attribute dict for the result. Your problem is related to how the interpreter *execute* a class definition rather than the name resolution. Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
HPJ wrote: And by the way, the reason I've come across this problem at all is because I have something like this: class A: class X: n = 'a' x = X() class B(A): class X(A.X): n = 'b' # x = X() The line commented out was originally not there, but I found out I had to add it if I wanted B().x.n to be 'b' instead of 'a'. I might be wrong, but aren't there some (non-obscure) OOP language in which the equivalent code (without the out-commented line) would have made B().x an object of type B.X instead of A.X? Perhaps in a language where classes attribute are declarative. Not in python where class attributes are executable statements. Note that when the python interpreter meets this statement: class B(P): def foo(self): print('ab') X = 'f' the compiler sees a class statement -> create a new blank class -> assign P as the new class' parent -> *execute* the class' body # new context the compiler sees a def statement -> *compile* the def's body -> assign the compiled body to B.foo the compiler sees X = 'f' statement -> assign 'f' to B.X # exit the new context -> assign the new class to B Your problem is related to how the interpreter *execute* a class definition rather than the name resolution. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Sep 9, 3:32 am, HPJ wrote: > > Maybe. For some languages this might be an obvious behavior, but > > Python would have different circumstances so it isn't so obvious (or > > possible) there. > > Which means this topic definitely needs to be handled in detail by the > LR, and preferably also in the Tutorial. As I said, I'm sure the doc maintainers would likey welcome your contributions. > Otherwise there is no way > anyone coming to Python could know which of the many ways of > inheritance Python follows. "Mo way"? You are definitely overstating things here. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> Maybe. For some languages this might be an obvious behavior, but > Python would have different circumstances so it isn't so obvious (or > possible) there. Which means this topic definitely needs to be handled in detail by the LR, and preferably also in the Tutorial. Otherwise there is no way anyone coming to Python could know which of the many ways of inheritance Python follows. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Tue, Sep 8, 2009 at 11:30 PM, Steven D'Aprano wrote: > Out of curiosity, are there languages where inheritance means copy? I think some prototype-based ones handle it that way... Cheers, Chris -- http://blog.rebertia.com -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Sep 8, 11:05 pm, HPJ wrote: > And by the way, the reason I've come across this problem at all is > because I have something like this: > > class A: > class X: > n = 'a' > x = X() > > class B(A): > class X(A.X): > n = 'b' > # x = X() You've nested classes here, that's a whole new layer of complexity. I would strongly recommend against nesting classes in Python, unless the inner class is a smallish class (such as a custom exception type) that doesn't interact with the outer class. It's just that nested classes don't ever seem to behave like anyone expects them to. Also you can't take advantage of Python's lexical scoping with nested classes (unlike, for instance, Java) so there really isn't much benefit to nesting them. > The line commented out was originally not there, but I found out I had > to add it if I wanted B().x.n to be 'b' instead of 'a'. Hm, even if class B did get copies of class A's attributes, B().x.n would still return 'a'. It seems as if you expect class B to re- execute A's statements in B's context, or something. That's not how it works at all. (Now if you define self.x=X() inside of __init__, that's a different story.) > I might be wrong, but aren't there some (non-obscure) OOP language in > which the equivalent code (without the out-commented line) would have > made B().x an object of type B.X instead of A.X? Maybe. For some languages this might be an obvious behavior, but Python would have different circumstances so it isn't so obvious (or possible) there. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Sep 8, 8:51 pm, HPJ wrote: > > Conceptually, Python checks for the presence of B.foo, and if it's > > not there it checks for foo's presence in the base classes. > > Yes, I have no problem believing you guys that this is what Python > does. Still, my question remains about where in the Language Reference > this is specified. And if the answer is nowhere, than the LR needs to > be amended, for obviously the way inheritance is done is no small > matter and its understanding should not be left to the user's own > intuition. Well, I don't know if this detail alone is all that grave an omission-- it'll matter to very few users--but it does seem the LRM could use a subsection on inheritance in general. I'm sure the doc maintainers would welcome a contribution. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Tue, 08 Sep 2009 13:14:42 -0700, HPJ wrote: >> I could, but I will let you read and find what it says about class >> attributes. > > You think I would have asked specifically about the Language Reference > if I hadn't read it and failed to find what I was looking for? You must be new to the Internet *wink* Of course people ask without having made the effort themselves. "Please sir, will you do my work for me?" is practically the norm on Internet forums. Only without the please. > The closest thing I was able to find was section 3.2. "The standard type > hierarchy", subsection "Custom classes", where it says: > > "When the attribute name is not found [in its namespace dictionary], the > attribute search continues in the base classes. This search of the base > classes uses the C3 method resolution order [...]" > > That tells me how the lookup works, which I already knew. But it doesn't > tell me what happens when a class is inherited. The inheriting class has its base class set, and the MRO (method resolution order), and that's pretty much it as far as I can tell. Seems to me that the documentation is a little incomplete in this regard. It looks to me like one of those "language lawyer" details that needs fleshing out. Out of curiosity, are there languages where inheritance means copy? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
And by the way, the reason I've come across this problem at all is because I have something like this: class A: class X: n = 'a' x = X() class B(A): class X(A.X): n = 'b' # x = X() The line commented out was originally not there, but I found out I had to add it if I wanted B().x.n to be 'b' instead of 'a'. I might be wrong, but aren't there some (non-obscure) OOP language in which the equivalent code (without the out-commented line) would have made B().x an object of type B.X instead of A.X? -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> http://docs.python.org/reference/datamodel.html#new-style-and-classic... > - search for 'method resolution order' for other hits in that document. First of all, that's the LR for Python 2, I'm with Python 3. Second of all, there's one single passage containing the phrase "method resolution order" in the Python 3 LR, and it's one that I've already quoted -- and discarded -- previously in this thread. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On 9/09/2009 1:51 PM, HPJ wrote: Conceptually, Python checks for the presence of B.foo, and if it's not there it checks for foo's presence in the base classes. Yes, I have no problem believing you guys that this is what Python does. Still, my question remains about where in the Language Reference this is specified. And if the answer is nowhere, than the LR needs to be amended, for obviously the way inheritance is done is no small matter and its understanding should not be left to the user's own intuition. http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes - search for 'method resolution order' for other hits in that document. HTH, Mark -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> Conceptually, Python checks for the presence of B.foo, and if it's > not there it checks for foo's presence in the base classes. Yes, I have no problem believing you guys that this is what Python does. Still, my question remains about where in the Language Reference this is specified. And if the answer is nowhere, than the LR needs to be amended, for obviously the way inheritance is done is no small matter and its understanding should not be left to the user's own intuition. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Sep 8, 4:50 pm, HPJ wrote: > > would you expect the B class to have a copy of the foo method? > > Sorta. I would expect B to have a copy of the "foo" attribute, which > then refers to the same method as A.foo. So the method itself will be > be copied, but its address stored separately in A.foo and B.foo. No, I'm afraid not. Here is what happens. Conceptually, Python checks for the presence of B.foo, and if it's not there it checks for foo's presence in the base classes. (In actuality Python premaps attributes to the approprirate base class, so only two dict lookups are necessary.) Python is a very dynamic langauge which allows you to modify class objects at runtime. So if you inherit from a class, then later modify that class, what should happen? class A(object): foo = 1 class B(A): pass A.foo = 2 print B.foo # what should this print, 1 or 2? You could argue that copying class attributes (so that B.foo would be 1) is a reasonable way to do inheritance, but IMO the referencing attributes in base classes reflects the underlying concept of inheritance better. Carl Banks -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> would you expect the B class to have a copy of the foo method? Sorta. I would expect B to have a copy of the "foo" attribute, which then refers to the same method as A.foo. So the method itself will be be copied, but its address stored separately in A.foo and B.foo. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Tue, 08 Sep 2009 04:36:19 -0700, HPJ wrote: >> Makes sense to me. To step through what's happening: >> >> >>> A.n, B.n >> (0, 0) >> >> Here, the lookup on B.n fails (that is, B itself has no variable n), >> and thus falls back to A.n > > See, this is what tripped me up, right at the beginning. I thought B > would inherit (as in copy) the variable n from A. Inherit does not mean copy. What makes you think it does? Given the following: class A(object): def foo(self): return "foo" class B(A): pass would you expect the B class to have a copy of the foo method? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> I could, but I will let you read and find what it says about class > attributes. You think I would have asked specifically about the Language Reference if I hadn't read it and failed to find what I was looking for? The closest thing I was able to find was section 3.2. "The standard type hierarchy", subsection "Custom classes", where it says: "When the attribute name is not found [in its namespace dictionary], the attribute search continues in the base classes. This search of the base classes uses the C3 method resolution order [...]" That tells me how the lookup works, which I already knew. But it doesn't tell me what happens when a class is inherited. Now, one could argue if the attributes were copied, there would be no need for a lookup in the base classes, so derivatively it says that's not the case. To this I would say yes, there still would because after they've been copied through inheritance, attributes can still be removed via "del". Anyway, this passage, which is the only one I could find, doesn't provide a direct and conclusive answer to my question. -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
HPJ wrote: Makes sense to me. To step through what's happening: A.n, B.n (0, 0) Here, the lookup on B.n fails (that is, B itself has no variable n), and thus falls back to A.n See, this is what tripped me up, right at the beginning. I thought B would inherit (as in copy) the variable n from A. Python does not copy objects unless asked to. Inheritance is a link request, not a copy request. Can you point out to me which part (or parts) of the Language Reference says this is the way it's supposed to be? I could, but I will let you read and find what it says about class attributes. tjr -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
> Makes sense to me. To step through what's happening: > > >>> A.n, B.n > (0, 0) > > Here, the lookup on B.n fails (that is, B itself has no variable n), > and thus falls back to A.n See, this is what tripped me up, right at the beginning. I thought B would inherit (as in copy) the variable n from A. Can you point out to me which part (or parts) of the Language Reference says this is the way it's supposed to be? -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Mon, Sep 7, 2009 at 7:21 PM, Henry 'Pi' James wrote: > I've just found out that a subclass shares the class variables of its > superclass until it's instantiated for the first time, but not any > more afterwards: > > Python 3.1 (r31:73574, Jun 26 2009, 20:21:35) [MSC v.1500 32 bit > (Intel)] on win32 > Type "help", "copyright", "credits" or "license" for more information. class A: > ... n = 0 > ... def __init__(self): > ... type(self).n += 1 class B(A): > ... pass > This makes no sense to me at all. Could it possibly be a bug? Makes sense to me. To step through what's happening: >>> A.n, B.n (0, 0) Here, the lookup on B.n fails (that is, B itself has no variable n), and thus falls back to A.n Thus, at this point, the expressions `A.n` and `B.n` are equivalent. >>> (A().n, A.n, B.n) (1, 1, 1) A.__init__() gets called, incrementing A.n; again, B.n falls back to A.n >>> (A().n, A.n, B.n) (2, 2, 2), >>> (B().n, A.n, B.n) (3, 2, 3) A.__init__() gets called since B did not define one of its own and this inherited A's. Therein, type(self) evaluates to B (not A as before). B.n += 1 is in this case equivalent to: B.n = B.n +1 Evaluating the right side, B.n falls back A.n once again, and we add 1. Now the assignment takes place, creating a new variable B.n, *separate* from A.n From hereon in, lookups of B.n don't fall back to A.n since B now has its own variable 'n'. Thus, the values of A.n and B.n differ and the expressions now refer to 2 distinct variables. The rest falls out from this and is left as an exercise for the reader. Cheers, Chris -- http://blog.rebertia.com -- http://mail.python.org/mailman/listinfo/python-list
Re: Class variable inheritance
On Mon, 07 Sep 2009 19:21:28 -0700, Henry 'Pi' James wrote: > I've just found out that a subclass shares the class variables String variables are strings. Int variables are ints. Float variables are floats. List variables are lists. Class variables are classes. Classes are first-class objects in Python. Perhaps you mean class attributes? > of its > superclass until it's instantiated for the first time, but not any more > afterwards: ... > This makes no sense to me at all. Could it possibly be a bug? You have misinterpreted what you have seen, and if there's a bug, it's in your code. When you retrieve an attribute, Python first looks for instance attributes, then class attributes, then attributes attached to superclasses. When you assign to an attribute, Python conceptually uses the exact same "search path", except that instance assignment always succeeds. (Well, almost -- but if it fails, you get an exception.) So in practice: x = obj.whatever may return the contents of an instance attribute "whatever", a class attribute, or an attribute of a superclass. But: obj.whatever = x always attempts to store x as an instance attribute, because there's no way for Python to read your mind and know that you mean a class attribute unless you say so explicitly. This attempt will either succeed, or it will raise an exception. Python doesn't try writing further along the hierarchy of instance/class/superclass(es). If you wish to write to a class attribute, you have to explicitly say so: obj.__class__.whatever = x Your other misunderstanding relates to augmented assignment: x += 1 does not modify x in place, it is *exactly* equivalent to: x = x + 1 Given the rules of attribute access, obj.whatever += 1 is exactly equivalent to: obj.whatever = obj.whatever + 1 The right hand attribute access finds a class attribute, and the left hand one sets an instance attribute. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Class variable inheritance
I've just found out that a subclass shares the class variables of its superclass until it's instantiated for the first time, but not any more afterwards: Python 3.1 (r31:73574, Jun 26 2009, 20:21:35) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> class A: ... n = 0 ... def __init__(self): ... type(self).n += 1 >>> class B(A): ... pass >>> A.n, B.n (0, 0) >>> (A().n, A.n, B.n), (A().n, A.n, B.n), (B().n, A.n, B.n) ((1, 1, 1), (2, 2, 2), (3, 2, 3)) >>> (A().n, A.n, B.n), (A().n, A.n, B.n), (B().n, A.n, B.n) ((3, 3, 3), (4, 4, 3), (4, 4, 4)) >>> (A().n, A.n, B.n), (A().n, A.n, B.n), (B().n, A.n, B.n) ((5, 5, 4), (6, 6, 4), (5, 6, 5)) This makes no sense to me at all. Could it possibly be a bug? -- http://mail.python.org/mailman/listinfo/python-list
Re: Class Variable Inheritance
Brian Jones wrote: class a(object): mastervar = [] def __init__(self): print 'called a' class b(a): def __init__(self): print 'called b' self.mapvar() def mapvar(self): self.mastervar.append(['b']) class c(b): mastervar = [] # Adding this should make things clearer def __init__(self): print 'called c' self.mapvar() def mapvar(self): super(c, self).mapvar() self.mastervar.append(['c']) if __name__ == '__main__': a1 = a() b1 = b() c1 = c() d1 = c() # Call C again for object in a1, b1, c1, d1: print id(object.mastervar), object.mastervar What I don't understand is why mastervar gets modified by each _seperate instance_ of classes that happen to extend the base class 'a'. Shouldn't mastervar be contained within the scope of the inheriting classes? Why is it being treated like a global variable and being modified by the other instances? By over-riding mastervar in class c, I hope I've shown that a class variable is shared by all of its instances, but can be over-ridden by a subclass's class variable. --Scott David Daniels [EMAIL PROTECTED] -- http://mail.python.org/mailman/listinfo/python-list
Re: Class Variable Inheritance
On Thu, 2004-12-09 at 08:55, Brian Jones wrote: > I'm sure the solution may be obvious, but this problem is driving me > mad. The following is my code: > > class a(object): > > mastervar = [] > > def __init__(self): > print 'called a' > > class b(a): > > def __init__(self): > print 'called b' > self.mapvar() > > def mapvar(self): > self.mastervar.append(['b']) > > class c(b): > > def __init__(self): > print 'called c' > self.mapvar() > > def mapvar(self): > super(c, self).mapvar() > self.mastervar.append(['c']) > > if __name__ == '__main__': > > a1 = a() > b1 = b() > c1 = c() > d1 = c() # Call C again > > print a1.mastervar > print b1.mastervar > print c1.mastervar > print d1.mastervar > > What I don't understand is why mastervar gets modified by each _seperate > instance_ of classes that happen to extend the base class 'a'. > Shouldn't mastervar be contained within the scope of the inheriting > classes? Why is it being treated like a global variable and being > modified by the other instances? A variable declared in a class definition is shared by all instances of the class. Python uses, essentially, a search path for names that goes from most specific to least specific scope. In your example, a lookup in c1 for mastervar will search for mastervar in: c1.__dict__ c1.__class__.dict (ie b.__dict__) a.__dict__ Note that "class variables" are not _copied_, they're just looked up in the class object if not found in the instance. Remember, the class declaration is only executed _once_ - then __init__ is executed for each new instance. If you want a per-instance copy of a variable, you need to generate a new copy in the __init__ method of the instance (or the parent class and call the parent's __init__ with super() ). If you actually assigned c1.mastervar, rather than modifying the dict, you would get the per-instance dictionary you expected. I strongly recommend a read of the book "Learning Python" if you want to really _understand_ this stuff (and they do a much better job explaining it than I ever could in my overcomplicated and incoherent way). I think the Python behaviour is counter-intuitive to C++ and Java programmers, but makes good sense in the context of the way Python classes, inheritance, and namespaces work. It's also extremely consistent with the way namespaces and inheritance work in the rest of Python - there's no special magic for objects and classes. A good rule might be "If you want Java-style instance variables, create instances variables in __init__ not in the class declaration." This might help explain things - ore might just confuse even more: >>> class A(object): ... ina = ["in A"] ... >>> class B(A): ... inb = ["in B"] ... >>> class C(A): ... ina = ["in C"] ... inc = ["in C"] ... >>> # examine the class dictionaries ... >>> A.__dict__.keys() ['ina', ...] >>> B.__dict__.keys() ['inb', ...] >>> C.__dict__.keys() ['ina', 'inc', ...] >>> # Now look up some variables to demonstrate the namespace ... # search in class inheritance ... >>> A.ina ['in A'] >>> B.ina ['in A'] >>> C.ina # remember, we redefined this in C ['in C'] >>> B.inb ['in B'] >>> C.inc ['in C'] >>> # This should help explain things ... >>> B.ina is A.ina # True, because B.ina just looks up A.ina True >>> C.ina is A.ina # False, because C.ina is found first False >>> # Now modify B.ina. Because asking for B.ina searches B, then A, ... # for ina, we'll actually end up modifying A.ina ... >>> B.ina.append("blah") >>> A.ina ['in A', 'blah'] >>> B.ina ['in A', 'blah'] >>> # but if we do the same to C.ina, which is redefined in C, ... # a.ina won't be modified ... >>> C.ina.append("change") >>> A.ina ['in A', 'blah'] >>> C.ina ['in C', 'change'] >>> # Now we're going to assign to B.ina, rebinding the name, ... # instead of just modifying the existing mutable object. ... >>> B.ina = "fred" >>> B.ina "fred" >>> B.__dict__.keys() ['inb', 'ina'] >>> # Note that there's now a new value for ina in B's dictionary. It ... # is found by the search BEFORE looking for A.ina, and used. A.ina ... # is not modified. ... >>> A.ina ['in A', 'blah'] What you can see happening here is the combination of a couple of principles: - Name lookups in classes happen as a search through the class dictionary then all its parent classes' dictionaries for a name. - Name assignments to a class are made directly in its dictionary. - A modification of a mutable value is a lookup of a name followed by the modification of an object, not an assignment to a name. The principle is pretty similar for instances and classes - a variable defined in a class is a single object shared between all instances of a class, and if mutable can be modified by all of them. Example: >>> class D(object): ...
Re: Class Variable Inheritance
Brian "bojo" Jones wrote: It became clear to me that mastervar inside of class a is a static variable, and is associated with all instances of classes that extend class a. Yeah, that's basically what's happening. AFAICT, a variable declared at class level is shared with all subclasses (and is available to all instances unless hidden by an instance variable). You can simulate the kind of behavior you want using descriptors: >>> import copy >>> class subclass_copied(object): ... def __init__(self, initial_value): ... self.initial_value = initial_value ... self.instances = {} ... def __get__(self, instance, owner): ... if owner not in self.instances: ... self.instances[owner] = copy.copy(self.initial_value) ... return self.instances[owner] ... >>> class A(object): ... x = subclass_copied([]) ... >>> class B(A): ... pass ... >>> A.x.append(1) >>> A().x.append(2) >>> A.x [1, 2] >>> B.x [] >>> B.x.append(3) >>> B().x.append(4) >>> B.x [3, 4] >>> A.x [1, 2] Basically, the subclass_copied descriptor returns a different object for each class by keeping a type -> object dict. If you wanted to be thorough with this, you would probably define a __set__ method too; see: http://docs.python.org/ref/descriptors.html Steve Steve -- http://mail.python.org/mailman/listinfo/python-list
Re: Class Variable Inheritance
On Wed, 08 Dec 2004 16:49:34 -0900, Brian "bojo" Jones wrote: > class a(object): > > def __init__(self): > self.map = mapper() > print 'called a' What is the advantage of this over def __init__(self): self.map = [] ? -- http://mail.python.org/mailman/listinfo/python-list
Re: Class Variable Inheritance
On Wed, 08 Dec 2004 15:55:09 -0900, Brian Jones wrote: > I'm sure the solution may be obvious, but this problem is driving me > mad. The following is my code: > > class a(object): > > mastervar = [] > > def __init__(self): > print 'called a' > > class b(a): > > def __init__(self): > print 'called b' > self.mapvar() > > def mapvar(self): > self.mastervar.append(['b']) > > class c(b): > > def __init__(self): > print 'called c' > self.mapvar() > > def mapvar(self): > super(c, self).mapvar() > self.mastervar.append(['c']) > > if __name__ == '__main__': > > a1 = a() > b1 = b() > c1 = c() > d1 = c() # Call C again > > print a1.mastervar > print b1.mastervar > print c1.mastervar > print d1.mastervar > > What I don't understand is why mastervar gets modified by each _seperate > instance_ of classes that happen to extend the base class 'a'. > Shouldn't mastervar be contained within the scope of the inheriting > classes? Why is it being treated like a global variable and being > modified by the other instances? > > > Thanks, > > Brian "bojo" Jones Brian, This is the first time I've responded to a post in this newsgroup so bear with me. First of all I believe that the place you declare mastervar is important. As you have placed it above (or outside) any class methods/functions it becomes a class variable. This gives it class scope and ALL instances of that class (and sub-classes I think) will reference the SAME variable. If, instead, you declare it inside the __init__ function of the class a object it will be an instance variable and inheritable. Secondly, in order to inherit methods and functions from base classes it is important to remember to call the base class __init__ function in the sub-class __init__ function. If you do both these things, that is declare mastervar as 'self.mastervar = []' inside class a.__init__ and call a.__init__ from b.__init__ (and likewise for b in c) then you should get the expected result. I hope. All I can say at this point is that I and not what you would call a programmer, and I could be quite wrong in my explanation. However if this doesn't help then there are many folk here who are better qualified to give you the correct solution. Regards -- http://mail.python.org/mailman/listinfo/python-list
Re: Class Variable Inheritance
It became clear to me that mastervar inside of class a is a static variable, and is associated with all instances of classes that extend class a. To get around this, I implemented a seperate mapping class: class mapper: def __init__(self): self.mastermap = [] def add(self, map): self.mastermap.append(map) def get(self): return self.mastermap class a(object): def __init__(self): self.map = mapper() print 'called a' class b(a): def __init__(self): self.map = mapper() print 'called b' self.mapvar() def mapvar(self): self.map.add('b') class c(b): def __init__(self): self.map = mapper() print 'called c' self.mapvar() def mapvar(self): super(c, self).mapvar() self.map.add('c') if __name__ == '__main__': a1 = a() a2 = a() b1 = b() c1 = c() d1 = c() # Call C again print a1.map.get() print a1.map.get() print b1.map.get() print c1.map.get() print d1.map.get() Brian Jones wrote: I'm sure the solution may be obvious, but this problem is driving me mad. The following is my code: -- http://mail.python.org/mailman/listinfo/python-list
Class Variable Inheritance
I'm sure the solution may be obvious, but this problem is driving me mad. The following is my code: class a(object): mastervar = [] def __init__(self): print 'called a' class b(a): def __init__(self): print 'called b' self.mapvar() def mapvar(self): self.mastervar.append(['b']) class c(b): def __init__(self): print 'called c' self.mapvar() def mapvar(self): super(c, self).mapvar() self.mastervar.append(['c']) if __name__ == '__main__': a1 = a() b1 = b() c1 = c() d1 = c() # Call C again print a1.mastervar print b1.mastervar print c1.mastervar print d1.mastervar What I don't understand is why mastervar gets modified by each _seperate instance_ of classes that happen to extend the base class 'a'. Shouldn't mastervar be contained within the scope of the inheriting classes? Why is it being treated like a global variable and being modified by the other instances? Thanks, Brian "bojo" Jones -- http://mail.python.org/mailman/listinfo/python-list