
Hello, This is a proposal and opinion I have thought at sending for a long time already, but did not because it is not exactly proper to Python (there are a few more of this category ;-). What decided me is the thread about the idiom "if __name__ == '__main__':", which had much success! Below a short summary or my views, followed by a longer series of comments. Summary: There should be 3 top-level functions predefined by the language: * 'start' : start func for a module run as an app (or 'main') * 'test' : main func of a module's test suite * 'init' : module init code, rather when imported In my view, all 3 correspond to clearly definite & distinct functionalities. Each of them provides clarity and all together permit getting rid of "lost code" roaming around at the top-level of modules; which I dislike, even for scripts; however, the proposal does not force anyone to follow such a style. Every module using such functions is then a set of definitions: assignments, def's, classes, plus imports and such. Possibly 1, 2, 3 of them are language-defined main functions. Very clean... The execution logics would be: * if imported module: ~ run init if any ~ else, run nothing * if executed module: ~ run test, if any (see below) ~ else, run start, if any ~ else, run nothing (error?) What do you think? === why start? === It looks nice to have hello world reduced to: print("Hello, world!") However, this is a very superficial nicety. I prefere the (very big!) complication of: def start(): print("Hello, world!") This code is self-understanding even for a novice programmer and nicely introduces some structural feature of the language. [0] This function 'start' would have an optional argument for command-line args; it may indeed also return an exit code. About the name 'start', well, it's a question of meaning; and to avoid confusion I'd rather reserved 'main' for a package's main module. Also, every of these 3 funcs is a 'main' one, depending on the actual case. But I would *not* fight on this point, call it 'main' if you like. (In assembly, it's commonly start as well: both ends of the expressivity scale meet here ;-). When compiling with start, in standard the language may also automagically strip out development or control instructions, like assertions. (There also may be a differenciated debug print command... but that's another point. Also different error messages for end-users.) === why test? === If you practice testing (by code), you know why. Nearly all of my modules end up ending with: # === t e s t ======================= def test_abc (): ... def test_def (): ... def test_ghi (): ... ... def test (): test_abc() test_def() test_ghi() ... if __name__ == '__main__': test() Then, I comment out the last 2 lines when all runs fine; or else, if it's the main module of an app, I replace it with a call to start. This is a second form or running a module as a stand-alone prog (from the command-line). Actually, I guess, anyone practicing a minimum of testing may so-to-say press the 'test' button constantly, far more often than we lauch an app in usage or trial mode (if ever it's an app). We switch to normal usage execution once only per development phase, when all is fine and we prepare a user release. This is why, in standard, when both exist, 'test' has precedence over 'start'. There may be a builtin config var (eg __main__) to set (eg __main__ = start), or any other to switch to start (but preferably from code, see also [1]). This function 'test' _may_ have an optional argument for command-line args; it may also return an exit code, here meaning test success / failure (why not number of failures?). Args may be handy to drive testing differently: exact funcs to run, form of output, depth of testing..., in a purely user-defined way (no language-defined meaning, else we'd never stop arguing on the topic; a typical bikeshed issue). [1] === why init? === There is much less use, in my personal practice, for such an init function typically run when a module is imported. (I know it from the D language.) But I guess whenever we need it, having it is very nice. I simulate it (1) to init program elements from external data (2) to import, scan, process, big data files like unicode tables, avoiding huge code-data files and/or security issues (3) for a usage similar to compile-time computations in static langs that provide that. Anyway, it is a clearly defined functionality, just like start & test. === flexibility === An init func may be run by test or start, conditionnally or not. A test func may be run by init or start; maybe self-testing just once on first launch of a just-installed app or package. === alternative === Apart from clarity and practicality (see below), such flexibility is also why I prefere such predefined function names to a proposal by Steven D'Aprano, on the mentionned thread, of builtin conditionals like: if __main__: ... if is_main(): ... if is_main: ... We could however trivially extend this proposal with eg is_tested & is_imported builtin conditionals. Why not chose the direct simplicity of builtin func names, though? This is a common Python usage (it would also introduce novices to this idea of special func names, then they are ready for "magic methods"). Another issue is practicle: writing or not such a function, or chosing between test and start, is something we control from code itself. To launch tests for instance, there is thus no need to run a module with a special command-line option, or to modify it in our favorite programming editor's settings, or to change environment variables or python config files... all pretty annoying things to do (and I never remember which is to be done, where, how exactly...). Instead, predefined conditionnals depend on such settings or data external to the code. [2] === why simple names? === Again, I would not fight for simple names; it may well in fact be preferable to have weird names with underscores. In my view, the need in python for names like __all__ or __str__ is due to the fact that there is no difference in the language between defining and redefining a symbol. If Python used eg ':=' to redefine symbols, then: foo = ... # error, symbol 'foo' already exists foo := ... # ok, intentional redefinition of builtin 'foo' Waiting for this, it may indeed be preferable to have weird names. === trial mode === There is one mode not covered by this: what I call trial, as opposed to in-code tests. This corresponds more or less to a beta-version: a simulation of normal usage by developpers or (power-)users, to further find bugs or more generally control the software as is. I don't know of cases where this would require a special dedicated main func: this is rather opposite to the idea of checking the program really as is. But there may be code parts interpreted differently or conditionnally compiled, differently from the case of an actual user release: assertions, debug prints, stats, benchmarking, profiling... all kinds of "meta-programming" issues. === all together === ''' d o c ''' import foo __all__ = ... code... code... code... def test_abc (): ... def test_def (): ... def test_ghi (): ... ... def test (): test_abc() test_def() test_ghi() ... def init (): ... # __main__ = start def start (args): init() # process args ... What do you think? (bis) Denis [0] Python may lack such higher-level code structure, more generally; this is an open question. [1] This feature is for command-line args fans, but I prefere to control testing from code itself. For information, I have 2 std test config params, which I define in code; whether to: * write successful checks also, for comparison * continue on check failures, or else stop (They affect a custom check func, similar to an assert, used for testing only.) Turning them to off transforms a module's diagnosis test suite into (part of) a regression test suite. [2] More generally, I want to control all what concerns code and its development from code itself. Command-line args and such (better command-line args only) are good only for very special needs like producing doc, a parse-tree, compile-only, profiling, etc. I definitely dislike languages that force people to constantly change the command line to compile/run or worse change env vars or edit config files (and I don't even evoque makefiles and such...).

The fundamental problem with this idea (outside of backwards compatibility issues) is that requiring people to write functions completely misses the core reason that scripting languages are easier to learn than those with a declarative compile time syntax: it's far easier to use a function than it is to define one. More on that topic: http://www.curiousefficiency.org/posts/2011/08/scripting-languages-and-suita... Aside from a couple of hints to the tokenizer and compiler in the file header, Python has no declarative mode - this is a feature, not a bug. Cheers, Nick.

On Dec 1, 2013, at 4:45, spir <denis.spir@gmail.com> wrote:
I assume you realize that function and class definitions, assignments, etc. are code, and there is no separate execution phase for defining code vs. running code in Python. So, are you proposing that top-level code only be allowed to run some subset of the language, or that it just be encouraged to do so as a convention? Meanwhile, your proposal to make hello world a two-liner instead of a one-liner may not seem that big a deal, but it means that every novice has to learn how to define functions before they can write their first program. And it means that everyone who wants to use Python as an admin/scripting language in place of perl or awk or whatever has to write that extra line of code, making Python less usable. And so on. And meanwhile, in realistic large programs, you're already going to define and call the function anyway, so you're only saving the call. I don't think saving 1 line in 100-line scripts is worth adding 1 line to 1-line scripts.

On 12/01/2013 02:49 PM, Andrew Barnert wrote:
Well, from the initial post: "however, the proposal does not force anyone to follow such a style" Nothing prevents you to write hello-world the usual way. Nothing prevents using Python as a calculator, neither, nore as a programmer-friendly Bash; however, for the latter case, i'd still use 'test' and 'start'. Instead, it is a structural addition to the language; a backward compatible one if ever special names, like '__test__', are used rather than my preferred ones, like 'test'. The last point of your post (saving a func call) has nothing to do with the proposal or its spirit. It is about code clarity and high-level structuration, replacing "if __name=='__main__'", allowing code flow logics to be all cleanly placed in funcs, such things... (did you reply too fast, maybe?) denis

spir, If you are serious about your idea I would recommend that you try to build a library that implements your convention. It's a clear that you have put a lot of thought in your proposal. It is not so clear that it will be an improvement. It is also not so clear that there won't be implementation roadblocks. However, it *is* clear that most people do not think it is worth the effort. You can be sure that the effort would be significant -- not just in coding it up, but in documentation, education, getting people to adopt it, and so on. So, since this is open source, if you really, truly believe in your idea, build it. You will definitely learn something. You may end up rejecting your own idea. Or you may find a better way. Or you may pave the road for adoption. There is only one way to find out. -- --Guido van Rossum (python.org/~guido)

On 12/01/2013 06:45 AM, spir wrote:
I think you are describing good programming practices for larger modules. And I think most people who have been programming in python for any length of time develop some form of what you are describing. The only difference is that they wouldn't need the conditional logic at the bottom of the module. But that also serves as bit of self documentation as to what the module or script does, is more flexible, and only adds a line or two if the rest is put into functions or classes. As for the testing case... I'd like for python to have a -t option that only sets a global name __test__ to True. Then that covers most of your use cases without adding a whole lot. Sometimes less is more. if __test__: test() elif __name__ == '__main__': main() That's just one possible combination of using __test__ and __name__. Cheers, Ron

On 2 Dec 2013 06:34, "Ron Adam" <ron3200@gmail.com> wrote:
And I think most people who have been programming in python for any length of time develop some form of what you are describing.
The only difference is that they wouldn't need the conditional logic at
the bottom of the module. But that also serves as bit of self documentation as to what the module or script does, is more flexible, and only adds a line or two if the rest is put into functions or classes.
As for the testing case... I'd like for python to have a -t option that
only sets a global name __test__ to True. Then that covers most of your use cases without adding a whole lot. Sometimes less is more.
Oh, interesting. Such an option could also alter -O and -OO to keep assert statements. I'd love to see that idea elaborated further, as there are a variety of questions around how it might work in practice (Compile time constant like __debug__? Always False builtin shadowed in the main module? If it works like __debug__ and/or affects -O and -OO, does it need a new naming convention in the pycache directory?) Cheers, Nick.

On Sun, Dec 1, 2013 at 1:13 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I like this idea but the specific proposal means __test__ needs to be defined in all modules. A simple alternative: if __name__ == '__test__': --- Bruce SALE! My brother's puzzle company Puzzazz <http://www.puzzazz.com> is having a BlackFriday/CyberMonday sale http://j.mp/182R4kG - FREE puzzle books and BOGO

On 12/01/2013 03:13 PM, Nick Coghlan wrote:
You could use the __test__ flag as the key to remove asserts rather than -O, -OO, and __debug__. Is that what you are thinking? If so, I think it would be equivalent to this. assert (invariant_condition) if __test__ else 1, fail_message
Isn't __debug__ set at Python's compile time, not module compile time? I think that makes __debug__ good for testing C extensions and python's own C code, but it's too static to be very useful in python modules. Always False builtin shadowed in the main module? That would limit the __test__ check to the __main__ module. I'd like to be able to have that check available anywhere. For example if I wanted to insert some print functions and use the __test__ flag to turn them on when I need to see them... if __test__: print(this) print(that) The idea could go one step further and allow a value to be passed with the -t flag. Then you could select tests based on that value.
I don't think it should effect -O or -OO in any significant way. And -O or -OO shouldn't effect __test__ either. I think the easiest way to implement it is to just to have __test__ set in the modules attributes at load/import time. If it's always to be available, then why not? I consider testing an imortant part of any program, so having __test__ in a module doesn't seem out of place to me. If anything... maybe if it's there... it's more likely to be used. ;-) I also like how easy it is to access. For many small scripts, including an argument parser is more work than I want to do, but including a few small tests to call if "__test__ == True" is perfect for those cases. if __test__: import doctest doctest.testmod() elif __name__ == '__main__': main() And I think it makes using __name__ here seem more natIt may also work as a name in the sys module. sys.__test__, but I prefer the simpler spelling of just __test__ because it looks nicer and allows for setting __test__ at the top of a module.ural. Ok, maybe that one is just me. It just seems, to me, some of the oddness comes from always seeing it spelled *exactly the same everywhere*. So the "if __name__ == '__main__':" line just begs for being reduced to something more minimal. Of course that does not mean it should be changes just that we will consider doing that to anything that stands out as being duplicated a lot. It's just what good programmers do. ;-) Cheers, Ron

