Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

getting equal behavior for scripts and modules ?

3 views
Skip to first unread message

Stef Mientki

unread,
Oct 11, 2009, 1:50:31 PM10/11/09
to pytho...@python.org
hello,

I do agree that circular references should preferable be avoided.

In languages like Delphi, you get an error message, trying to use
circular references,
but solving them in large programs with a lot of history can be very
painful.

Now I finally (after 2 years) knowing there's a difference between
modules and scripts,
I want to guarantee that I always get the same functional behavior.

I found 2 solutions to realize the above.

=== solution 1 ===
Inserting a launcher into the IDE,
so instead of running the application as a script,
the file will always be executed as a module.
"""
== Launcher ==
instead of
if __name__ == '__main__' :
define a function
def main () :
and start this Launcher with the first parameter being the name of the
module
Launcher <module to be tested> <other arguments>
"""

import sys
__My_Main_Application = __import__ ( sys.argv[1] )

if 'main' in dir ( __My_Main_Application ) :
__My_Main_Application.main ()

=== solution 2 ===
Prevent execution of the code in this file if the file is ran as a script.
if __name__=='__main__':
import os, sys

# determine the name of myself
a = sys._getframe().f_code.co_filename
X = os.path.splitext ( os.path.split(a)[1] ) [0]

#import myself as 'ME'
ME = __import__ ( X )

# run some code in myself
ME.functional_code ()

# prevent that the code below is executed,
# ( for the second time )
# if this file is used as a script
sys.exit()

print 'One time import code'
def functional_code () :
print 'Functional Code'


any comment ?
thanks,
Stef Mientki

Gabriel Genellina

unread,
Oct 11, 2009, 2:44:36 PM10/11/09
to pytho...@python.org
En Sun, 11 Oct 2009 14:50:31 -0300, Stef Mientki <stef.m...@gmail.com>
escribiᅵ:

> I do agree that circular references should preferable be avoided.
>
> In languages like Delphi, you get an error message, trying to use
> circular references,
> but solving them in large programs with a lot of history can be very
> painful.
>
> Now I finally (after 2 years) knowing there's a difference between
> modules and scripts,
> I want to guarantee that I always get the same functional behavior.

In Delphi terms, you have units (.pas) and programs (.dpr). You can't add
a .dpr to the Uses clause of an unit. In case you have some code in a .dpr
that you want to use somewhere else, you move it into a new unit and Use
it from both places.

Translated to Python terms: you have modules and scripts. You shouldn't
import a script from a module. In case you have some code in a script that
you want to use somewhere else, move it into a new module and import it
from both places.

Note the change between "can't" and "shouldn't". Delphi just won't let you
import the main program from another place; Python does, with strange
effects, but you should not do that. You can avoid the temptation by
naming your scripts with another extension (or no extension at all).

> I found 2 solutions to realize the above.

> [...]

Too much hassle and magic for what should be a non-issue.

--
Gabriel Genellina

Stef Mientki

unread,
Oct 11, 2009, 4:40:31 PM10/11/09
to pytho...@python.org
Stephen Hansen wrote:
>
>
> On Sun, Oct 11, 2009 at 10:50 AM, Stef Mientki <stef.m...@gmail.com
> <mailto:stef.m...@gmail.com>> wrote:
> [...]
>
> In languages like Delphi, you get an error message, trying to use
> circular references,
> but solving them in large programs with a lot of history can be
> very painful.
>
> [...]

