3

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.

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

2 Comments

It's a string typed really fast.
thanks for the second answer. I must have missed that somewhere. This also answer some questions about scope. Regarding the first question: I thought foo() would be called only after the class B has been instantiated. I was wrong. Thanks!
1

The thing you haven't understood about __init__ is that it is only called when you instantiate (i.e. make an instance of) class A. Since nowhere in your code have you actually made an instance of this class, you never call its initialiser and hence never run into the forward declaration.

In general forward declarations aren't a problem in Python, because the reference is only evaluated when you call the necessary function. The problem here is that class definitions are executed at define-time. More, specifically, here's what happens when the Python interpreter meets a class statement:

  • It defines a new namespace (dictionary of local variables) to hold all the code.
  • It executes the code inside the class definition.
  • It puts anything stored into the local namespace into the class __dict__.
  • It closes the new namespace and adds the new class to the module namespace.

Of course, you don't need to know that to define a class; you just need to remember that anything inside a class definition will be executed when the class is first defined! (This is rarely a problem, because class-level variables aren't that common in the first place, and don't usually need to be set dynamically at define-time.)

This issue also pops up in function definitions: when you do

def foo(x=bar()): pass

then bar will be called once, at the time foo is defined, and never again.


Try running the following code and see if it clarifies things:

class A():
    def __init__(self):
        self.a = foo()

a = A()

def foo():
    pass

2 Comments

the code does not run: NameError: global name 'foo' is not defined. But I understand what you mean.
@lorenzog: yes, that's the point: the same thing happens as above if you actually try to initialise the class, since then you are looking up a name which hasn't been defined yet.
1
class A:
    def __init__(self):
        a = foo("baa")

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

a is an instance attribute - each A has its own a variable, and foo("baa") is only evaluated when you create an A object.

b is a class attribute - every B object shares the same copy of b, and foo("boo") is evaluated when the class is defined.

In general, you can make references to functions and classes which do not yet exist so long as they get defined before you evaluate the reference (ie before you actually try calling the function).

Comments

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.