On 12/01/2013 06:55 PM, Ron Adam wrote:
Hmmm... still have that annoying bug of having stuff I cut pasted back in at random places in Thunderbird. That should have read... "And I think it makes using __name__ here seem more natural." The part that was pasted in was a paragraph I deleted considering using sys.__test__, but I decided it wasn't really needed. Cheers, Ron

On 12/01/2013 04:55 PM, Ron Adam wrote:
Isn't __debug__ set at Python's compile time, not module compile time?
No. __debug__ is true when Python [1] is started normally, and False when started with -O or -OO. -- ~Ethan~ [1] Cpython to be specific; and there may be other flags that affect __debug__.

On 12/01/2013 09:32 PM, Ron Adam wrote:
That is all right, in my view; except maybe the point on flexibility (the solution of std func names is highly flexible). However, this does not address 2 related issues: * Why has the idiom "(el)if __name__ == '__main__':" has to be that obscure? and involve unnecessary knwoledge of Python arcanes (for a newcomer) * Having a std (albeit not required) high-level software structure is a net gain for the community of Python programmers (instead of everyone doing their own way... when they do). Denis

On Mon, Dec 02, 2013 at 01:35:31PM +0100, spir wrote:
It seems to me that having to know the string "if __name__ == '__main__'" is about the same level of arcana as knowing the name of a magic function that does the same.
"if __name__ == '__main__'" is, by necessity, standard across all Python programs. And if I want to run the tests for a project, I would expect './setup.py test' to run them for me. If a project has more than one entry point, how would I know which one to run to get the tests to work? Or would they all have to implement the test function identically? Dan

