17

First of all, here's my test code, I'm using python 3.2.x:

class account:
    def __init__(self):
        pass

    class bank:
        def __init__(self):
            self.balance = 100000

        def balance(self):
            self.balance

        def whitdraw(self, amount):
            self.balance -= amount

        def deposit(self, amount):
            self.balance += amount

when I do:

a = account()
a.bank.balance

I expected to get the value of balance returned, instead I get the function "balance", why is this? It returns the value of balance when I do:

class bank:
    def __init__(self):
        self.balance = 100000

    def balance(self):
        self.balance

    def whitdraw(self, amount):
        self.balance -= amount

    def deposit(self, amount):
        self.balance += amount

a = bank()
a.balance

So I want to know why this is and it would be great if someone could come up with a way to give me the value of balance in the nested version.

9
  • May be a.bank.balance() (note: trailing brackets) will return correct value? Commented Jan 30, 2013 at 14:39
  • TypeError: ret_balance() takes exactly 1 argument (0 given) Commented Jan 30, 2013 at 14:41
  • 1
    Don't you need an instance of bank? i.e., in the __init__ method of account, you need something like self.my_bank = bank(), I think. Then check with a = account() and balance = a.my_bank.balance should be 100000. Commented Jan 30, 2013 at 14:42
  • You need to read a Python tutorial. See for instance docs.python.org/3/tutorial/classes.html Commented Jan 30, 2013 at 14:43
  • 1
    There's almost never any need to nest class definitions. Certainly, there is no need to do it here. Commented Jan 30, 2013 at 15:05

3 Answers 3

31

My version of your code, with comments:

#
# 1. CamelCasing for classes
#
class Account:
    def __init__(self):
        # 2. to refer to the inner class, you must use self.Bank
        # 3. no need to use an inner class here
        self.bank = self.Bank()

    class Bank:
        def __init__(self):
            self.balance = 100000

        # 4. in your original code, you had a method with the same name as 
        #    the attribute you set in the constructor. That meant that the 
        #    method was replaced with a value every time the constructor was 
        #    called. No need for a method to do a simple attribute lookup. This
        #    is Python, not Java.

        def withdraw(self, amount):
            self.balance -= amount

        def deposit(self, amount):
            self.balance += amount

a = Account()
print(a.bank.balance)
Sign up to request clarification or add additional context in comments.

Comments

10

There are several problems:

  1. You're using the name balance for both the data member and for the function.
  2. You're missing a return statement in balance().
  3. balance() operates on an instance of bank. There is no instance in a.bank.balance: here, a.bank refers to the inner class itself.

5 Comments

changed the balance function's name to ret_balance and added return in it's body, same result though
reading the other comments I'm convinced you're explanation of WHY it doesn't work is correct, do you have an idea on a way it would work?
@Daquicker: You need to create an instance of bank within the instance of account (just make sure the class and the instance don't have the same name).
Tried that by adding my_bank = bank() to the end of the account class, kinda doesn't work either, gives me this: <bound method bank.ret_balance of <__main__.bank object at 0x02D68E70>>
allright, found a way, just needed to add the brackets at the end, bumped into another problem though, when I have a = account() and change the value of balance by a.mybank.whitdraw(50000) and then do b = account(), the result of b.mybank.ret_balance also is 50000... while I want it to be 100000
1

a.bank is the class (not instance) since you've never created an instance of the bank on a. So if a.bank is a class, a.bank.balance is a method bound to that class.

This works however:

class account:
    def __init__(self):
        self.bank = account.bank()

    class bank:
        def __init__(self):
            self.balance = 100000

        def whitdraw(self, amount):
            self.balance -= amount

        def deposit(self, amount):
            self.balance += amount

a = account()
print a.bank.balance

Of course, as you show working code without nested classes, It really begs the question about why you want to use nested classes for this. I would argue that the non-nested version is much cleaner.

2 Comments

@Daquicker -- classes are really neat, and nesting them isn't really a problem once you understand python's scoping rules (which is definitely worth investing some time to learn). The main thing that I was trying to point out is that from a program design, it doesn't really make much sense in this case -- Actually, I tend to believe it doesn't make much sense in most cases, but maybe that's just because I haven't met those cases yet ;-). Anyway, this is still useful stuff to work through as an exercise.
I wanted to nest them because I need more things in account than only a bank and building classes for each major part seemed to be the neatest way to do it... I just want to keep everyhing together so it doesn't get scattered all across the code...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.