In Python:
- all variables are references
- integers and strings are immutable
So when you do:
>>> a = 1 # a points to 1
>>> b = a # b points to 1
>>> b = 10 # b now points to 10, a still points to 1 and 1 is unchanged.
>>> b
10
>>> a
1
If you use a mutable data type, then it works:
>>> a = []
>>> b = a
>>> b.append(10)
>>> b
[10]
>>> a
[10]
>>> a[0] = 20
>>> b
[20]
Perhaps you can create a generic container:
class GenericContainer(object):
def __init__(self, **kwargs):
self._keys = set()
for k, v in kwargs.items():
if k in ('inventory', 'charge'):
raise ValueError('Unable to override method {}'.format(k))
setattr(self, k, v)
self._keys.add(k)
def charge(self, **kwargs):
for k, v in kwargs.items():
if k in ('inventory', 'charge'):
raise ValueError('Unable to override method {}'.format(k))
if v < 0 and getattr(self, k, 0) < abs(v):
raise ValueError("You don't have enough {}".format(k))
setattr(self, k, getattr(self, k, 0) + v)
self._keys.add(k)
return self
def inventory(self):
return {k:getattr(self, k) for k in self._keys}
def __repr__(self):
return str(self.inventory())
Then your wallet can be an instance of GenericContainer:
>>> wallet = GenericContainer(gold=10, silver=5)
>>> wallet
{'gold': 10, 'silver': 5}
>>> wallet.charge(gold=-5, silver=5)
{'gold': 5, 'silver': 10}
>>> wallet.charge(gold=-20)
ValueError: You don't have enough gold
>>> wallet.gold
5
You can set and/or retrieve the attributes directly:
>>> wallet.gold
5
>>> wallet.gold += 10
>>> wallet.gold
15
>>> wallet
{'gold': 15, 'silver': 10}
You can get the attribute by name from the inventory or using getattr
:
>>> wallet.inventory().get('gold', 0)
15
>>> getattr(wallet, 'gold')
15
You can set it by name using dict of parameter:value or setattr
:
>>> wallet.charge(**{'gold': -10})
{'gold': 5, 'silver': 10}
>>> setattr(wallet, 'gold', 20)
>>> wallet.gold
20
Looking at the result, I see why in Python I often use just a dictionary instead of creating a class - although I do miss the Javascript object syntax where you can access properties both using either foo.bar
or foo["bar"]
.
In Python, the builtin data structures are very powerful and Python developers tend to use a "we are all consenting adults" approach where you just pass data around without caring too much about attribute protection. Probably I would end up doing just this:
>>> wallet = {'gold': 10, 'silver': 15}
And instead of using a charge(gold=10)
method:
>>> wallet['gold'] += 10
It takes time for this "it is just data" approach to sink but after that you seldom miss the more bureaucratic OO idioms so common in languages like Java or C++ specially for small projects/teams.