On 12/02/2013 06:35 AM, spir wrote:
I don't see it as obscure or arcane to compare a string to variable which bound to a string. It's a very common and basic operation. The only extra knowledge you need is to know that the __name__ attribute is set to "__main__" in the main module. And that enables us to check if "this" is the main module in a direct way.
The difference between python and compiled languages that must use functions to get things started, is that python is already executing the code, so it a matter of avoiding some parts at different times.
Most beginner books on python explain objects and name binding fairly early. Knowing a module is also an object and has a __name__ attribute is something a python programmer should learn very early. It helps them learn and understand how everything works in a more direct way. So rather than adding ... "You been doing this for a while, but many people do this other way ... ". So it would need to be explained anyway. Cheers, Ron

If somebody wants this type of behavior it is easy enough to put in the `if __name__ == "__main__"` section. I do not see that adding it to the language buys us anything. -- ~Ethan~

On 12/1/2013 7:45 AM, spir wrote:
The style above is obsolete. The older test.regrtest module (private, intended for CPython test suite only) required a test_main function in which one collected together the test classes, etc, but one might forget something. The newer unittest module does the test discovery for us, so no master test function is needed. Just put unittest.main() at the bottom instead of test(). Much easier. -- Terry Jan Reedy

1) I'd make "main" a keyword, used to denote the program start point, and let the interpreter bail-out if it encounters more than one "main" section. Yes that keyword would only be used for that one, simple purpose, but it *is* a special purpose. This would also solve the circular import issues, because now you have a well-defined *root* in which to construct a graph and check for cycles. 2) I think testing should also be more "built-into" the interpreter environment. I like the idea of a python "-t" flag or something which makes it runs doctests. In which case, I'd also what a test() built-in, so that I can use it *within* the interpreter environment also, making sure invariants are preserved when modifying and re-using code. 3) with a "main" keyword, this wouldn't be absolutely necessary. You'll know where your top-level scope is. -- MarkJ Tacoma, Washington

