3

I have a set of classes which should all keep track of which instance they are. For this purpose I have a class variable in the parent class, which is copied and incremented at initialization of each object. Here's a minimal example which seems to work just fine:

class Parent:
    counter = 0
    def __init__(self):
        self.name = self.__class__.__name__ + "_" + str(self.__class__.counter)
        self.__class__.counter += 1

    def __repr__(self):
        return self.name

mother = Parent()
father = Parent()
print(mother)
print(father)

Parent_0

Parent_1

So far so good. Now I'd like to use make some subclasses that have the same behavior without rewriting the code. So I do this:

class Child(Parent):
    # counter = 0
    pass

son = Child()
daughter = Child()
stepfather = Parent()

print(son)
print(daughter)
print(stepfather)

Child_2

Child_3

Parent_2

This behavior is not what I intended. When the first instance of a child is created it inherits whichever value the parent counter has at that moment, however after this the classes each maintain their own counter. I can avoid this by putting the line counter = 0 into every single subclass, but this strikes me as redundant. Is there some more elegant way that I can inherit the behavior from the parent without having to redeclare the same variable every time?

4
  • 1
    not sure if I got you correctly - do you want each subclass to have its own 0 based counter or do you want a running counter over all base/derived classes? Commented Mar 5, 2018 at 12:49
  • 2
    What is your expected output? Do all objects share a counter, or a separate one for children and parents? Commented Mar 5, 2018 at 12:50
  • Sorry for being unclear. I want each class and subclass to have its own counter starting at 0. Uncommenting the single commented line in my code example gives my desired behavior. Commented Mar 5, 2018 at 12:54
  • 1
    Added code example Commented Mar 5, 2018 at 12:56

1 Answer 1

2

No idea why you want this behavior, but ... instead of an counter int, create a counter dict:str->int in Parent. Use a key of self.__class__.__name__ to acces the running counter of each seperate class in it. With assign it with dict.setdefault(self.__class__.__name__,0) and increment it inside __init__.

 class Parent:
    counter = dict()

    def __init__(self):
        Parent.counter.setdefault(self.__class__.__name__,0)
        self.name = f'{self.__class__.__name__}_{Parent.counter[self.__class__.__name__]}' 
        Parent.counter[self.__class__.__name__] += 1

    def __repr__(self):
        return self.name

mother = Parent()
father = Parent()
print(mother)
print(father)

class Child(Parent):
    # counter = 0
    pass

son = Child()
daughter = Child()
stepfather = Parent()

print(son)
print(daughter)
print(stepfather)

Output:

Parent_0
Parent_1
Child_0
Child_1
Parent_2
Sign up to request clarification or add additional context in comments.

3 Comments

This seems to accomplish what I am looking for. I have changed the 0 to an empty dict and the init to cl = self.__class__ ; self.name = cl.__name__ + "_" + str(cl.counter.setdefault(cl.__name__, 0)) ; cl.counter[cl.__name__] += 1 . Could you elaborate why this behavior is weird / unexpected for you?
I never hat the need to auto-name and "count" the "instances" of my classes :) so no need to do this. I am not quite getting why you would need a dict of dicts to hold the counters (or are you talking of your code, not the one I added ?) Mine uses the f''{} format syntax. @James
Basically I want a unique string describing each object, because the objects are wrappers for tensorflow subgraphs, and tensorflow allows you to give your variables names in the form of python strings. That's why I wanted to provide easily interpretable default values automatically. The counters are there so it doesn't accidentally lump together different objects. The {} formatting I know, I just forget the rules for it sometimes :) - anyway thanks for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.