In this piece of code when I write name of the class in the forth line, the account_id differs every time, but when I use self instead, the account_id will be the same number as much as the number of objects, in the reference I’ve learnt from, it said ther’s no difference between using the name of class and key word self in such a situation, but I see in this example that it differs, what’s the reason? Is what I learnt wrong?
class BankAccount():
initial_acount_id = 1000110011
def __init__(self, fname, lname, deposit = 0) -> None:
BankAccount.initial_acount_id += 12
self.account_id = self.initial_acount_id
self.fname = fname
self.lname = lname
self.deposit = deposit
fir = BankAccount("ali", 'zarei')
sec = BankAccount('mehrdad', 'rsccz', 50)
thi = BankAccount('sdad', 'ccjkj')
print(fir.account_id)
print(sec.account_id)
print(thi.account_id)
>Solution :
I assume you are asking about self.initial_account_id += 12. This does not update the class attribute; it creates a new instance attribute which shadows the class attribute, equivalent to self.initial_account_id = self.initial_account_id + 12. For each new instance, the right-hand occurrence of self.initial_account_id does not yet exist, and so devolves to BankAccount.initial_account_id.
Assuming you don’t define an instance attribute named initial_account_id, then self.account_id = self.initial_account_id will work as expected (the RHS resolves to BankAccount.initial_account_id), but it’s still better to be explicit:
class BankAccount:
initial_account_id = 1000110011
def __init__(self, fname, lname, deposit = 0) -> None:
BankAccount.initial_account_id += 12
self.account_id = BankAccount.initial_account_id
self.fname = fname
self.lname = lname
self.deposit = deposit
(That is to say, if you intend to use a class attribute, say so, instead of implicitly accessing it via an instance of the class.)
Even better, remove the (explicit) logic of incrementing the account ID from BankAccount.__init__, and do so implicitly by using an iterator.
from itertools import count
class BankAccount:
initial_account_id = count(1000110011, 12)
def __init__(self, fname, lname, deposit = 0) -> None:
# As an aside, self.initial_account_id here would
# be safe, since we aren't *assigning* to the attribute, only calling
# one of its mutating methods.
self.account_id = next(BankAccount.initial_account_id)
self.fname = fname
self.lname = lname
self.deposit = deposit