On Dec 1, 2013, at 17:19, Mark Janssen <dreamingforward@gmail.com> wrote:
How does that solve circular import issues? There's already a well-defined root, __main__, today. And if there's a cycle, it's a cycle whether it involves the root or not. And if you're talking about moving imports into a function instead of at the top level, people already do that today, and it wouldn't work any better.

On 2 Dec 2013 21:37, "spir" <denis.spir@gmail.com> wrote:
inter-module side: a module's 'test' or 'start' (I think in particular at regression test suites, with a std 'test' name for unit tests). That's already covered by unittest test discovery. Higher level structure beyond the individual module is more the province of distutils-sig than it is python-ideas or python-dev. Cheers, Nick.

Hello, Below is a minimal simulation of the proposal's core principal. Using my best knowledge of Python to have things light for the client, the necessity for it to make use of globals() and sys (see below, end of mod.py) nevertheless removes much of the proposal's nicety. Anyway. It establishes the control logic as expressed in the proposal: * if imported module: ~ run 'init' if any ~ else, run nothing * if executed module: ~ run 'test', if any (see below) ~ else, run 'start', if any ~ else, run nothing (error?) If both test & start exist, start is run if the magic var __run_fn__ == start. The implementation also forwards command-line args to either test or start. Below code: * I called the control logic module 'top_fn', with a func of same name. * To test it, a module 'mod'. * To test the case of import, a module 'main'. Try it by: * running mod as is (with some command-line args): should run test * running mod after uncommenting __run_fun__: should run start * running main, importing mod: should run init Non-nice aspects: * The obligation to include in client module: import sys from topfn import topfn topfn(globals(), sys.argv) This should be compiler magic, certainly (eg make C main be the right func). * No further possible compiler magic about differential compilation or such (see original proposal). To be clear, the most important feature of the proposal is to establish standard magic names for high-level software structure, which are correctly taken into account by the language (read: compiler, probably). If this feature exists, it will be used, then recommanded. Thank you, Denis ============================================================================== # topfn.py from types import FunctionType def topfn(env, argv): ''' Control which top function is executed in importing module. ''' # relevant vars: name = env["__name__"] # know if module was run as app init = env.get("init", None) # init func test = env.get("test", None) # test func start = env.get("start", None) # start func for app run run_fn = env.get("__run_fn__", None) # choice between test & start # control logic: if name == "__main__": if isinstance(start, FunctionType) and run_fn == start: start(argv) elif isinstance(test, FunctionType): test(argv) elif isinstance(init, FunctionType): init() ============================================================================== # mod.py print("in mod") def init (): print("Executing init.") def test1 (): print("Executing test1.") def test2 (): print("Executing test1.") def test3 (): print("Executing test1.") def test (argv): print("Executing test with argv: %s." % argv) test1() test2() test3() def start (argv): print("Executing start with argv: %s." % argv) #~ __run_fn__ = start import sys from topfn import topfn topfn(globals(), sys.argv) ============================================================================== # main.py print("in main") import mod

