@Steven D'Aprano <steve@pearwood.info> Yes my original post is somewhat pithy and has some harsh words for decorators. Like many I have some opinions about code. Don't take them too seriously if they disagree with your experience, but I do hold my opinions for reasons, and I will explain some of them, but I don't want to derail my first python ideas proposal that has gotten some semblance of a positive reception. So I will quickly explain my terse statements in a more professional manner. And I will note again, these are opinions. * Avoid global variables, they make state difficult to reason about. Plenty of opinions have been written about this. * Code runs faster when it's in a function then when it is in a global scope. I don't have the reference on hand, but I can get it if anyone's interested. Python is a scripting language, but it's used heavily in production, It's nice if the efficient way of doing something is natural, intuitive, and easy. It's true that it's just a two-line pattern, and not all simplifications of two line patterns make it into the python standard. But this is an extremely common two line pattern. One that's often written less efficiently than it could be. If you already wrote the if statement for name, a new programmer is not incentivized to write a separate main function and then call it, it would be simpler if there was some construct that just declared this is the main function, and then the code inside the function is executed. For giant single file scripts, that are just protected by an if name equals main, this could be a big performance improvement. Although I imagine in the average case it won't impact that much. But there may be some small benefit. The biggest benefit will be in the clarity of the code, the state will be easier to reason about because there will be less globals. My initial proposal could absolutely be implemented in pure Python, but I do think I like the idea of just having a special dunder main function. I am an experienced user who avoids decorators. They make it difficult to statically parse the code. They are useful, but when I was younger I did fall in the trap of abusing them. And I do think there is something to be said for statically parsable code. Having to guarantee that when you see a function definition, that that function definition won't change or be dynamically rewritten, can be nice. There's value in dynamic code, decorators are a good concept, and Python is better for them, but I do find it fun to take jabs at them from time to time. So yes I was being a bit sarcastic and part of the proposal, but I was serious when I proposed using that form of dunder main as a decorator. However now I do favor Python just checking that there is a dunder main function, and calling it. That would be in the spirit of dunder getattr, which imo is one of the best improvements Python has made. On Fri, Oct 1, 2021, 9:01 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Fri, Oct 01, 2021 at 03:35:26PM -0400, Jonathan Crall wrote:
My motivation for writing this suggestion is in an attempt to stop a common anti-pattern, where instead of defining a `main` function (or a function by any other name) an simply calling that by adding the above two lines, a lot of Python users I work with will just start dumping their logic into the global scope of the module.
Needless to say, this can have consequences.
What sort of consequences are you thinking of, under what circumstances?
Remember, Python is first and foremost a scripting language. There's nothing wrong with writing scripts that run in the global scope.
If there was some default builtin, let's call it `__main__` for now (open to suggestions), that took a function as an argument and conditionally executed it if `__name__ == "__main__"` in the caller's scope, that would allow us to simplify the above boilerplate to a single line with no extra indentation:
``` def main(): ...
__main__(main) ```
You don't need `__main__` to be built into the interpreter. It's a two-line pattern: not every two line function needs to be a builtin.
``` def __main__(func): if __name__ == '__main__': func() ```
Put that in a module, then:
``` from module import __main__ ```
in all your scripts.
If you're worried about keystrokes, and your editor doesn't have a "snippets" functionality, you can put your `__main__` in your PYTHONSTARTUP file or sitecustomize.py and have it loaded automatically into builtins.
``` import builtins builtins.__main__ = __main__ ```
In addition to being simpler, it would allow users to avoid the trap of adding logic that impacts the global scope.
There is nothing necessarily wrong with logic that impacts the global scope in a script. It can be the easiest thing that works. The more complex your system, the more there is to go wrong.
Is your definition of simpler based on counting keystrokes? The underlying complexity is the same. Your builtin `__main__` performs exactly the same conditional test, it's just buried behind a function call.
Furthermore, it could be used as a decorator (and the use-case wouldn't be unreasonable!), and we all know how much new Python users love decorators when they find out about them.
Are you being sarcastic? The idiom "We all know how much X love Y" is typically (but not always) used sarcastically.
Decorator syntax has been a great success for Python, but even to this day newbies often struggle to understand them and even some experienced users avoid them.
My completely unscientific, pluck-a-figure-out-of-the-air guestimate is that about 10% of Python users treat decorators as a hammer and every problem they see as a nail, another 10% find them to be utterly perplexing and a source of dread, 20% know how to cut-and-paste a recipe involving decorators when needed, but don't know how they work (and have no interest in learning), and the rest have some reasonable level of understanding of how to use decorators and write their own.
In this particular case, using decorator syntax:
@__main__ def main(): ...
to call the function immediately, rather than the more straightforward
__main__(main)
seems to me to fall squarely in the "hammer + nail" category. I can't tell whether this is a serious proposal on your part or not.
Maybe having such a builtin would discourage globals and help new users get the use-decorators-everywhere bug out of their system.
There is no need to discourage globals for script writing. And I'm not entirely sure how it follows that encouraging people to use a decorator to run their script main function will discourage them from using decorators everywhere. What have I misunderstood?
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YSCULW... Code of Conduct: http://python.org/psf/codeofconduct/