Search code examples
pythonclass-designforward-declaration

Python forward-declaration of functions inside classes


I am getting my head around Python for the first time and I am stuck here:

class A:
    def __init__(self):
        a = foo("baa")

class B(A):
    b = foo("boo")

def foo(string):
    return string

At this point I load the above file (named classes) and this happens:

$ python
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from classes import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "classes.py", line 5, in <module>
    class B(A):
  File "classes.py", line 6, in B
    b = foo("boo")
NameError: name 'foo' is not defined

Notice how the error is in class B, where foo is called directly and not from __init__. Notice also how I have not yet instantiated the class B.

First question:

  • Why is it returning an error? I am not instantiating a class.

Moving on. The 'problem' is solved by moving the definition of foo() a few lines above:

def foo(string):
    return string

class A:
    def __init__(self):
        a = foo("baa")

class B(A):
    b = foo("boo")

Now I can do

>>> x = B()
>>> x.b
'boo'

but I can't do

>>> y = A()
>>> y.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'a'

Further questions:

  • What is that I have not understood about __init__?

I don't think this is the same as a forward declaration, hence I hope this question is not a duplicate.

On a side note, I am aiming towards implementing a DSL, but that's mostly an excuse to get myself to learn python.


Solution

  • First, in class B, the function foo() is called before being declared. A does not have this problem because foo() is only called when the class is instantiated--after the function foo is defined.

    For your second question, y.a will not work because you did not say self.a = foo('stirng'). a = foo('stirng') only creates the variable a in the scope of __ init __.

    An ideal __ init __ function assigns variables to the instance self.