The fundamental problem with this idea (outside of backwards compatibility issues) is that requiring people to write functions completely misses the core reason that scripting languages are easier to learn than those with a declarative compile time syntax: it's far easier to use a function than it is to define one. More on that topic: http://www.curiousefficiency.org/posts/2011/08/scripting-languages-and-suita... Aside from a couple of hints to the tokenizer and compiler in the file header, Python has no declarative mode - this is a feature, not a bug. Cheers, Nick.

On Dec 1, 2013, at 4:45, spir <denis.spir@gmail.com> wrote:
I assume you realize that function and class definitions, assignments, etc. are code, and there is no separate execution phase for defining code vs. running code in Python. So, are you proposing that top-level code only be allowed to run some subset of the language, or that it just be encouraged to do so as a convention? Meanwhile, your proposal to make hello world a two-liner instead of a one-liner may not seem that big a deal, but it means that every novice has to learn how to define functions before they can write their first program. And it means that everyone who wants to use Python as an admin/scripting language in place of perl or awk or whatever has to write that extra line of code, making Python less usable. And so on. And meanwhile, in realistic large programs, you're already going to define and call the function anyway, so you're only saving the call. I don't think saving 1 line in 100-line scripts is worth adding 1 line to 1-line scripts.

On 12/01/2013 02:49 PM, Andrew Barnert wrote:
Well, from the initial post: "however, the proposal does not force anyone to follow such a style" Nothing prevents you to write hello-world the usual way. Nothing prevents using Python as a calculator, neither, nore as a programmer-friendly Bash; however, for the latter case, i'd still use 'test' and 'start'. Instead, it is a structural addition to the language; a backward compatible one if ever special names, like '__test__', are used rather than my preferred ones, like 'test'. The last point of your post (saving a func call) has nothing to do with the proposal or its spirit. It is about code clarity and high-level structuration, replacing "if __name=='__main__'", allowing code flow logics to be all cleanly placed in funcs, such things... (did you reply too fast, maybe?) denis

