简体   繁体   中英

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.

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, ya 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 .

The thing you haven't understood about __init__ is that it is only called when you instantiate (ie 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
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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM