Private class variables (Python)

From LiteratePrograms

Jump to: navigation, search

Python does not have the concept of private class variables, offering only name-mangling to discourage internal methods from being called from outside the class.

However, Python does have lexical scoping, and with some clever trick one can get the benefits of private class variables.

In the code example below, we use the common example of a bank account class. The operations that are accessible to the public is get_balance, deposit and withdraw; the latter would fail if there are insufficient funds.

<<bank_account.py>>=
class account(object):
    def __init__(self, amount):
        private_vars
        private_methods
        class_methods
        instance_methods
<<private_vars>>=
privates = { 'balance' : amount }

The private variables need to be contained within a mutable object, otherwise attempts to modify it from a method would result in the creation of a local variable with the same name.

I use a dictionary here, but you can use a list as well. The advantage of using a dictionary is that it is more readable when you have many private variables.

<<private_methods>>=
'''
set_balance is a private method
it is only visible from other methods declared
in the constructor
'''
def set_balance(new_balance):
    privates['balance'] = new_balance

set_balance should be kept private, since it can set the bank balance to an arbitrary amount. By defining it inside the constructor and not attaching it to either the class or the method, we ensure that it can only be called by other methods we also define inside the constructor.

<<instance_methods>>=
'''
get_balance is attached to the
instance of the class, so it does not need
to take the object self, since it is in the
lexical scope
'''
def get_balance():
    return privates['balance']
self.get_balance = get_balance
def deposit(amount):
    bal = set_balance(get_balance() + amount)
self.deposit = deposit

Here are so-called instance methods. Note that they behave the same way as class methods, even though we attach them to the object instantiated from the class (self) rather than the class itself.

<<class_methods>>=
'''
withdraw is a more normal Python class method
'''
def withdraw(self, amount):
    bal = get_balance()
    if bal >= amount:
        bal = set_balance(bal - amount)
        return True
    else:
        return False
account.withdraw = withdraw

And class methods.

The only difference between the two is that if you try dir(account) after creating at least one object, the class methods will show up but the instance methods would not. It is probably preferable to use class methods for this reason.

Download code
Views