spir, If you are serious about your idea I would recommend that you try to build a library that implements your convention. It's a clear that you have put a lot of thought in your proposal. It is not so clear that it will be an improvement. It is also not so clear that there won't be implementation roadblocks. However, it *is* clear that most people do not think it is worth the effort. You can be sure that the effort would be significant -- not just in coding it up, but in documentation, education, getting people to adopt it, and so on. So, since this is open source, if you really, truly believe in your idea, build it. You will definitely learn something. You may end up rejecting your own idea. Or you may find a better way. Or you may pave the road for adoption. There is only one way to find out. -- --Guido van Rossum (python.org/~guido)

On 12/01/2013 06:45 AM, spir wrote:
I think you are describing good programming practices for larger modules. And I think most people who have been programming in python for any length of time develop some form of what you are describing. The only difference is that they wouldn't need the conditional logic at the bottom of the module. But that also serves as bit of self documentation as to what the module or script does, is more flexible, and only adds a line or two if the rest is put into functions or classes. As for the testing case... I'd like for python to have a -t option that only sets a global name __test__ to True. Then that covers most of your use cases without adding a whole lot. Sometimes less is more. if __test__: test() elif __name__ == '__main__': main() That's just one possible combination of using __test__ and __name__. Cheers, Ron

On 2 Dec 2013 06:34, "Ron Adam" <ron3200@gmail.com> wrote:
And I think most people who have been programming in python for any length of time develop some form of what you are describing.
The only difference is that they wouldn't need the conditional logic at
the bottom of the module. But that also serves as bit of self documentation as to what the module or script does, is more flexible, and only adds a line or two if the rest is put into functions or classes.
As for the testing case... I'd like for python to have a -t option that
only sets a global name __test__ to True. Then that covers most of your use cases without adding a whole lot. Sometimes less is more.
Oh, interesting. Such an option could also alter -O and -OO to keep assert statements. I'd love to see that idea elaborated further, as there are a variety of questions around how it might work in practice (Compile time constant like __debug__? Always False builtin shadowed in the main module? If it works like __debug__ and/or affects -O and -OO, does it need a new naming convention in the pycache directory?) Cheers, Nick.

On Sun, Dec 1, 2013 at 1:13 PM, Nick Coghlan <ncoghlan@gmail.com> wrote:
I like this idea but the specific proposal means __test__ needs to be defined in all modules. A simple alternative: if __name__ == '__test__': --- Bruce SALE! My brother's puzzle company Puzzazz <http://www.puzzazz.com> is having a BlackFriday/CyberMonday sale http://j.mp/182R4kG - FREE puzzle books and BOGO

