git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

What's the difference between running a script under command box and interpreter?


On 31Oct2019 20:44, Jach Fong <jfong at ms4.hinet.net> wrote:
>The script test.py is something like this:
>-------test.py
>from pyeds import fsm
>...
>...
>class Rule_Parse:
>    def __init__(self):
>        ...
>        self.current_char = ''
>...
>...
>def main(input_str):
>    for c in input_str:
>        ...
>        rule.current_char = c
>        ...
>
>if __name__ == '__main__':
>    input_str = '(NNS(acoustics) & RB(not)) | JJ(muted)'
>    rule = Rule_Parse()
>    main(input_str)
>    ...
>
>-----------
>The test.py can run correctly under command box:
>D:\Works\Python\pyeds-master\src>py test.py
>
>but fails when running under interpreter:
>D:\Works\Python\pyeds-master\src>py
>Python 3.4.4 (v3.4.4:737efcadf5a6, Dec 20 2015, 19:28:18) [MSC v.1600 32 bit (Intel)] on win32
>Type "help", "copyright", "credits" or "license" for more information.
>>>> from test import *
>>>> input_str = "(NNS(acoustics) & RB(not)) | JJ(muted)"
>>>> rule = Rule_Parse()
>>>> main(input_str)
>Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
>  File "D:\Works\Python\pyeds-master\src\test.py", line 229, in main
>    rule.current_char = c
>NameError: name 'rule' is not defined
>>>>
>
>I did check the globals using dir() and the 'rule' is there, no doubt.

It matters how you checked this. This isn't apparent.

>I also tried "py -m pdb test.py" and step through it, no problem too.

This:
  py test.py
and this:
  py -m pdb test

both run test.py with __name__ set to "__main__" to indicate that 
test.py is the main programme.

When you "import test", the module's __name__ is from the import 
("test") i.e. not the main programme.

The bottom of your module has an if statement whose body only runs when 
this is the main programme.

The core issue is that the global "rule" is _only_ defined inside that 
if statement.

You might set it unconditionally to None at the start of the file, but 
that would only change the failure mode.

You might set it unconditionally to Rule_Parse() at the top of the file 
but that pointlessly instantiates an instance of Rule_Parse which might 
never be needed (maybe that is cheap, but many other classes are not).  
The basic intent of an import is to define various classes and other 
names, but _not_, generally, to create class instances and do 
significant work.

This is really an example illustrating one reason why global variables 
are considered things to avoid almost all of the time. Had main() 
required "rule" as a parameter then it would not have been possible to 
call it without at least providing a rule. The same applies with most 
other functions: if they all require their external state via parameters 
then you can't miss things out. (You can, of course, always pass 
incorrect values, but that is usually easier to debug.)

Avoid globals; they are usually a source of bugs.

Cheers,
Cameron Simpson <cs at cskk.id.au>