[Tutor] Expression order problem

Andrei project5 at redrival.net
Thu May 26 20:24:57 CEST 2005


William O'Higgins <william.ohiggins <at> utoronto.ca> writes:

> This is a problem if you are used to Perl, where the whole script is
> parsed first (Perl also auto-vivifies variables, but that's a different
> problem for a different day).  Here is a test script:

The Python compiler parses the whole script too, can't compile otherwise. Of
course a variable must exist if its value is requested. I don't know what
vivifying a variable means, but surely Perl doesn't pull a non-existing variable
out of its sleeves? 

> class test:
>     variable = "is this a variable" + other_argument
> 
> if sys.argv[1:]:
>     other_argument = sys.argv[2]
>     instance = test()
>     print instance.variable
> else:
>     sys.exit()
> I am only beginning to get my head around OO programming, so please bear
> with me.  In Perl, I would define all of my subs (functions or classes)
> at the end of the program, because the Perl parser will read the whole
> program, and then execute it.  So I'm having trouble from the start

That's what Python does too. But the variable assignment above is not in a
function, so it's executed immediately like any other statement.

> because I can't do that - the interpreter whines about undefined calls
> when things are defined further down the page.

It whines if they're used before they're defined. It's perfectly fine to have
them, undefined and all, as long as they aren't used.

> In my example though - I
> want to use variables from one code block in another, but whichever one
> is first, something is undefined.  I'm not necessarily looking for a
> fix, but pointers as to technique to avoid this would be appreciated.
> Thanks.

I can think of several possibilities:

1. assign a value to your variable before using it in the class definition. You
can do this by putting the assignment code above the class definition or putting
the assignment code in a separate module and importing it at the top of the
module which defines the class.

2. assign the attribute to the class only once its value is known:

>>> class tst:
...     var = None
...
>>> myvar = 5
>>> tst.var = myvar
>>> inst = tst()
>>> inst.var
5

3. Make it an attribute of the instance rather than of the class:

>>> class tst2:
...     def __init__(self):
...         self.var = newvar
...         print 'tst2.__init__ executed'
...
>>> tst2()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in __init__
NameError: global name 'newvar' is not defined
>>> newvar = 57
>>> tst2().var
tst2.__init__ executed
57

It would be better to pass the extra argument as function parameter to __init__,
but anyway.

4. Generate the class after the value of the variable is known:

>>> def generateclass():
...     class test4:
...         var = newervar
...     return test4
...
>>> test = generateclass()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 2, in generateclass
  File "<stdin>", line 3, in test4
NameError: name 'newervar' is not defined
>>> newervar = 100
>>> test = generateclass()
>>> instance = test()
>>> instance.var
100

5. Use a class method instead of an attribute:

>>> class test5:
...     @classmethod
...     def var(cls):
...         return dummy
...
>>> test5.var()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 4, in var
NameError: global name 'dummy' is not defined
>>> dummy = 234
>>> test5.var()
234
>>> test5().var()
234

Which soultion is right, depends on your needs. I'm tempted to say (3) is the
best one, unless you really need that to be a class attribute. 

Tip: http://zephyrfalcon.org/labs/python_pitfalls.html

Yours,

Andrei




More information about the Tutor mailing list