On 12/01/2013 03:13 PM, Nick Coghlan wrote:
You could use the __test__ flag as the key to remove asserts rather than -O, -OO, and __debug__. Is that what you are thinking? If so, I think it would be equivalent to this. assert (invariant_condition) if __test__ else 1, fail_message
Isn't __debug__ set at Python's compile time, not module compile time? I think that makes __debug__ good for testing C extensions and python's own C code, but it's too static to be very useful in python modules. Always False builtin shadowed in the main module? That would limit the __test__ check to the __main__ module. I'd like to be able to have that check available anywhere. For example if I wanted to insert some print functions and use the __test__ flag to turn them on when I need to see them... if __test__: print(this) print(that) The idea could go one step further and allow a value to be passed with the -t flag. Then you could select tests based on that value.
I don't think it should effect -O or -OO in any significant way. And -O or -OO shouldn't effect __test__ either. I think the easiest way to implement it is to just to have __test__ set in the modules attributes at load/import time. If it's always to be available, then why not? I consider testing an imortant part of any program, so having __test__ in a module doesn't seem out of place to me. If anything... maybe if it's there... it's more likely to be used. ;-) I also like how easy it is to access. For many small scripts, including an argument parser is more work than I want to do, but including a few small tests to call if "__test__ == True" is perfect for those cases. if __test__: import doctest doctest.testmod() elif __name__ == '__main__': main() And I think it makes using __name__ here seem more natIt may also work as a name in the sys module. sys.__test__, but I prefer the simpler spelling of just __test__ because it looks nicer and allows for setting __test__ at the top of a module.ural. Ok, maybe that one is just me. It just seems, to me, some of the oddness comes from always seeing it spelled *exactly the same everywhere*. So the "if __name__ == '__main__':" line just begs for being reduced to something more minimal. Of course that does not mean it should be changes just that we will consider doing that to anything that stands out as being duplicated a lot. It's just what good programmers do. ;-) Cheers, Ron

On 12/01/2013 06:55 PM, Ron Adam wrote:
Hmmm... still have that annoying bug of having stuff I cut pasted back in at random places in Thunderbird. That should have read... "And I think it makes using __name__ here seem more natural." The part that was pasted in was a paragraph I deleted considering using sys.__test__, but I decided it wasn't really needed. Cheers, Ron

On 12/01/2013 04:55 PM, Ron Adam wrote:
Isn't __debug__ set at Python's compile time, not module compile time?
No. __debug__ is true when Python [1] is started normally, and False when started with -O or -OO. -- ~Ethan~ [1] Cpython to be specific; and there may be other flags that affect __debug__.

On 12/01/2013 09:32 PM, Ron Adam wrote:
That is all right, in my view; except maybe the point on flexibility (the solution of std func names is highly flexible). However, this does not address 2 related issues: * Why has the idiom "(el)if __name__ == '__main__':" has to be that obscure? and involve unnecessary knwoledge of Python arcanes (for a newcomer) * Having a std (albeit not required) high-level software structure is a net gain for the community of Python programmers (instead of everyone doing their own way... when they do). Denis

On Mon, Dec 02, 2013 at 01:35:31PM +0100, spir wrote:
It seems to me that having to know the string "if __name__ == '__main__'" is about the same level of arcana as knowing the name of a magic function that does the same.
"if __name__ == '__main__'" is, by necessity, standard across all Python programs. And if I want to run the tests for a project, I would expect './setup.py test' to run them for me. If a project has more than one entry point, how would I know which one to run to get the tests to work? Or would they all have to implement the test function identically? Dan

On 12/02/2013 06:35 AM, spir wrote:
I don't see it as obscure or arcane to compare a string to variable which bound to a string. It's a very common and basic operation. The only extra knowledge you need is to know that the __name__ attribute is set to "__main__" in the main module. And that enables us to check if "this" is the main module in a direct way.
The difference between python and compiled languages that must use functions to get things started, is that python is already executing the code, so it a matter of avoiding some parts at different times.
Most beginner books on python explain objects and name binding fairly early. Knowing a module is also an object and has a __name__ attribute is something a python programmer should learn very early. It helps them learn and understand how everything works in a more direct way. So rather than adding ... "You been doing this for a while, but many people do this other way ... ". So it would need to be explained anyway. Cheers, Ron

If somebody wants this type of behavior it is easy enough to put in the `if __name__ == "__main__"` section. I do not see that adding it to the language buys us anything. -- ~Ethan~

On 12/1/2013 7:45 AM, spir wrote:
The style above is obsolete. The older test.regrtest module (private, intended for CPython test suite only) required a test_main function in which one collected together the test classes, etc, but one might forget something. The newer unittest module does the test discovery for us, so no master test function is needed. Just put unittest.main() at the bottom instead of test(). Much easier. -- Terry Jan Reedy

