class MyClass(object):
next_number = 0
def __init__(self):
self.number = self.next_number
MyClass.next_number += 1
class MyClassA(MyClass):
pass
Above it would appear I am forced hardcode the class name when updating the class variable on line 6 since writing:
self.__class__.next_number += 1
results in a new class variable in any derived class. Is there any alternative to hardcoding the class name?
Also on line 5 should I instead write:
self.number = self.__class__.next_number
to make it obvious next_number is a class variable.
One way to dodge around the issue of rebinding the class variable is to replace the immutable integer value with an mutable object that contains the number inside it. You can then mutate the object in place.
A simple version of this is to put the number in a one-element list:
class MyClass(object):
next_number = [0]
def __init__(self):
self.number = self.next_number[0]
self.next_number[0] += 1
That works, but it's not very elegant.
A much better approach would be to replace the integer class variable with an iterator returned by the itertools.count
function, which will yield successively higher integers each time you call next
on it (forever, it's an infinite iterator). At a high level this still works like the list code, since next
mutates the iterator, but the exact details are hidden behind the iterator protocol (and the implementation of itertools.count
).
class MyClass(object):
number_iter = itertools.count()
def __init__(self):
self.number = next(self.number_iter) # this mutates number_iter by consuming a value
If you needed something a little more complicated, such that itertools
didn't provide exactly the right sequence, you could write your own generator function and assign its return value to your class variable. For instance, here's a generator for the Fibonacci sequence:
def fib():
a, b = 0, 1
while True:
a, b = b, a+b
yield a
You are correct that self.__class__.next_number
would create a variable for each class that instantiate an object that calls this __init__
.
You have 2 choices: hard code the class name as you did, or do not call super().__init__
from the derived class.
I would go with the former.
In my opinion, you are unnecessarily worried about hard coding the class name here. After all, the class name is "hard coded" in this module already anyway when you do class MyClass(object):
.
Regarding your second comment, it is a good consideration to have. I would go with: self.__class__.next_number += 1
. Not only is this more explicit to the reader, but it also guarantees that you keep the appropriate behaviour, should you mistakenly define self.next_number later on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With