0

I have a base class which has a blank list as a class attribute. Many child classes inherit from this base class. The intent is to use this list class attribute in conjunction with a class method in order to allow each child class to keep track of a certain set of its own instances. Each class is supposed to have a separate list which contains only its own instances.

When I made a naive implementation of this inheritance scheme, durring debugging I noticed that in fact every single child class was sharing the exact same list as a class attribute, and I was once again having Fun with the fact that python passes lists by reference. On closer inspection, it seems like every class attribute of the parent, methods and values alike, is simply passed by reference to every child, and that this doesn't change unless a particular attribute is explicitly overridden in the definition of the child.

What is the best way to reinitialize the class variables of a child upon its creation? Ideally, I'd like a way to ensure that every child starts with a cls.instances attribute that is a unique blank list which involves NO extra code in any of the children. Otherwise, what am I bothering with inheritance for in the first place? (don't answer that)

tel
  • 13,005
  • 2
  • 44
  • 62
  • What do you mean by same list? They had the same value e.g. `[]` or that they were actually the same reference in memory; there is a difference. – Hunter McMillen May 18 '12 at 20:23
  • @Hunter I mean that they were exactly the same. Pointed to the same location in memory. id(list) returned the same value, etc., etc. – tel May 18 '12 at 20:31

4 Answers4

3

No disrespect to @DanielRoseman and his insightful answer, but I thought I'd write up exactly how you'd use metaclasses to accomplish what I understand you want to accomplish:

mc.py:

class Meta(type):
    def __init__(cls, name, bases, attrs):
        cls.foo = []

class A:
    __metaclass__ = Meta

class B(A):
    pass

Given this:

>>> import mc
>>> mc.A.foo
[]
>>> mc.A.foo.append(1)
>>> mc.A.foo
[1]
>>> mc.B.foo
[]
Mattie
  • 20,280
  • 7
  • 36
  • 54
1

This is the point that you probably need to get into metaclasses. What you're saying is that each time you define a new child class, you need a new set of variables. So, the metaclass is the class of the class type: you're instantiating a new instance of the metaclass each time you define a subclass. Each metaclass instance can have its own instance variables, which means that each subclass gets its own set of class variables.

There's a great write-up of how to use metaclasses to do this sort of thing on Marty Alchin's blog.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Sigh... metaclasses? At this point I seriously just want to go and drown this project in the bathtub. But I will persevere! I'll go check out that blog you linked. – tel May 18 '12 at 20:50
0

Do you mean something like this:

    >>> class Foo():
    ...   alist = []
    ...   def __init__(self):
    ...     pass
    >>> foo = Foo()
    >>> foo.alist
    []
    >>> Foo.alist
    []
    >>> Foo.alist.append(7)
    >>> Foo.alist
    [7]
    >>> foo.alist
    [7]
    >>> foo2 = Foo()
    >>> foo2.alist
    [7]
Schuh
  • 1,045
  • 5
  • 9
0

I think the problem you are running in to here is that classes are actually objects, and class members are members of the type type object of the class rather than members of the instances thereof. From that perspective, it is easy to see why a subclass does not actually have a unique instance of the parent's class-level member. A method I've used to solve this sort of problem in the past is to make your .instances class variable in the parent a dictionary, then catalog instances of each child, in the parent's __init__ method, in a list stored in the .instances dictionary under a key that is of the self type. Remember, even from within the parent scope, doing type() on self will give you the type the object was created as directly, not the type of the local scope.

Silas Ray
  • 25,682
  • 5
  • 48
  • 63