1) I'd make "main" a keyword, used to denote the program start point, and let the interpreter bail-out if it encounters more than one "main" section. Yes that keyword would only be used for that one, simple purpose, but it *is* a special purpose. This would also solve the circular import issues, because now you have a well-defined *root* in which to construct a graph and check for cycles. 2) I think testing should also be more "built-into" the interpreter environment. I like the idea of a python "-t" flag or something which makes it runs doctests. In which case, I'd also what a test() built-in, so that I can use it *within* the interpreter environment also, making sure invariants are preserved when modifying and re-using code. 3) with a "main" keyword, this wouldn't be absolutely necessary. You'll know where your top-level scope is. -- MarkJ Tacoma, Washington

On Dec 1, 2013, at 17:19, Mark Janssen <dreamingforward@gmail.com> wrote:
How does that solve circular import issues? There's already a well-defined root, __main__, today. And if there's a cycle, it's a cycle whether it involves the root or not. And if you're talking about moving imports into a function instead of at the top level, people already do that today, and it wouldn't work any better.

On 12/02/2013 02:19 AM, Mark Janssen wrote:
I guess that is close to my point of view, if I undertand yours correctly: there could be an minimal amount of high-level software structure, at least about different running modes (exec, test, import), built into the language. Denis

On 2 Dec 2013 21:37, "spir" <denis.spir@gmail.com> wrote:
inter-module side: a module's 'test' or 'start' (I think in particular at regression test suites, with a std 'test' name for unit tests). That's already covered by unittest test discovery. Higher level structure beyond the individual module is more the province of distutils-sig than it is python-ideas or python-dev. Cheers, Nick.

Hello, Below is a minimal simulation of the proposal's core principal. Using my best knowledge of Python to have things light for the client, the necessity for it to make use of globals() and sys (see below, end of mod.py) nevertheless removes much of the proposal's nicety. Anyway. It establishes the control logic as expressed in the proposal: * if imported module: ~ run 'init' if any ~ else, run nothing * if executed module: ~ run 'test', if any (see below) ~ else, run 'start', if any ~ else, run nothing (error?) If both test & start exist, start is run if the magic var __run_fn__ == start. The implementation also forwards command-line args to either test or start. Below code: * I called the control logic module 'top_fn', with a func of same name. * To test it, a module 'mod'. * To test the case of import, a module 'main'. Try it by: * running mod as is (with some command-line args): should run test * running mod after uncommenting __run_fun__: should run start * running main, importing mod: should run init Non-nice aspects: * The obligation to include in client module: import sys from topfn import topfn topfn(globals(), sys.argv) This should be compiler magic, certainly (eg make C main be the right func). * No further possible compiler magic about differential compilation or such (see original proposal). To be clear, the most important feature of the proposal is to establish standard magic names for high-level software structure, which are correctly taken into account by the language (read: compiler, probably). If this feature exists, it will be used, then recommanded. Thank you, Denis ============================================================================== # topfn.py from types import FunctionType def topfn(env, argv): ''' Control which top function is executed in importing module. ''' # relevant vars: name = env["__name__"] # know if module was run as app init = env.get("init", None) # init func test = env.get("test", None) # test func start = env.get("start", None) # start func for app run run_fn = env.get("__run_fn__", None) # choice between test & start # control logic: if name == "__main__": if isinstance(start, FunctionType) and run_fn == start: start(argv) elif isinstance(test, FunctionType): test(argv) elif isinstance(init, FunctionType): init() ============================================================================== # mod.py print("in mod") def init (): print("Executing init.") def test1 (): print("Executing test1.") def test2 (): print("Executing test1.") def test3 (): print("Executing test1.") def test (argv): print("Executing test with argv: %s." % argv) test1() test2() test3() def start (argv): print("Executing start with argv: %s." % argv) #~ __run_fn__ = start import sys from topfn import topfn topfn(globals(), sys.argv) ============================================================================== # main.py print("in main") import mod
participants (10)
-
Andrew Barnert
-
Bruce Leban
-
Daniel Watkins
-
Ethan Furman
-
Guido van Rossum
-
Mark Janssen
-
Nick Coghlan
-
Ron Adam
-
spir
-
Terry Reedy