obj['balance']
notation won’t work here, obj.balance
is the right one.
As for the seemingly adding new entry to both ledgers. In fact there’s no two ledgers, but only one, both self.ledger
and obj.ledger
references here the same ledger
. This is because of defining ledger
as a class variable, instead of instance variable. Instance variables are defined in the __init__
method. Because it’s currently class variable, and lists are mutable types when appending, the ledger
variable on the instance isn’t defined, or redefined, but the original ledger
gets changed.
It may appear that for balance
and title
variables, also defined as class variables something else is happening. As those are of immutable types, this means internally they can’t be changed, but rather are overwritten with new value.
What might make this particularly interesting (and even more confusing) is the way python resolves names when accessed by self.x
. It first looks for the variables defined on the instance, if it doesn’t found it, then checks class variables, then parent classes and so on. However, when assigning to self.x
, the new variable will be saved as an instance variable.
What can happen the first time line obj.balance +=amount
or self.balance+=amount
is executed? First balance
variable is looked for in the instance variables. If not found, then class variables will be checked. There’s balance
class variable, so the value of it will be read, then to that value it will be added amount
. Now is the tricky part, because integers are immutable types, the original value can’t be changed to reflect added amount, but it needs to be overwritten. However, the saved value will be saved on the obj
or self
object, making this a newly created instance variable. Which will be later used in any further self.balance
or obj.balance
operation.
In case of wanting to update the actual class variable, similar notation is used, but with the class name: ClassName.variable