>
>
> === solution 1 ===
>
> Inserting a launcher into the IDE,
> so instead of running the application as a script,
> the file will always be executed as a module.
> """
>
> [...]
>
> Eh. If you must do it this way, just launch the program as 'python -c
> "import modulename; modulename.main()" <arguments>'. Then the __main__
> becomes that little string. The only "cost" then becomes "make sure
> there's a main function". That's pretty minimal isn't it? Sure you'll
> make changes to lots of different modules, but only once, and those
> changes are probably almost boilerplate and simple.
thanks for the tip, your suggestion works equally well,
but I guess it will be somewhat more complicated to implement that as a
general solution in an IDE.

>
> === solution 2 ===
> Prevent execution of the code in this file if the file is ran as a
> script.
>
>
> AHH RUN!
>
> RUN FOR YOUR LIFE :)
>
> Really.. at a certain point all these hacks to get Python to work in
> some weird-other-unpythony-way WILL come back and make your "large
> program with lots of history" descend into a pit of chaos and either
> rise up again and conquer the world in its evil ways, or, just decay
> and die under the weight of its own hacks :)
ok, I admit it's a little bit tricky, ...
... on the other hand,
I don't see any invalid python statement in the code
>
> [ I'm still slightly reeling, I admit, for the module you posted the
> other day which recursively added package directories to PYTHONPATH :) ]
Well that was / is a very rare case:
Design specifications:
- an general purpose builder / distributor / ...
- minimalistic input from the user
- all settings also available from a GUI

So the most minimalistic input I can think of is :

Exe_Files.append ( New_Program.py )

There is one simpeler line I can think of, namely :

New_Program

But as real life is somewhat more complicated, the last line isn't
discriminative enough.

In the final situation, given the above input, a distro should be build
(through py2exe + lots of exceptions due to standard libs ;-) ), an inno
setup installer should be created, the zip file should be uploaded and
an announcement should be made. So without having to build a parser
myself, the above code should be pure Python code.

So if there's a better way to implement that one line of code (or in
real life it might grow to 10 lines with user content) in a script
performing these tasks, please let me know.

thanks,
Stef

Stef Mientki

unread,
Oct 11, 2009, 5:07:30 PM10/11/09
to pytho...@python.org
Gabriel Genellina wrote:
> En Sun, 11 Oct 2009 14:50:31 -0300, Stef Mientki
> <stef.m...@gmail.com> escribiᅵ:
>
>> I do agree that circular references should preferable be avoided.
>>
>> In languages like Delphi, you get an error message, trying to use
>> circular references,
>> but solving them in large programs with a lot of history can be very
>> painful.
>>
>> Now I finally (after 2 years) knowing there's a difference between
>> modules and scripts,
>> I want to guarantee that I always get the same functional behavior.
>
> In Delphi terms, you have units (.pas) and programs (.dpr). You can't
> add a .dpr to the Uses clause of an unit. In case you have some code
> in a .dpr that you want to use somewhere else, you move it into a new
> unit and Use it from both places.
I never ever edited a dpr file, it's created fully automatically (don't
know what is in it) and I even think you don't need to use it at all.
In Delphi there's a "main unit" and other units, but it's up to the
programmer which unit is set as the "main unit".
Although I admit (because of the forbidden circular references) that's
not easy to use a unit designed as "main", and use as normal unit or
even better as a general purpose library.

>
> Translated to Python terms: you have modules and scripts. You
> shouldn't import a script from a module. In case you have some code in
> a script that you want to use somewhere else, move it into a new
> module and import it from both places.
>
> Note the change between "can't" and "shouldn't". Delphi just won't let
> you import the main program from another place;
well is does, notice Delphi has 2 locations for the uses clause !

> Python does, with strange effects, but you should not do that. You can
> avoid the temptation by naming your scripts with another extension (or
> no extension at all).
Going from Delphi to Python,
using a module (unit) both as standalone program and a library for other
programs,
was a beautiful relief.
Now finally I could play with software as if it was Lego ( those
children building blocks).
And indeed I've a few stand alone Python applications, that can fully be
embedded in other Python applications and docked in their GUI.

>
>> I found 2 solutions to realize the above.
>> [...]
>
> Too much hassle and magic for what should be a non-issue.
>
If you choose for a strict separation between "script" and "module", I
guess it's indeed a non-issue.
Using software as if it was Lego, needs either a detection or prevention
of effects of the difference between script and module.

thanks,
Stef


Steven D'Aprano

unread,
Oct 11, 2009, 6:06:46 PM10/11/09
to
On Sun, 11 Oct 2009 19:50:31 +0200, Stef Mientki wrote:

> Now I finally (after 2 years) knowing there's a difference between
> modules and scripts,
> I want to guarantee that I always get the same functional behavior.

You are confused. Scripts *are* modules. What makes a script a script is
that it is executed from the shell:

$ python ~/scripts/helloworld.py
Hello World.
$

The difference isn't between files which *are* scripts and files which
*are* modules, but between modules which do something useful when *run as
a script* versus modules which don't. Recent versions of Python even
include a switch -m that searches the sys.path for the named module and
runs the module's .py file as a script.

You don't get the same behaviour between *running* a module and
*importing* a module because they do different thing. When you say
"import module" inside the Python environment, the module goes through
the import machine. When you say "python script.py" in the shell, it
doesn't.

When you import a module, Python looks to see if it has already been
imported, and if it has, it returns the module object in the cache. If
not, then it does a whole lot of magic which includes executing the code
inside the module. This means that modules get executed only once in any
session (unless you remove it from the cache).

When you run a module as a script from the shell, it doesn't go through
the import machinery, it doesn't get looked up in the cache, and it gets
executed every time.

The consequence of this is that if you run a module as a script, it gets
executed. If, in the process of being executed, it imports itself
(directly or indirectly), the import machinery has to run it again. Hence
the module gets executed twice.


> I found 2 solutions to realize the above.

Over-engineered overly-complicated non-solution to a non-problem.

The simplest solution is as follows: code that must always be executed
goes in the body of the module. Code that *only* gets executed when
running as a script goes under a test:

if __name__ == '__main__':
# running as a script
# code goes here
pass

That code will *only* run when running as a script, and not when you
import the module. Everything outside such a test will always run. If you
don't want that distinction, then don't use such a test.

--
Steven

Gabriel Genellina

unread,
Oct 12, 2009, 7:01:12 PM10/12/09
to pytho...@python.org
En Sun, 11 Oct 2009 18:07:30 -0300, Stef Mientki <stef.m...@gmail.com>
escribiᅵ:
> Gabriel Genellina wrote:
>> En Sun, 11 Oct 2009 14:50:31 -0300, Stef Mientki
>> <stef.m...@gmail.com> escribiᅵ:
>>
>>> Now I finally (after 2 years) knowing there's a difference between
>>> modules and scripts,
>>> I want to guarantee that I always get the same functional behavior.
>>
>> In Delphi terms, you have units (.pas) and programs (.dpr). You can't
>> add a .dpr to the Uses clause of an unit. In case you have some code in
>> a .dpr that you want to use somewhere else, you move it into a new unit
>> and Use it from both places.
> I never ever edited a dpr file, it's created fully automatically (don't
> know what is in it) and I even think you don't need to use it at all.
> In Delphi there's a "main unit" and other units, but it's up to the
> programmer which unit is set as the "main unit".

The main unit is the program (the one that starts with the keyword
'program' instead of 'unit', and has no interface). But if you don't know
what a program is, explaining the analogy is pointless.

>> Too much hassle and magic for what should be a non-issue.
>>
> If you choose for a strict separation between "script" and "module", I
> guess it's indeed a non-issue.
> Using software as if it was Lego, needs either a detection or prevention
> of effects of the difference between script and module.

Just remember to put a guard like this:

if __name__ == '__main__':

around anything you don't want executed when the code is imported (as
opposed to being run as a script/program)

--
Gabriel Genellina

Gabriel Genellina

unread,
Oct 12, 2009, 7:01:12 PM10/12/09
to pytho...@python.org
0 new messages