0

I am trying to have a single static variable as an 'id' for all the child instantiations of this parent class. The problem I'm having is double counting of this ID, likely because the parent's __init__ gets called twice. But if I remove the explicit Parent().__init__() call, then the counter doesn't get incremented at all. How do I get the id to increment only ones? Here's my code snippet:

#!/usr/bin/python3
class Parent:
    cls_id = 0

    def __init__ (cls):
        cls.cls_inc_id()

    @classmethod
    def cls_inc_id (cls):
        cls.cls_id += 1

    @classmethod
    def child_inc_id (self):
        self.id += 1


class Child1 (Parent):

    def __init__ (self):
        Parent().__init__()
        self.id = super().cls_id
        print ("Child1 id: ", self.id)

class Child2 (Parent):

    def __init__ (self):
        Parent().__init__()
        self.id = super().cls_id
        print ("Child2 id: ", self.id)


child1 = Child1()
child2 = Child1()

child3 = Child2()
child4 = Child2()

My output is: %> ./static_vars.py

Child1 id:  2
Child1 id:  4
Child2 id:  6
Child2 id:  8

Thanks in advance

2
  • 1
    I'm sorry, what is it exactly you are trying to accomplish? What is the output you expect? Commented Sep 23, 2021 at 17:46
  • 2
    As an aside, don't use cls as the name of the first argument to __init__. Conventionally, it should be __init__ (self) since it is an instance method Commented Sep 23, 2021 at 17:49

2 Answers 2

2

It gets incremented twice because of Parent().__init(). That creates a brand-new object, initializes it, then discards it. You should use super().__init__(), and in your __init__ method refer to Parent.cls_inc_id`. Then it will work.

And by the way, in Parent.__init__ you call the parameter "cls", but it's actually "self" -- that's an object method, not a class method.

New code:

#!/usr/bin/python3
class Parent:
    cls_id = 0

    def __init__ (self):
        print("Parent.__init__")
        Parent.cls_inc_id()

    @classmethod
    def cls_inc_id (cls):
        print("Parent.cls_inc_id")
        cls.cls_id += 1

    @classmethod
    def child_inc_id (cls):
        print("child_inc_id")
        cls.id += 1


class Child1 (Parent):

    def __init__ (self):
        print("Child1.__init__")
        super().__init__()
        self.id = super().cls_id
        print ("Child1 id: ", self.id)

class Child2 (Parent):

    def __init__ (self):
        print("Child2.__init__")
        super().__init__()
        self.id = super().cls_id
        print ("Child2 id: ", self.id)


child1 = Child1()
child2 = Child1()

child3 = Child2()
child4 = Child2()

Output:

Child1.__init__
Parent.__init__
Parent.cls_inc_id
1
Child1 id:  1
Child1.__init__
Parent.__init__
Parent.cls_inc_id
1
Child1 id:  2
Child2.__init__
Parent.__init__
Parent.cls_inc_id
1
Child2 id:  3
Child2.__init__
Parent.__init__
Parent.cls_inc_id
1
Child2 id:  4
Sign up to request clarification or add additional context in comments.

9 Comments

Also cls.cls_inc_id() needs to be Parent.cls_inc_id(). Otherwise it creates an instance attribute instead of updating the class attribute.
Hah! Very good eye!
@Barmar no it doesn't, because cls_inc_id is a classmethod
Yes it does, because he's CALLING it as an object method. Try it.
I'm not sure what you mean. It will always get provided the class object as the first parameter. It doesn't matter how you call it, it won't create an instance attribute. However, it will create seperate class variables depending on how you call it. i.e. if you use self.cls_inc_id(), the Parent.cls_inc_id method gets passed either Child1 or Child2 depending on the type of self
|
1

As others have mentioned, you're not using super constructor correctly, but also I would reference the actual class in the parent class, not the instance self which you incorrectly named cls:

class Parent:
    cls_id = 0

    def __init__(self):
        self.id = Parent.cls_id
        Parent.cls_id += 1


class Child1(Parent):
    def __init__(self):
        super().__init__()
        print ("Child1 id: ", self.id)


class Child2(Parent):
    def __init__(self):
        super().__init__()
        print ("Child2 id: ", self.id)


child1 = Child1()
child2 = Child1()

child3 = Child2()
child4 = Child2()
Child1 id:  0
Child1 id:  1
Child2 id:  2
Child2 id:  3

If you wanted a separate ID per type of class, you could use a dictionary mapping class to id:

from collections import defaultdict


class Parent:
    cls_ids = defaultdict(int)

    def __init__(self):
        self.id = Parent.cls_ids[type(self)]
        Parent.cls_ids[type(self)] += 1
Child1 id:  0
Child1 id:  1
Child2 id:  0
Child2 id:  1

1 Comment

Thanks for the tip on using the collections package. I'll give this a shot.

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.