Syntactic sugar
I often want to execute a chunk of code n times for iter in range(n): chunkofcode Sometimes, the chunk of code doesn't care about which iteration it's on. A week or two back, I would have sworn that I came across a syntax for the above that eliminates the iteration counter. This morning, I had use for that syntax, but couldn't find it on-line or guess what it was. Does this syntax exist, or am I simply imagining things? Thanks, -- Michael F. Stemper There's no "me" in "team". There's no "us" in "team", either. -- https://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar
On 28/06/2021 11.57, Stefan Ram wrote: "Michael F. Stemper" writes: for iter in range(n): chunkofcode When the counter does not matter, people sometimes write "_": for _ in range( n ): chunkofcode That looks like what I wanted. Thanks! -- Michael F. Stemper Indians scattered on dawn's highway bleeding; Ghosts crowd the young child's fragile eggshell mind. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 02Dec2014 02:17, Ethan Furman wrote: On 12/01/2014 05:15 PM, Chris Angelico wrote: On Tue, Dec 2, 2014 at 11:45 AM, Ethan Furman wrote: Put the above somewhere in your path (e.g. /usr/local/bin), make it executable, and then instead of shebanging your scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, which will load and execute the script, calling script.main as its last act. Be aware that this trick (shebanging to a script rather than a binary) isn't specified by the POSIX standard. It works on Linux, but I don't know about other systems. Ah, thanks for that! I'm pretty sure I've used systems where you could not shebang to a script. Solaris IIRC. Several years ago, might not be an issue on modern releases. Cheers, Cameron Simpson For reading rec.moto, I use one of those carbon-fiber Logitech mice w/a little 'No Fear' sticker on it. - Mike Hardcore DoD#5010 Apologies to Primus -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 12/01/2014 05:15 PM, Chris Angelico wrote: > On Tue, Dec 2, 2014 at 11:45 AM, Ethan Furman wrote: >> >> Put the above somewhere in your path (e.g. /usr/local/bin), make it >> executable, and then instead of shebanging your >> scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, >> which will load and execute the script, >> calling script.main as its last act. > > Be aware that this trick (shebanging to a script rather than a binary) > isn't specified by the POSIX standard. It works on Linux, but I don't > know about other systems. Ah, thanks for that! -- ~Ethan~ signature.asc Description: OpenPGP digital signature -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Tue, Dec 2, 2014 at 11:45 AM, Ethan Furman wrote: > Put the above somewhere in your path (e.g. /usr/local/bin), make it > executable, and then instead of shebanging your > scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, > which will load and execute the script, > calling script.main as its last act. Be aware that this trick (shebanging to a script rather than a binary) isn't specified by the POSIX standard. It works on Linux, but I don't know about other systems. It's a great trick, though. I once had shebangs chained something like three or four levels deep. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 12/01/2014 03:19 PM, Ethan Furman wrote: > > Well, I've tried this out, and it's only okay. As soon as interesting things > start happening, spurious errors about > thread IDs start printing, which really messes up the user experience [...] So here's another thought: Have a small python script that loads and runs the actual script -- here's a POC: --- 8< py_main -- #!/usr/bin/env python import sys sys.argv.pop(0) try: execfile except NameError: def execfile(file_name, globals): with open(file_name) as fh: script = fh.read() exec(fh, globals) module = {} execfile(sys.argv[0], module) module['main']() - Put the above somewhere in your path (e.g. /usr/local/bin), make it executable, and then instead of shebanging your scripts with `/usr/local/bin/python` you can use `/usr/local/bin/py_main`, which will load and execute the script, calling script.main as its last act. -- ~Ethan~ signature.asc Description: OpenPGP digital signature -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 11/13/2014 10:32 AM, Ethan Furman wrote: > On 11/12/2014 01:51 PM, Ian Kelly wrote: >> On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: >>> >>> A decorator is an interesting idea, and should be easy to implement (only >>> lightly tested): >>> >>> def main(func): >>> if func.__module__ == "__main__": >>> func() >>> return func # The return could be omitted to block the function from >>> being manually called after import. >> >> This calls it at the wrong time, though. [...] > > One decorator that won't call too early is atexit.register(). Well, I've tried this out, and it's only okay. As soon as interesting things start happening, spurious errors about thread IDs start printing, which really messes up the user experience [1]. [1] something like Exception KeyError: KeyError(139924387112272,) in ignored -- ~Ethan~ signature.asc Description: OpenPGP digital signature -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Sun, Nov 16, 2014 at 3:39 AM, Vito De Tullio wrote: > for the "right time" you can choose to spin a thread and wait to the end of > the load of the module Yuck. "Just add threads" is /not/ the answer to everything. This case looks fairly harmless on the surface, although I could imagine it breaking things that might object to the main thread being changed, e.g. things that use event loops or that rely in some way on the threading.main_thread() function. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
Ian Kelly wrote: >> def main(func): >> if func.__module__ == "__main__": >> func() >> return func # The return could be omitted to block the function from >> being manually called after import. >> >> Just decorate the "main" function of the script with that, and it will be >> automatically called when ran as a script, but not when imported as a >> module. > > This calls it at the wrong time, though. Typically the way this idiom > is used is that you define everything you need (functions, classes, > etc.) within the main script, and then you call the main function. > This would call the main function at the time it's defined, when other > things in the main script may not have been defined yet. One could > place the main function last, but it would be preferable not to be > forced. for the "right time" you can choose to spin a thread and wait to the end of the load of the module something like from threading import Thread, current_thread def run_func(func, module_thread): module_thread.join() func() def main(func): if func.__module__ == '__main__': Thread(target=run_func, args=[func, current_thread()]).start() return func -- By ZeD -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
Steven D'Aprano wrote: > Chris Kaynor wrote: > >> I was thinking along the lines of replacing: >> >> if __name__ == "__main__": >> <<>> >> >> with >> >> @main >> def myFunction() >> <<<> >> >> Both blocks of code will be called at the same time. > > > You can't guarantee that, because you cannot tell ahead of time when the > "if __name__" statement will be run. It is *usually* at the end of the > file, but that's just the normal useful convention, it is not a hard > requirement. sure you can: simply the main decorator is just something like def main(myMainFunction): if myMainFunction.__module__ == '__main__': myMainFunction() return myMainFunction -- By ZeD -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
Steven D'Aprano : > if __name__ == '__main__' or condition(): > print "still executing" > main() > > print "done loading" > > (I haven't ever done *all* of these things in a *single* file, but I > have done all these things at one time or another.) > > There's no way that any automatic system can match that for > flexibility or simplicity. Our test system has this boilerplate at the end of each test case: if __name__ == '__main__': run(test) Nobody claims it's beautiful but nobody has been overly bothered by it, either. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
Chris Kaynor wrote: > I was thinking along the lines of replacing: > > if __name__ == "__main__": > <<>> > > with > > @main > def myFunction() > <<<> > > Both blocks of code will be called at the same time. You can't guarantee that, because you cannot tell ahead of time when the "if __name__" statement will be run. It is *usually* at the end of the file, but that's just the normal useful convention, it is not a hard requirement. The current idiom uses normal, unmagical execution of Python code. When the interpreter reaches the "if __name__ ..." statement, it executes that statement, just like every other statement. There's no magic involved here, and in fact I have written code with *multiple* such "if __name__" blocks. Here's a sketch of the sort of thing I mean: import a import b if __name__ == '__main__': import c as d else: import d def this(): ... def that(): ... flag = __name__ == '__main__' process(flag) if __name__ == '__main__' or condition(): print "still executing" main() print "done loading" (I haven't ever done *all* of these things in a *single* file, but I have done all these things at one time or another.) There's no way that any automatic system can match that for flexibility or simplicity. -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
John Ladasky wrote: > I have taught Python to several students over the past few years. As I > have worked with my students, I find myself bothered by the programming > idiom that we use to determine whether a module is being executed or > merely imported: > > "if __name__ == '__main__':" > > The use of two dunder tokens -- one as a name in a namespace, and the > other as a string, is intimidating. It exposes too much of Python's guts. The dunders are a tad ugly, but it's actually quite simple and elegant: * every module has a global variable `__name__` which normally holds the name of the module: py> import functools py> functools.__name__ 'functools' py> import math as foobarbaz py> foobarbaz.__name__ 'math' * When Python imports a module, it sets the global __name__ to that module's actual name (as taken from the file name). * But when Python runs a file, as in `python2.7 path/to/script.py`, it sets the global __name__ to the magic value '__main__' instead of "script". The consequence is that every module can tell whether it is being run as a script or not by inspecting the __name__ global. That's all there is to it. -- Steven -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 1:53 PM, Skip Montanaro wrote: > On Thu, Nov 13, 2014 at 2:44 PM, Skip Montanaro > wrote: >> What's not documented is >> the behavior of calling atexit.register() while atexit._run_exitfuncs >> is running. That's an implementation detail, and though unlikely to >> change, it might be worthwhile getting that behavior documented. > > http://bugs.python.org/issue22867 In fact it seems the behavior does differ between Python 2.7 and Python 3.4: $ cat testatexit.py import atexit @atexit.register def main(): atexit.register(goodbye) @atexit.register def goodbye(): print("Goodbye") $ python2 testatexit.py Goodbye Goodbye $ python3 testatexit.py Goodbye -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 1:44 PM, Skip Montanaro wrote: > On Thu, Nov 13, 2014 at 2:33 PM, Ian Kelly wrote: >> ... other things decorated with atexit.register >> might actually be called before the main function > > I don't think that will happen. The atexit module is documented to > execute its exit functions in reverse order. Right, so if something else gets registered after the main function, it will be called before the main function. > What's not documented is > the behavior of calling atexit.register() while atexit._run_exitfuncs > is running. That's an implementation detail, and though unlikely to > change, it might be worthwhile getting that behavior documented. Since the exit functions are executed in reverse order, anything registered at this time would have to be called before something else that has already been called, so I would expect this to be an error condition. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 2:44 PM, Skip Montanaro wrote: > What's not documented is > the behavior of calling atexit.register() while atexit._run_exitfuncs > is running. That's an implementation detail, and though unlikely to > change, it might be worthwhile getting that behavior documented. http://bugs.python.org/issue22867 Skip -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 2:33 PM, Ian Kelly wrote: > ... other things decorated with atexit.register > might actually be called before the main function I don't think that will happen. The atexit module is documented to execute its exit functions in reverse order. What's not documented is the behavior of calling atexit.register() while atexit._run_exitfuncs is running. That's an implementation detail, and though unlikely to change, it might be worthwhile getting that behavior documented. Skip -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 11/13/2014 12:33 PM, Ian Kelly wrote: > On Thu, Nov 13, 2014 at 11:32 AM, Ethan Furman wrote: >> On 11/12/2014 01:51 PM, Ian Kelly wrote: >>> >>> On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: A decorator is an interesting idea, and should be easy to implement (only lightly tested): def main(func): if func.__module__ == "__main__": func() return func # The return could be omitted to block the function from being manually called after import. >>> >>> This calls it at the wrong time, though. [...] >> >> One decorator that won't call too early is atexit.register(). > > Nice. That feels like an abuse, though. The actual program won't be able to > register its own atexit handlers, > because the program will already be exiting, and other things decorated with > atexit.register might actually be > called before the main function. It's definitely a niche use-case -- such as a cli-helper lib: import said lib, and when it's decorators are used set the atexit handler to call the lib's __main__ function, which checks that the module name of the decorated function is '__main__', and if it is, run stuff! Hmmm... hopefully that wasn't difficult to explain. ;) - -- ~Ethan~ -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAEBAgAGBQJUZRfjAAoJENZ7D1rrH75Nx4IP/3tuR4JhVK6Acv04+DiHm32H BHGmBRZGtXQrHGEBcv8BlvUiztmrHqjV+Lkm78zKF3n9R8Ta9qTeSjqIsjRWUMtR JVraCSH6usUwmcGITXIYKQHdXynl+ylu9p8Hr3NT2aNoICqowVGSvK3Ie1NmJuf3 lJcl8tXiXgUrGCwBwEgdrBKTdaATe4QT9XFQJx1QbXpF3qT1Za5hPYthY3fH/Pd9 Nl9NHyA6F5x4sSO7itD23UtUpnRBHWl7blwsKkBi7ClfacxJMrYjFAMUaxUaiTFF /bygveskmMAZw87ISLtjkmOcKtsi0i2BQSQEjpBDZTiveCD/wyDDhJ+5pmZKzll0 Q+pISt4jG9hkArd+JCCxPuTCCo2xm+cMIB4/oSeONd760u6vURLPUNZ5tmNsRkiZ o0/EwyRhWPZotiLoyi7kDNyfpj/BSKV0A6Ph+M40UXOkTZFUf0E84OFEpB359MTO rIvHDpd6Tzch2Dliuj6UKZ1OOygIZauv2ebmEBHHNDMdsVbhdtTElS1Rh2JtDVyZ tUd67KTmE9CwOPcFIbYKHXGIf4FWDAgeaz9x8RY4UUPaDRlyG1eqSxx8Vob2AG9c MEawmA48JCj52ZeICQf6nnIFdIowFkV7QssUgte3cVfbcMBYnPx/nuJWWMjULo77 WrIUpisDf/juvXn4VtuO =oczI -END PGP SIGNATURE- -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 11:32 AM, Ethan Furman wrote: > On 11/12/2014 01:51 PM, Ian Kelly wrote: >> >> On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: >>> >>> A decorator is an interesting idea, and should be easy to implement (only >>> lightly tested): >>> >>> def main(func): >>> if func.__module__ == "__main__": >>> func() >>> return func # The return could be omitted to block the function from >>> being manually called after import. >> >> This calls it at the wrong time, though. [...] > > One decorator that won't call too early is atexit.register(). Nice. That feels like an abuse, though. The actual program won't be able to register its own atexit handlers, because the program will already be exiting, and other things decorated with atexit.register might actually be called before the main function. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 11/12/2014 01:51 PM, Ian Kelly wrote: On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: A decorator is an interesting idea, and should be easy to implement (only lightly tested): def main(func): if func.__module__ == "__main__": func() return func # The return could be omitted to block the function from being manually called after import. This calls it at the wrong time, though. [...] One decorator that won't call too early is atexit.register(). -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Fri, Nov 14, 2014 at 12:33 AM, Roy Smith wrote: > ... you also get to not worry > about what order things are defined. That's only as regards the interpreter, though. My point has nothing to do with the order the interpreter sees things, it's all about how they're laid out for humans to read. For that, I prefer to have definitions before use. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
In article , Chris Angelico wrote: > On Thu, Nov 13, 2014 at 7:47 PM, Cameron Simpson wrote: > > My view is that if there's a main (i.e. the module implements a small app > > all on its own, however tiny), then the main program logic should come > > first. The details follow later. > > Ah, I see. Makes sense. It's kinda like an executable docstring. Still > not my preferred style, but makes its own sense. > > ChrisA I generally define a main() routine up near the top, then put if __name__ == '__main__': main() at the bottom. That gives you the best of both worlds; you get to see the main() code up front in the file, but you also get to not worry about what order things are defined. It also means you can import your module and call its main() directly. That's useful for testing, but occasionally for other purposes too. You can't do that with the (detestable) style of putting a whole bunch of code in the body of the "if" statement. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 7:47 PM, Cameron Simpson wrote: > My view is that if there's a main (i.e. the module implements a small app > all on its own, however tiny), then the main program logic should come > first. The details follow later. Ah, I see. Makes sense. It's kinda like an executable docstring. Still not my preferred style, but makes its own sense. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 13Nov2014 19:04, Chris Angelico wrote: On Thu, Nov 13, 2014 at 6:23 PM, Cameron Simpson wrote: Indeed. This aspect is a deal breaker for me; I'd never use it. I make a point of putting the module's main function right up the top, immediately after the imports and any "constants" (let's not dither over that term). I _want_ the main function to in the reader's face when they visit the module code. All the cogs come later. And lots of my modules have "main" functions. Terribly useful. Hmm, I go the other way. As much as possible, I prefer functions to call what's above them, not what's below them - so the main function would always be at the end of the file. [...] My view is that if there's a main (i.e. the module implements a small app all on its own, however tiny), then the main program logic should come first. The details follow later. For a pureply functional module (utility functions, classes built on them, etc) I tend to go your way. But the main, if there is one, comes first. The very top of the file should have comments/docstrings etc, then imports, then pure utility functions that don't call on anything else, then "guts" functions, and finally routines that are called externally but never internally (like main). That way, if you're wondering at what some name means, you go to the top of the file and find the first occurrence; that'll usually be its definition. Sounds effective. I probably prefer my code (main aside, again) organised the same way. Needless to say, I have a heap of modules that could do with a cleanup along these lines. Cheers, Cameron Simpson If you make people think they're thinking, they'll love you; but if you really make them think, they'll hate you. - Don Marquis -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 6:23 PM, Cameron Simpson wrote: > Indeed. This aspect is a deal breaker for me; I'd never use it. > > I make a point of putting the module's main function right up the top, > immediately after the imports and any "constants" (let's not dither over > that term). I _want_ the main function to in the reader's face when they > visit the module code. All the cogs come later. > > And lots of my modules have "main" functions. Terribly useful. Hmm, I go the other way. As much as possible, I prefer functions to call what's above them, not what's below them - so the main function would always be at the end of the file. The very top of the file should have comments/docstrings etc, then imports, then pure utility functions that don't call on anything else, then "guts" functions, and finally routines that are called externally but never internally (like main). That way, if you're wondering at what some name means, you go to the top of the file and find the first occurrence; that'll usually be its definition. Most people already do this with their imports, putting them all at the top - I like to go further and make it unusual for this not to be the case. (Of course, the nature of live projects and constant editing is that there will be violations of the principle, and I don't code-churn just to fix it. But that's still the ideal.) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 12Nov2014 14:51, Ian Kelly wrote: On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: A decorator is an interesting idea, and should be easy to implement (only lightly tested): [...] Just decorate the "main" function of the script with that, and it will be automatically called when ran as a script, but not when imported as a module. This calls it at the wrong time, though. [...] This would call the main function at the time it's defined, when other things in the main script may not have been defined yet. One could place the main function last, but it would be preferable not to be forced. Indeed. This aspect is a deal breaker for me; I'd never use it. I make a point of putting the module's main function right up the top, immediately after the imports and any "constants" (let's not dither over that term). I _want_ the main function to in the reader's face when they visit the module code. All the cogs come later. And lots of my modules have "main" functions. Terribly useful. Cheers, Cameron Simpson We're in the business of putting goo on a substrate. - overhead by WIRED at the Intelligent Printing conference Oct2006 -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 11:35 AM, Terry Reedy wrote: >> Safer - and more in line with the way >> other such functions are written - would be a dunder function: >> >> if __name__ == '__main__': __main__() > > > I presume you mean that calling __main__ implicitly would be both consistent > and safer. No code should be using that now. That's what I mean. Like changing iter.next() to iter.__next__() in Py3, it'd be using a name that emphasizes that the interpreter, not userland code, should be calling this function. Of course, it'd still be optional. Top-level code would be executed top-down, same as it now is. ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 11/12/2014 6:26 PM, Chris Angelico wrote: On Thu, Nov 13, 2014 at 10:19 AM, Terry Reedy wrote: Functions have an implicit 'return None' at the end (which, in CPython, become an explicit pair of bytecodes, even when the function already ends with return something'. The simplest proposal is that modules have an implicit "if __name__ == '__main__': main()" at the end. I think this would not have to be added to the bytecode. This magical invocation mimics C and some other languages, and I think it works well. Yes, but it conflicts with the existing and common usage of having that explicitly in the code. Yeh, calling main twice could be a problem. Safer - and more in line with the way other such functions are written - would be a dunder function: if __name__ == '__main__': __main__() I presume you mean that calling __main__ implicitly would be both consistent and safer. No code should be using that now. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Thu, Nov 13, 2014 at 10:19 AM, Terry Reedy wrote: > Functions have an implicit 'return None' at the end (which, in CPython, > become an explicit pair of bytecodes, even when the function already ends > with return something'. The simplest proposal is that modules have an > implicit "if __name__ == '__main__': main()" at the end. I think this would > not have to be added to the bytecode. > > This magical invocation mimics C and some other languages, and I think it > works well. Yes, but it conflicts with the existing and common usage of having that explicitly in the code. Safer - and more in line with the way other such functions are written - would be a dunder function: if __name__ == '__main__': __main__() ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 11/12/2014 4:02 PM, John Ladasky wrote: I have taught Python to several students over the past few years. As I have worked with my students, I find myself bothered by the programming idiom that we use to determine whether a module is being executed or merely imported: "if __name__ == '__main__':" The use of two dunder tokens -- one as a name in a namespace, and the other as a string, is intimidating. It exposes too much of Python's guts. As such, I think that it is less Pythonic than we might want. Myself, I've been programming in Python for a decade, and I still haven't dug very deeply into what exactly __name__ means or does. I would like to start a discussion about whether Python should include a function which executes this evaluation, and hides all of the unfriendly dunderish details. And if that's a good idea, I would invite a discussion of how, exactly, it should be implemented. I'm nowhere near proposing a PEP, but that may come later. Functions have an implicit 'return None' at the end (which, in CPython, become an explicit pair of bytecodes, even when the function already ends with return something'. The simplest proposal is that modules have an implicit "if __name__ == '__main__': main()" at the end. I think this would not have to be added to the bytecode. This magical invocation mimics C and some other languages, and I think it works well. -- Terry Jan Reedy -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Wed, Nov 12, 2014 at 3:09 PM, Chris Kaynor wrote: > I was thinking along the lines of replacing: > > if __name__ == "__main__": > <<>> > > with > > @main > def myFunction() > <<<> > > Both blocks of code will be called at the same time. 99% of the time the content of <<>> is just "main()", so then you're proposing replacing this: if __name__ == "__main__": main() with this: @main def myFunction(): my_main() Which feels redundant to me. Why have a function here that does nothing but call another function? I think if this is the goal then a simple predicate would be clearer: if is_main_module(): main() -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Wed, Nov 12, 2014 at 1:51 PM, Ian Kelly wrote: > On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor > wrote: > > A decorator is an interesting idea, and should be easy to implement (only > > lightly tested): > > > > def main(func): > > if func.__module__ == "__main__": > > func() > > return func # The return could be omitted to block the function from > > being manually called after import. > > > > Just decorate the "main" function of the script with that, and it will be > > automatically called when ran as a script, but not when imported as a > > module. > > This calls it at the wrong time, though. Typically the way this idiom > is used is that you define everything you need (functions, classes, > etc.) within the main script, and then you call the main function. > This would call the main function at the time it's defined, when other > things in the main script may not have been defined yet. One could > place the main function last, but it would be preferable not to be > forced. > > I was thinking along the lines of replacing: if __name__ == "__main__": <<>> with @main def myFunction() <<<> Both blocks of code will be called at the same time. > This also calls the function before it's been assigned to the global, > which would prevent recursive calls of the main function. > > Instead of a decorator, I'd prefer to just have this: > > def main(func, *args, **kwargs): > if func.__module__ == '__main__': > func(*args, **kwargs) > > And then I can easily invoke it wherever I want in the main script. > On Wed, Nov 12, 2014 at 1:55 PM, Skip Montanaro wrote: > > This won't work (I don't think) if you want to call the "main" function from another place (like the interpreter prompt). With the plain if block, you absolutely cannot call it elsewhere, without wrapping it in a function anyways. There is the issue, as mentioned by Ian, that the function will not be in the module namespace at the time it is called. That does block it, however it is also easy to work around: make the main function extremely simple, such as just calling another function. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
> def main(func): > if func.__module__ == "__main__": > func() > return func # The return could be omitted to block the function from > being manually called after import. > > Just decorate the "main" function of the script with that, and it will be > automatically called when ran as a script, but not when imported as a > module. This won't work (I don't think) if you want to call the "main" function from another place (like the interpreter prompt). Skip -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
John Ladasky : > I find myself bothered by the programming idiom that we use to > determine whether a module is being executed or merely imported: > > "if __name__ == '__main__':" I find the idiom cute and loveably silly. A typing tongue twister of sorts. That boilerplate is far less cumbersome than, say, in Java. > Myself, I've been programming in Python for a decade, and I still > haven't dug very deeply into what exactly __name__ means or does. The idiom allows you to include a main function in auxiliary modules. When imported, the module acts as a library. When executed, it acts as a command. I have done this a couple of times IRL. > I would like to start a discussion about whether Python should include > a function which executes this evaluation, and hides all of the > unfriendly dunderish details. Probably not. Idioms are important in that they are immediately spotted by a casual reader of the code. However ugly you consider those two lines, it will not waste a measurable amount of your precious time to begin your brand new project by typing: import sys def main(): pass if __name__ == "__main__": main() Yes, I always type those in again. I don't copy them over as I do, say, Java main programs or static HTML pages. Marko -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Wed, Nov 12, 2014 at 2:33 PM, Chris Kaynor wrote: > A decorator is an interesting idea, and should be easy to implement (only > lightly tested): > > def main(func): > if func.__module__ == "__main__": > func() > return func # The return could be omitted to block the function from > being manually called after import. > > Just decorate the "main" function of the script with that, and it will be > automatically called when ran as a script, but not when imported as a > module. This calls it at the wrong time, though. Typically the way this idiom is used is that you define everything you need (functions, classes, etc.) within the main script, and then you call the main function. This would call the main function at the time it's defined, when other things in the main script may not have been defined yet. One could place the main function last, but it would be preferable not to be forced. This also calls the function before it's been assigned to the global, which would prevent recursive calls of the main function. Instead of a decorator, I'd prefer to just have this: def main(func, *args, **kwargs): if func.__module__ == '__main__': func(*args, **kwargs) And then I can easily invoke it wherever I want in the main script. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Wed, Nov 12, 2014 at 1:07 PM, Joel Goldstick wrote: > On Wed, Nov 12, 2014 at 4:02 PM, John Ladasky > wrote: > > I have taught Python to several students over the past few years. As I > have worked with my students, I find myself bothered by the programming > idiom that we use to determine whether a module is being executed or merely > imported: > > > > "if __name__ == '__main__':" > > > > The use of two dunder tokens -- one as a name in a namespace, and the > other as a string, is intimidating. It exposes too much of Python's guts. > As such, I think that it is less Pythonic than we might want. Myself, I've > been programming in Python for a decade, and I still haven't dug very > deeply into what exactly __name__ means or does. > > > > I would like to start a discussion about whether Python should include a > function which executes this evaluation, and hides all of the unfriendly > dunderish details. And if that's a good idea, I would invite a discussion > of how, exactly, it should be implemented. I'm nowhere near proposing a > PEP, but that may come later. > > > > Thanks for your thoughts. > > How about a decorator? > A decorator is an interesting idea, and should be easy to implement (only lightly tested): def main(func): if func.__module__ == "__main__": func() return func # The return could be omitted to block the function from being manually called after import. Just decorate the "main" function of the script with that, and it will be automatically called when ran as a script, but not when imported as a module. -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On 11/12/2014 01:02 PM, John Ladasky wrote: I would like to start a discussion about whether Python should include a function which executes this evaluation, and hides all of the unfriendly dunderish details. And if that's a good idea, I would invite a discussion of how, exactly, it should be implemented. I'm nowhere near proposing a PEP, but that may come later. I believe this has come up before. You might check the Python-Ideas list to see. If you do, please write up a summary of the past discussions so we can move forward instead of rehashing the same things as before. -- ~Ethan~ -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
It appears that I'm not the first person to have thoughts along these lines. Here's a relevant article: http://aliles.tumblr.com/post/7455032885/sugar-for-pythons-main -- https://mail.python.org/mailman/listinfo/python-list
Re: How about some syntactic sugar for " __name__ == '__main__' "?
On Wed, Nov 12, 2014 at 4:02 PM, John Ladasky wrote: > I have taught Python to several students over the past few years. As I have > worked with my students, I find myself bothered by the programming idiom that > we use to determine whether a module is being executed or merely imported: > > "if __name__ == '__main__':" > > The use of two dunder tokens -- one as a name in a namespace, and the other > as a string, is intimidating. It exposes too much of Python's guts. As > such, I think that it is less Pythonic than we might want. Myself, I've been > programming in Python for a decade, and I still haven't dug very deeply into > what exactly __name__ means or does. > > I would like to start a discussion about whether Python should include a > function which executes this evaluation, and hides all of the unfriendly > dunderish details. And if that's a good idea, I would invite a discussion of > how, exactly, it should be implemented. I'm nowhere near proposing a PEP, > but that may come later. > > Thanks for your thoughts. > -- > https://mail.python.org/mailman/listinfo/python-list How about a decorator? -- Joel Goldstick http://joelgoldstick.com -- https://mail.python.org/mailman/listinfo/python-list
How about some syntactic sugar for " __name__ == '__main__' "?
I have taught Python to several students over the past few years. As I have worked with my students, I find myself bothered by the programming idiom that we use to determine whether a module is being executed or merely imported: "if __name__ == '__main__':" The use of two dunder tokens -- one as a name in a namespace, and the other as a string, is intimidating. It exposes too much of Python's guts. As such, I think that it is less Pythonic than we might want. Myself, I've been programming in Python for a decade, and I still haven't dug very deeply into what exactly __name__ means or does. I would like to start a discussion about whether Python should include a function which executes this evaluation, and hides all of the unfriendly dunderish details. And if that's a good idea, I would invite a discussion of how, exactly, it should be implemented. I'm nowhere near proposing a PEP, but that may come later. Thanks for your thoughts. -- https://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On Wed, Sep 28, 2011 at 07:01:11PM -0400, Terry Reedy wrote: > On 9/28/2011 5:26 PM, Ethan Furman wrote: > > >I don't remember if 'def' is sugar for something besides lambda. > > That is a bit backwards. > lambda x: expr(x) > is syntactic sugar for > def (x): return expr(x) > del > ;-) > lambda is less sugar and more of just a def as an expression. -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On 9/28/2011 5:26 PM, Ethan Furman wrote: I don't remember if 'def' is sugar for something besides lambda. That is a bit backwards. lambda x: expr(x) is syntactic sugar for def (x): return expr(x) del ;-) -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On Wed, Sep 28, 2011 at 3:26 PM, Ethan Furman wrote: > I remember that 'class' is sugar for type(). > > I don't remember if 'def' is sugar for something besides lambda. This is something I have thought about a lot since PyCon this year. I apologize in advance. Since 3.0, class statements are syntactic sugar for some extra steps beyond "meta(...)" [1]. In CPython this is facilitated through the "hidden" __build_class__() builtin[2]. We have the __import__() builtin for customizing module creation. But, as you asked, what about functions? Currently there isn't a way to customize function creation. There is no __build_function__() builtin. The best you can do is, like others have said, directly call FunctionType(...) or type(f)(...) where f is an existing function. I expect that if there were a __build_function__, it would wrap the code that is currently run for the MAKE_FUNCTION/MAKE_CLOSURE opcodes[3]. Also, both modules and classes have mechanisms built-in to allow for customization in certain parts of the creation process (PEP 302[4] and metaclasses[5], respectively). Functions lack this as well, though there hasn't been a big clamor for it. :) Nick Coghlan proposed an interesting idea for this in March[6], with some later follow-up[7]. Nothing much came of it though. Definitely an interesting topic, which has led me to learn a lot about Python and CPython. -eric [1] http://www.python.org/dev/peps/pep-3115/ http://mail.python.org/pipermail/python-3000/2007-March/006338.html [2] http://hg.python.org/cpython/file/default/Python/bltinmodule.c#l35 [3] http://hg.python.org/cpython/file/default/Python/ceval.c#l2680 [4] http://www.python.org/dev/peps/pep-0302/ http://docs.python.org/release/2.3.5/whatsnew/section-pep302.html http://docs.python.org/dev/reference/simple_stmts.html#the-import-statement [5] http://docs.python.org/dev/reference/datamodel.html#customizing-class-creation http://www.python.org/doc/essays/metaclasses/ [6] http://mail.python.org/pipermail/python-ideas/2011-March/009391.html [7] http://mail.python.org/pipermail/python-ideas/2011-March/009625.html http://mail.python.org/pipermail/python-ideas/2011-April/009765.html > > Any clues for me? Heck, I'll even be grateful for outright answers! > > ~Ethan~ > -- > http://mail.python.org/mailman/listinfo/python-list > -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
En Wed, 28 Sep 2011 18:51:00 -0300, Chris Kaynor escribió: On Wed, Sep 28, 2011 at 2:37 PM, Arnaud Delobelle wrote: On 28 September 2011 22:26, Ethan Furman wrote: I remember that 'class' is sugar for type(). I don't remember if 'def' is sugar for something besides lambda. Any clues for me? Heck, I'll even be grateful for outright answers! It's not really sugar. But I think you mean something like this: class A: pass ... type(A) type is type(A) True So the closest you get for functions will be: def f(): pass ... type(f) Try help(type(f)) to see how to use it to create a function object. The problem is that you need to provide a code object, and the easiest way to create a code object is to use a def statement :) I would say compile isn't too much harder to use: c = compile('a = 123', 'test', 'exec') d = {} f = types.FunctionType(c, d, 'test') f() print d {'a': 123} Although it appears you get all of the variables defined as global apparently (try "f = types.FunctionType(c, globals(), 'test')" instead). I know no way of compiling a function body alone. Suppose you have this function: def foo(x): print x y = 2*x return y py> compile(" print x\n y = 2*x\n return y", "", "exec") Traceback (most recent call last): File "", line 1, in File "", line 1 print x ^ IndentationError: unexpected indent py> compile("print x\ny = 2*x\nreturn y", "", "exec") Traceback (most recent call last): File "", line 1, in File "", line 3 SyntaxError: 'return' outside function If you include the 'def' statement in the source string, the resulting code object does not represent the function itself, but a "module" defining it: py> f = FunctionType(compile("def foo(x):\n print x\n y = 2*x\n return y\n", ... "", "exec"), globals(), "foo") py> f(3) Traceback (most recent call last): File "", line 1, in TypeError: () takes no arguments (1 given) py> dis.dis(f) 1 0 LOAD_CONST 0 (file "", line 1>) 3 MAKE_FUNCTION0 6 STORE_NAME 0 (foo) 9 LOAD_CONST 1 (None) 12 RETURN_VALUE To get at the actual function code, one should use f.func_code.co_consts[0]; this would be the 'code' parameter for types.FunctionType. Very complicated, really; nothing can beat the 'def' statement for defining a function ;) -- Gabriel Genellina -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On Wed, Sep 28, 2011 at 2:37 PM, Arnaud Delobelle wrote: > On 28 September 2011 22:26, Ethan Furman wrote: >> I remember that 'class' is sugar for type(). >> >> I don't remember if 'def' is sugar for something besides lambda. >> >> Any clues for me? Heck, I'll even be grateful for outright answers! > > It's not really sugar. But I think you mean something like this: > > class A: pass > ... type(A) > type is type(A) > True > > So the closest you get for functions will be: > def f(): pass > ... type(f) > > > Try help(type(f)) to see how to use it to create a function object. > The problem is that you need to provide a code object, and the easiest > way to create a code object is to use a def statement :) I would say compile isn't too much harder to use: >>> c = compile('a = 123', 'test', 'exec') >>> d = {} >>> f = types.FunctionType(c, d, 'test') >>> f() >>> print d {'a': 123} Although it appears you get all of the variables defined as global apparently (try "f = types.FunctionType(c, globals(), 'test')" instead). > > HTH > > -- > Arnaud > -- > http://mail.python.org/mailman/listinfo/python-list > -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On 28 September 2011 22:26, Ethan Furman wrote: > I remember that 'class' is sugar for type(). > > I don't remember if 'def' is sugar for something besides lambda. > > Any clues for me? Heck, I'll even be grateful for outright answers! It's not really sugar. But I think you mean something like this: >>> class A: pass ... >>> type(A) >>> type is type(A) True So the closest you get for functions will be: >>> def f(): pass ... >>> type(f) Try help(type(f)) to see how to use it to create a function object. The problem is that you need to provide a code object, and the easiest way to create a code object is to use a def statement :) HTH -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list
Re: syntactic sugar for def?
On Wed, Sep 28, 2011 at 3:26 PM, Ethan Furman wrote: > I remember that 'class' is sugar for type(). > > I don't remember if 'def' is sugar for something besides lambda. > > Any clues for me? Heck, I'll even be grateful for outright answers! If you mean is there a way to create functions using reflection, you can use types.FunctionType. Like type() requires a dict, FunctionType() requires a code object that must first be compiled. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
syntactic sugar for def?
I remember that 'class' is sugar for type(). I don't remember if 'def' is sugar for something besides lambda. Any clues for me? Heck, I'll even be grateful for outright answers! ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
In article <16ea4848-db0c-489a-968c-ca40700f5...@m5g2000prh.googlegroups.com>, gc wrote: > I frequently need to initialize several variables to the same > value, as I'm sure many do. Sometimes the value is a constant, often > zero; sometimes it's more particular, such as defaultdict(list). I use > dict() below. Keep in mind that when you do: a = dict() b = dict() you are NOT initializing a and b to the same value. You are initializing each of them to a different empty dictionary, which is very different from a = b = dict() I suspect you knew that, but it's worth mentioning. > # Option 1 (separate lines) > # Verbose and annoying, particularly when the varnames are long and of > irregular length > > a = dict() > b = dict() > c = dict() > d = dict() > e = dict() This seems the best to me. Simple, straight-forward, easy to understand. What could be bad? It may not be elegant, but if I could have a nickel for every hour I've wasted trying to understand elegant code, I'd be a rich man. I can understand the above code in an instant, even at 2 AM juiced up on sugar and caffeine. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Aug 3, 2:45 am, gc wrote: > Hi everyone! Longtime lurker, hardly an expert, but I've been using > Python for various projects since 2007 and love it. > > I'm looking for either (A) suggestions on how to do a very common > operation elegantly and Pythonically, or (B) input on whether my > proposal is PEP-able, assuming there's no answer to A. (The proposal > is sort of like the inverse of PEP 3132; I don't think it has been > proposed before, sorry if I missed it.) > > Anyway, I frequently need to initialize several variables to the same > value, as I'm sure many do. Sometimes the value is a constant, often > zero; sometimes it's more particular, such as defaultdict(list). I use > dict() below. > > Target lists using comma separation are great, but they don't work > very well for this task. What I want is something like > > a,b,c,d,e = *dict() > > where * in this context means something like "assign separately to > all." I'm not sure that * would the best sugar for this, but the > normal meaning of * doesn't seem as if it would ever be valid in this > case, and it somehow feels right (to me, anyway). > > Statements fitting the form above would get expanded during parsing to > a sequence of separate assignments (a = dict(); b = dict(); c = dict() > and so forth.) That's all there is to it. Compared to the patterns > below, it's svelte, less copy-paste-y (so it removes an opportunity > for inconsistency, where I remember to change a-d to defaultdict(list) > but forget with e), and it doesn't require me to keep count of the > number of variables I'm initializing. > > This would update section 6.2 of the language reference and require a > small grammar expansion. > > But: Is there already a good way to do this that I just don't know? > Below, I compare four obvious patterns, three of which are correct but > annoying and one of which is incorrect in a way which used to surprise > me when I was starting out. > > # Option 1 (separate lines) > # Verbose and annoying, particularly when the varnames are long and of > irregular length > > a = dict() > b = dict() > c = dict() > d = dict() > e = dict() > > # Option 2 (one line) > # More concise but still pretty annoying, and hard to read (alternates > variables and assignments) > > a = dict(); b = dict(); c = dict(); d = dict(); e = dict() > > # Option 3 (multiple target list: this seems the most Pythonic, and is > normally what I use) > # Concise, separates variables from assignments, but somewhat > annoying; have to change individually and track numbers on both sides. > > a,b,c,d,e = dict(),dict(),dict(),dict(),dict() > > # Option 4 (iterable multiplication) > # Looks better, and if the dict() should be something else, you only > have to change it once, but the extra brackets are ugly and you still > have to keep count of the targets... > > a,b,c,d,e = [dict()] * 5 > > # and it will bite you... > > >>> a[1] = 1 > >>> b > {1: 1} > >>> id(a) == id(b) > > True > > # Gotcha! > > # Other forms of 4 also have this behavior: > > a,b,c,d,e = ({},) * 5>>> a[1] = 1 > >>> b > > {1: 1} > > Alternatively, is there a version of iterable multiplication that > creates new objects rather than just copying the reference? That would > solve part of the problem, though it would still look clunky and you'd > still have to keep count. > > Any thoughts? Thanks! I hesitate to put this forward, as it smells and is probably considered bad practice, but heh! for char in 'abcdefg' : globals()[ char ] = dict() does what you wanted. Best wishes, John -- -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
: Off on a tangent ... On 16 August 2011 20:14, gc wrote: > > Let me address one smell from my particular example, which may be the > one you're noticing. If I needed fifty parallel collections I would > not use separate variables; I've coded a ghastly defaultdefaultdict > just for this purpose, which effectively permits what most people > would express as defaultdict(defaultdict(list)) [not possible AFAIK > with the existing defaultdict class]. Dunno if it's better than your ghastly defaultdefaultdict, but this works: >>> from collections import defaultdict >>> ddd = defaultdict(lambda: defaultdict(list)) >>> ddd["foo"]["bar"].append("something") >>> ddd["foo"]["bar"] ['something'] >>> -[]z. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
gc wrote: Target lists using comma separation are great, but they don't work very well for this task. What I want is something like a,b,c,d,e = *dict() This isn't going to happen. From all the discussion so far I think your best solution is a simple helper function (not tested): def repeat(count_, object_, *args, **kwargs): result = [] for _ in range(count_): result.append(object_(*args, **kwargs)) return result a, b, c, d, e = repeat(5, dict) These are each new objects, so depending on the function (like the random.rand_int example) the values may not be the same. Oh, and I put the trailing _ on count and object to minimize possible conflicts with keyword arguments. ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
gc wrote: > Maybe this is more visibly convenient with a complex class, like > > x, y, z = *SuperComplexClass(param1, param2, kwparam = "3", ...) > > where you need three separate objects but don't want to duplicate the > class call (for obvious copy-paste reasons) and where bundling it in a > list comprehension: > > x, y, z = [SuperComplexClass(param1, etc, ...) for _ in range(3)] > > layers gunk on top of something that's already complex. That just seems like an odd use case to me. I rarely find myself wanting to make exactly N copies of the same thing and assign them to explicit names. If I'm not making just one, it's usually because I'm making some sort of list or dict of them that will be accessed by index (not with names like "x", "y", and "z"), in which case a list comprehension is the right way to go. -- --OKB (not okblacke) Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Wed, Aug 17, 2011 at 5:55 PM, MRAB wrote: > x, y, z = lazy copies(SuperComplexClass(param1, etc, ...)) > This assumes that you can construct it once and then copy it reliably, which may mean that the class implement copying correctly. It also wouldn't work with: a, b, c, d = *random.randint(1,20) which would roll 4d20 and get the results in separate variables. The OP's idea of separately evaluating the expression would; but to do it with copying would require a special "randint" object that functions exactly as an integer but, when copied, would re-randomize. Perhaps * is the wrong syntactic element to use. Maybe it needs a special assignment operator: a, b, c, d @= random.randint(1,20) which would evaluate its left operand as a tuple of lvalues, then evaluate its right operand once for each element in the left operand, and assign to each element in turn. (I've no idea what form of assignment operator would be suitable, but @= is currently illegal, so it ought to be safe at least for discussion purposes.) Chris Angelico -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On 17/08/2011 10:26, gc wrote: On Aug 17, 3:13 am, Chris Angelico wrote: Minor clarification: You don't want to initialize them to the same value, which you can do already: a=b=c=d=e=dict() Right. Call the proposed syntax the "instantiate separately for each target" operator. (It can be precisely defined as a * on the RHS of a one-into-many assignment statement--i.e. an assignment statement with 1 object on the RHS and more than 1 on the LHS). I think that lazy unpacking is the more important issue because we can replace instantiation with copying: def copies(obj, count=None): if count is None: while True: yield obj.copy() else: for i in range(count): yield obj.copy() (Should it yield deep copies, or should there be a separate deep_copies function?) It has only one very modest function, which is to unpack a, b, c, d, e = *dict() to a, b, c, d, e = dict(), dict(), dict(), dict(), dict() This becomes: a, b, c, d, e = copies(dict(), 5) With lazy unpacking it would become: a, b, c, d, e = lazy copies(dict()) (Or whatever the syntax is.) so that you have n separate objects instead of one. If you want the same object duplicated five times, you'd best use a=b=c=d=e=dict(). (I'd guess that 90% of the people who try the a=b=c version actually *want* separate objects and are surprised at what they get--I made that mistake a few times!--but changing either behavior would be a very bad idea. This proposed syntax would be the Right Way to get separate objects.) Maybe this is more visibly convenient with a complex class, like x, y, z = *SuperComplexClass(param1, param2, kwparam = "3", ...) x, y, z = lazy copies(SuperComplexClass(param1, etc, ...)) [snip] -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
The issue behind this thread is that for immutable objects, binding to n copies has the same effect as n bindings to one object (so one does not really have to know which one is doing), whereas the two are different for mutable objects (so one does have to know). In short, identity matters for mutables but not for immutables. Python programmers must learn both this and the fact that Python does not make copies unless asked. Adding a special case exception to the latter to mask the former does not seem like a good idea. On 8/17/2011 5:26 AM, gc wrote: It has only one very modest function, which is to unpack a, b, c, d, e = *dict() *expression has already been proposed to generally mean what it does in function calls -- unpack the iterator in place. funnylist = [1,2,*dict,99,100] # == [1,2]+list(dict)+[99,100] would interpolate the keys of the dict into the list. There is a tracker issue for this -- it would be a follow-on to the addition of *traget in assignments. In a real sense, "a,b = iterable" *already* means "a,b = *iterable". If *iterable had been in general use from the beginning, presume the latter is how we would write sequence unpacking for assignments. a, b, c, d, e = dict(), dict(), dict(), dict(), dict() *expression will not be changed in meaning to magically re-evaluate an expression some multiple number of times according to code elsewhere. so that you have n separate objects instead of one. If you want the same object duplicated five times, you'd best use a=b=c=d=e=dict(). Not 'duplicated', but 'bound'. (I'd guess that 90% of the people who try the a=b=c version actually *want* separate objects and are surprised at what they get--I made that mistake a few times! Guessing that 90% of people are like you is likely to be wrong. I think this use case (for more than 2 or 3 copies) is pretty rare for most people. Where many people do trip up is "array = [[0]*i]*j", expecting to get j copies of [0]*i rather than j bindings of one object. But then, they must have the same wrong idea that [0]*i makes i copies of 0. For immutable 0, the misunderstanding does not matter. For mutable [0]*i, it does. People *must* learn that sequence multiplication multiplies bindings, not (copies of) objects. Both multiple copy problems have the same solution: array = [[0]*i for _ in range(j)] a,b,c,d,e = [dict() for _ in range(5)] The fact that the number of assignment sources (possibly after implicit unpacking) and targets have to match, unless one uses *target, and that both sides need to be changed if one is, is true of all assignments, not just this rare case. --but changing either behavior would be a very bad idea. This proposed syntax would be the Right Way to get separate objects.) It would be very Wrong as it already has a very different meaning. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Aug 17, 5:45 am, Chris Angelico wrote: (snip) > > Right. Call the proposed syntax the "instantiate separately for each > > target" operator. > (snip) > It might just > as easily be some other function call; for instance: > > head1,head2,head3=file.readline() Hm--that's interesting! OK, call it the "evaluate separately for each target" operator. Same benefits in this use case; if I realize that the file only has two header lines, I can just change head1, head2, head3 = *file.readline() to head1, head2 = *file.readline() without needing to keep a RHS like = [file.readline() for _ in range(3)] in lockstep with the number of variables I'm assigning. Presumably this syntax should be disallowed, as a grammatical matter, when there's a starred target (per PEP 3132/language reference 6.2). That is, head, *body, tail = *file.readline() is disallowed, since it is (by definition) simply sugar for head = file.readline() *body = file.readline() tail = file.readline() and *body = file.readline() is disallowed (see PEP 3132). (Here, of course, you'd just want head, *body, tail = file.readlines(), which is perfectly good code.) PS. Off-topic, but the *target syntax already gets into similar territory, since a, *b, c = itertools.count() crashes with a MemoryError--but what else could it do? Ruling out such infinite-assignment statements on a grammatical basis would require solving the halting problem through static analysis, which might be a bit inefficient :P -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Wed, Aug 17, 2011 at 10:26 AM, gc wrote: > On Aug 17, 3:13 am, Chris Angelico wrote: > >> Minor clarification: You don't want to initialize them to the same >> value, which you can do already: >> >> a=b=c=d=e=dict() > > Right. Call the proposed syntax the "instantiate separately for each > target" operator. (It can be precisely defined as a * on the RHS of a > one-into-many assignment statement--i.e. an assignment statement with > 1 object on the RHS and more than 1 on the LHS). > Agreed, but there's no requirement for it to be instantiating something (although that will be common). "dict()" is an expression that you want to evaluate five (or however many) times. It might just as easily be some other function call; for instance: head1,head2,head3=file.readline() to read three lines from a file. Or it mightn't even be a function call per se. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Aug 17, 3:13 am, Chris Angelico wrote: > Minor clarification: You don't want to initialize them to the same > value, which you can do already: > > a=b=c=d=e=dict() Right. Call the proposed syntax the "instantiate separately for each target" operator. (It can be precisely defined as a * on the RHS of a one-into-many assignment statement--i.e. an assignment statement with 1 object on the RHS and more than 1 on the LHS). It has only one very modest function, which is to unpack a, b, c, d, e = *dict() to a, b, c, d, e = dict(), dict(), dict(), dict(), dict() so that you have n separate objects instead of one. If you want the same object duplicated five times, you'd best use a=b=c=d=e=dict(). (I'd guess that 90% of the people who try the a=b=c version actually *want* separate objects and are surprised at what they get--I made that mistake a few times!--but changing either behavior would be a very bad idea. This proposed syntax would be the Right Way to get separate objects.) Maybe this is more visibly convenient with a complex class, like x, y, z = *SuperComplexClass(param1, param2, kwparam = "3", ...) where you need three separate objects but don't want to duplicate the class call (for obvious copy-paste reasons) and where bundling it in a list comprehension: x, y, z = [SuperComplexClass(param1, etc, ...) for _ in range(3)] layers gunk on top of something that's already complex. > I think it's going to work out something very similar to a > list comprehension (as has been mentioned). Right; kind of a self-limiting generator[1], although that sounds MUCH more complex than it needs to. It's really just sugar. Not that it this is a suggestion :) but it could easily be done with a pre- processor. It would also be perfectly amenable to automated code conversion (i.e. 3to2). On Aug 16, 10:11 pm, MRAB wrote: > 1. Repeated evaluation of an expression: "dict()" would be evaluated as > many times as necessary. In other words, it's an unlimited generator. > 2. Lazy unpacking: unpacking normally continues until the source is > exhausted, but here you want it to stop when the destination (the RHS) > is satisfied. Yes, this is a good way to think of it. (Although I think you meant to type LHS, right?) * in this context would tell Python to do both of these things at once: evaluate successively and unpack lazily to the destination. Although it's still fully (and more simply) explainable as sugar. [1] Self-limiting is the key here. As above, the only proposed methods which don't require manual tallying on the RHS are Tim's very creative a,b,c,d,e,*scrap = (dict() for _ in range()), which in this case creates a list containing 9994 unnecessary dicts, or the purer but Python-crashing a,b,c,d,e,*scrap = (dict() for _ in itertools.count()). Tim's intuition, which I share, is that in both cases *scrap should, since it's in final position, actually become the generator-in-state-6, rather than slurping the rest into a list. One argument for this is that the present behavior is (surprisingly, counterintuitively) identical for list comprehensions and generator expressions. Changing the outer parens to brackets yields the same results. But that's a separate, more complex proposal which would need its own use cases. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Wed, Aug 17, 2011 at 1:14 AM, gc wrote: > Perfectly reasonable request! Maybe there aren't as many cases when > multiple variables need to be initialized to the same value as I think > there are. > Minor clarification: You don't want to initialize them to the same value, which you can do already: a=b=c=d=e=dict() You want to initialize them each to a fresh evaluation of the same expression. What you're asking for is a syntax that writes an expression once, but evaluates it many times; I think it's going to work out something very similar to a list comprehension (as has been mentioned). ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On 17/08/2011 01:14, gc wrote: On Aug 16, 4:39 pm, "Martin P. Hellwig" wrote: On 03/08/2011 02:45, gc wrote: a,b,c,d,e = *dict() where * in this context means something like "assign separately to all. . . . it has a certain code smell to it. I would love to see an example where you would need such a construct. Perfectly reasonable request! Maybe there aren't as many cases when multiple variables need to be initialized to the same value as I think there are. [snip] As I see it, there are 2 issues: 1. Repeated evaluation of an expression: "dict()" would be evaluated as many times as necessary. In other words, it's an unlimited generator. 2. Lazy unpacking: unpacking normally continues until the source is exhausted, but here you want it to stop when the destination (the RHS) is satisfied. It just happens that in your use-case they are being used together. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Aug 16, 4:39 pm, "Martin P. Hellwig" wrote: > On 03/08/2011 02:45, gc wrote: > > > > a,b,c,d,e = *dict() > > > where * in this context means something like "assign separately to > > all. > . . . it has a certain code smell to it. > I would love to see an example where you would need such a construct. Perfectly reasonable request! Maybe there aren't as many cases when multiple variables need to be initialized to the same value as I think there are. I'm a heavy user of collections, especially counters and defaultdicts. One frequent pattern involves boiling (typically) SQLite records down into Python data structures for further manipulation. (OK, arguably that has some code smell right there--but I often have to do very expensive analysis on large subsets with complex definitions which can be very expensive to pull, sometimes requiring table scans over tens of gigabytes. I *like* being able to use dicts or other structures as a way to cache and structure query results in ways amenable to analysis procedures, even if it doesn't impress Joe Celko.) defaultdict(list) is a very clean way to do this. I'll often have four or five of them collecting different subsets of a single SQL pull, as in: # PROPOSED SYNTAX: all_pets_by_pet_store, blue_dogs_by_pet_store, green_cats_by_pet_store, red_cats_and_birds_by_pet_store = *defautdict(list) # (Yes, indexes on color and kind would speed up this query, but the actual fields can be way quite complex and have much higher cardinality.) for pet_store, pet_kind, pet_color, pet_weight, pet_height in cur.execute("""SELECT s, k, c, w, h FROM SuperExpensivePetTable WHERE CostlyCriterionA(criterion_basis) IN("you", "get", "the", "idea")"""): all_pets_by_pet_store[pet_store].append(pet_weight, pet_height) if pet_color in ("Blue", "Cyan", "Dark Blue") and pet_kind in ("Dog", "Puppy"): blue_dogs_by_pet_store[pet_store].append(pet_weight, pet_height) #... and so forth all_pets_analysis = BootstrappedMarkovDecisionForestFromHell(all_pets_by_pet_store) blue_dogs_analysis = BootstrappedMarkovDecisionForestFromHell(blue_dogs_by_pet_store) red_cats_and_birds_analysis = BMDFFHPreyInteracton(red_cats_and_bird_by_pet_store) #... and so forth Point is, I'd like to be able to create such collections cleanly, and a,b,c = *defaultdict(list) seems as clean as it gets. Plus, when I realize I need six (or only three) it's annoying to need to change two redundant things (i.e. both the variable names and the count.) if tl_dr: break() Generally speaking, when you know you need several variables of the same (maybe complex) type, the proposed syntax lets the equals sign fully partition the variables question (how many variables do I need, and what are they called?) from the data structure question (what type should the variables be?) The other syntaxes (except Tim's generator- slurping one, which as Tim points out has its own issues) all spread the variables question across the equals sign, breaking the analogy with single assignment (where the form is Variable = DataStructure). If we're allowing multiple assignment, why can't we allow some form of Variable1, Variable2, Variable3 = DataStructure without reaching for list comprehensions, copy-pasting and/or keeping a side count of the variables? if much_tl_dr: break() Let me address one smell from my particular example, which may be the one you're noticing. If I needed fifty parallel collections I would not use separate variables; I've coded a ghastly defaultdefaultdict just for this purpose, which effectively permits what most people would express as defaultdict(defaultdict(list)) [not possible AFAIK with the existing defaultdict class]. But for reasons of explicitness and simplicity I try to avoid hash-tables of hash-tables (and higher iterations). I'm not trying to use dicts to inner-platform a fully hashed version of SQL, but to boil things down. Also bear in mind, reading the above, that I do a lot of script-type programming which is constantly being changed under severe time pressure (often as I'm sitting next to my clients), which needs to be as simple as possible, and which tech-savvy non-programmers need to understand. A lot of my value comes from quickly creating code which other people (usually research academics) can feel ownership over. Python is already a great language for this, and anything which makes the syntax cleaner and more expressive and which eliminates redundancy helps me do my job better. If I were coding big, stable applications where the defaultdicts were created in a header file and wouldn't be touched again for three years, I would care less about a more awkward initialization method. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On 03/08/2011 02:45, gc wrote: a,b,c,d,e = *dict() where * in this context means something like "assign separately to all. Any thoughts? Thanks! Well got a thought but I am afraid it is the opposite of helpful in the direct sense. So if you don't want to hear it skip it :-) Although I can not proficiently argument it, it has a certain code smell to it. In the sense that it could hint that there is a better more readable way of solving that particular problem (taking in account that the one letter labels are pure for demonstration purpose). I would love to see an example where you would need such a construct. -- mph -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
Thanks for all the discussion on this. Very illuminating. Sorry for the long delay in responding--deadlines intervened. I will use the list comprehension syntax for the foreseeable future. Tim, I agree with you about the slurping in final position--it's actually quite surprising. As I'm sure you realized, that behavior makes your 'tidier' version: a,b,c,d,e, *more_dict_generator = (dict() for _ in itertools.count()) break with a MemoryError, which I don't think is the result that most people would expect. Stephen wrote: > While slightly ugly, it doesn't seem ugly enough to justify the > extra complexity of special syntax for such a special case. You're probably right (although for my coding this multiple assignment scenario is a pretty ordinary case.) Anyway, I'll shop the a,b,c = *dict() syntax over to python-ideas just to see what they say. Thanks again, everyone! Happy Python. On Aug 3, 7:25 am, Tim Chase wrote: > On 08/03/2011 03:36 AM, Katriel Cohn-Gordon wrote: > > > On Wed, Aug 3, 2011 at 9:25 AM, Steven D'Aprano wrote: > >> a, b, c, d, e = [dict() for i in range(5)] > > > I think this is good code -- if you want five different dicts, > > then you should call dict five times. Otherwise Python will > > magically call your expression more than once, which isn't > > very nice. And what if your datatype constructor has > > side-effects? > > If the side-effects are correct behavior (perhaps opening files, > network connections, or even updating a class variable) then > constructor side-effects are just doing what they're supposed to. > E.g. something I use somewhat regularly in my code[*]: > > a,b,c,d = (file('file%i.txt', 'w') for i in range(4)) > > If the side-effects aren't performing the correct behavior, fix > the constructor. :) > > -tkc > > [*] okay, it's more like > > (features, > adjustments, > internet, > ) = (file(fname) for fname in ( > 'features.txt', > 'adjustments.txt', > 'internet.txt' > ) > > or even > > (features, > adjustments, > internet, > ) = ( > set( > line.strip().upper() > for line > in file(fname) > if line.strip() > ) > for fname in ( > 'features.txt', > 'adjustments.txt', > 'internet.txt' > ) > > to load various set() data from text-files. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On 08/03/2011 03:36 AM, Katriel Cohn-Gordon wrote: On Wed, Aug 3, 2011 at 9:25 AM, Steven D'Aprano wrote: a, b, c, d, e = [dict() for i in range(5)] I think this is good code -- if you want five different dicts, then you should call dict five times. Otherwise Python will magically call your expression more than once, which isn't very nice. And what if your datatype constructor has side-effects? If the side-effects are correct behavior (perhaps opening files, network connections, or even updating a class variable) then constructor side-effects are just doing what they're supposed to. E.g. something I use somewhat regularly in my code[*]: a,b,c,d = (file('file%i.txt', 'w') for i in range(4)) If the side-effects aren't performing the correct behavior, fix the constructor. :) -tkc [*] okay, it's more like (features, adjustments, internet, ) = (file(fname) for fname in ( 'features.txt', 'adjustments.txt', 'internet.txt' ) or even (features, adjustments, internet, ) = ( set( line.strip().upper() for line in file(fname) if line.strip() ) for fname in ( 'features.txt', 'adjustments.txt', 'internet.txt' ) to load various set() data from text-files. -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On 08/03/2011 03:25 AM, Steven D'Aprano wrote: gc wrote: Target lists using comma separation are great, but they don't work very well for this task. What I want is something like a,b,c,d,e = *dict() a, b, c, d, e = [dict() for i in range(5)] Unfortunately there is no way of doing so without counting the assignment targets. While slightly ugly, it doesn't seem ugly enough to justify the extra complexity of special syntax for such a special case. I understand that in Py3k (and perhaps back-ported into later 2.x series?) one can do something like a, b, c, d, e, *junk = (dict() for _ in range()) to prevent the need to count. However, I was disappointed with all the generator-ification of things in Py3k, that this "and the rest" syntax slurps up the entire generator, rather than just assigning the iterator. That would much more tidily be written as a,b,c,d,e, *more_dict_generator = (dict() for _ in itertools.count()) (itertools.count() happening to be a infinite generator). I can see the need to slurp if you have things afterward: a,b,c, *junk ,d,e = iterator(...) but when the "and the rest" is the last one, it would make sense not to force a slurp. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Wed, Aug 3, 2011 at 9:25 AM, Steven D'Aprano < steve+comp.lang.pyt...@pearwood.info> wrote: > gc wrote: > > > Target lists using comma separation are great, but they don't work > > very well for this task. What I want is something like > > > > a,b,c,d,e = *dict() > > a, b, c, d, e = [dict() for i in range(5)] > I think this is good code -- if you want five different dicts, then you should call dict five times. Otherwise Python will magically call your expression more than once, which isn't very nice. And what if your datatype constructor has side-effects? Katriel -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
gc wrote: Alternatively, is there a version of iterable multiplication that creates new objects rather than just copying the reference? You can use a list comprehension: a, b, c, d, e = [dict() for i in xrange(5)] or a generator expression: a, b, c, d, e = (dict() for i in xrange(5)) -- Greg -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
gc wrote: > Target lists using comma separation are great, but they don't work > very well for this task. What I want is something like > > a,b,c,d,e = *dict() a, b, c, d, e = [dict() for i in range(5)] Unfortunately there is no way of doing so without counting the assignment targets. While slightly ugly, it doesn't seem ugly enough to justify the extra complexity of special syntax for such a special case. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Syntactic sugar for assignment statements: one value to multiple targets?
On Wed, Aug 3, 2011 at 2:45 AM, gc wrote: > Anyway, I frequently need to initialize several variables to the same > value, as I'm sure many do. Sometimes the value is a constant, often > zero; sometimes it's more particular, such as defaultdict(list). I use > dict() below. If it's an immutable value (such as a constant integer), you can use syntax similar to C's chained assignment: a=b=c=0 If you do this with dict(), though, it'll assign the same dictionary to each of them - not much use. > # Option 3 (multiple target list: this seems the most Pythonic, and is > normally what I use) > # Concise, separates variables from assignments, but somewhat > annoying; have to change individually and track numbers on both sides. > > a,b,c,d,e = dict(),dict(),dict(),dict(),dict() I think this is probably the best option, although I would be inclined to use dictionary-literal syntax: a,b,c,d,e = {},{},{},{},{} It might be possible to do something weird with map(), but I think it'll end up cleaner to do it this way. Chris Angelico -- http://mail.python.org/mailman/listinfo/python-list
Syntactic sugar for assignment statements: one value to multiple targets?
Hi everyone! Longtime lurker, hardly an expert, but I've been using Python for various projects since 2007 and love it. I'm looking for either (A) suggestions on how to do a very common operation elegantly and Pythonically, or (B) input on whether my proposal is PEP-able, assuming there's no answer to A. (The proposal is sort of like the inverse of PEP 3132; I don't think it has been proposed before, sorry if I missed it.) Anyway, I frequently need to initialize several variables to the same value, as I'm sure many do. Sometimes the value is a constant, often zero; sometimes it's more particular, such as defaultdict(list). I use dict() below. Target lists using comma separation are great, but they don't work very well for this task. What I want is something like a,b,c,d,e = *dict() where * in this context means something like "assign separately to all." I'm not sure that * would the best sugar for this, but the normal meaning of * doesn't seem as if it would ever be valid in this case, and it somehow feels right (to me, anyway). Statements fitting the form above would get expanded during parsing to a sequence of separate assignments (a = dict(); b = dict(); c = dict() and so forth.) That's all there is to it. Compared to the patterns below, it's svelte, less copy-paste-y (so it removes an opportunity for inconsistency, where I remember to change a-d to defaultdict(list) but forget with e), and it doesn't require me to keep count of the number of variables I'm initializing. This would update section 6.2 of the language reference and require a small grammar expansion. But: Is there already a good way to do this that I just don't know? Below, I compare four obvious patterns, three of which are correct but annoying and one of which is incorrect in a way which used to surprise me when I was starting out. # Option 1 (separate lines) # Verbose and annoying, particularly when the varnames are long and of irregular length a = dict() b = dict() c = dict() d = dict() e = dict() # Option 2 (one line) # More concise but still pretty annoying, and hard to read (alternates variables and assignments) a = dict(); b = dict(); c = dict(); d = dict(); e = dict() # Option 3 (multiple target list: this seems the most Pythonic, and is normally what I use) # Concise, separates variables from assignments, but somewhat annoying; have to change individually and track numbers on both sides. a,b,c,d,e = dict(),dict(),dict(),dict(),dict() # Option 4 (iterable multiplication) # Looks better, and if the dict() should be something else, you only have to change it once, but the extra brackets are ugly and you still have to keep count of the targets... a,b,c,d,e = [dict()] * 5 # and it will bite you... >>> a[1] = 1 >>> b {1: 1} >>> id(a) == id(b) True # Gotcha! # Other forms of 4 also have this behavior: a,b,c,d,e = ({},) * 5 >>> a[1] = 1 >>> b {1: 1} Alternatively, is there a version of iterable multiplication that creates new objects rather than just copying the reference? That would solve part of the problem, though it would still look clunky and you'd still have to keep count. Any thoughts? Thanks! -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 12/02/2010 10:39 AM, Mark Dickinson wrote: On Nov 15, 12:46 pm, Tim Chase wrote: On 11/15/2010 12:39 AM, Dmitry Groshev wrote: x in range optimisation I've often thought this would make a nice O(1)-test lookup on an xrange() generator. An O(1) test for 'x in' is implemented in Python 3.2, at least provided that x has type 'int', 'long' or 'bool'. (If x is an instance of a subclass of int or long, then there's a risk that the semantics of the membership test have been changed by an explicitly overridden __eq__, so Python wimps out and falls back to the O(n) algorithm in that case.) Drat, bested again by the python time-machine. Thanks for bringing that to my attention. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 12:46 pm, Tim Chase wrote: > On 11/15/2010 12:39 AM, Dmitry Groshev wrote: > > > x in range optimisation > > I've often thought this would make a nice O(1)-test lookup on an > xrange() generator. An O(1) test for 'x in ' is implemented in Python 3.2, at least provided that x has type 'int', 'long' or 'bool'. (If x is an instance of a subclass of int or long, then there's a risk that the semantics of the membership test have been changed by an explicitly overridden __eq__, so Python wimps out and falls back to the O(n) algorithm in that case.) Python 3.2a4+ (py3k:86635:86636M, Nov 21 2010, 19:22:18) [GCC 4.2.1 (Apple Inc. build 5664)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> -1 in range(10**9) False >>> 5 in range(0, 10**100, 2) False >>> 10**99 in range(0, 10**100, 2) True IIRC, there wasn't sufficient interest to get it backported to Python 2.7 in time for its release. Though as a pure optimization, one could argue that it would still be possible to get this into Python 2.7.2. Mark -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Wed, 01 Dec 2010 15:18:32 -0800, Dmitry Groshev wrote: > Here is a fresh example of what I meant by my first proposal. You need > to build a matrix like this: > 2 1 0 ... > 1 2 1 ... > 0 1 2 ... > ... > ... 1 2 1 > ... 0 1 2 > You could do this by one-liner: > [[(2 - abs(x - y)) if it > 0 else 0 for x in xrange(8)] for y in > xrange(8)] > ...but in reality you should write something like this: [[(lambda t: t > if t > 0 else 0)(2 - abs(x - y)) for x in xrange(8)] for y in xrange(8)] > or this > [[(2 - abs(x - y)) if (2 - abs(x - y)) > 0 else 0 for x in xrange(8)] > for y in xrange(8)] > or even this > def foo(x, y): > if abs(x - y) == 0: > return 2 > elif abs(x - y) == 1: > return 1 > else: > return 0 > [[foo(x, y) for x in xrange(8)] for y in xrange(8)] All those one-liners give me a headache. At least your "foo" solution is understandable. But I'd do it like this: >>> array = [[0]*8 for _ in range(8)] >>> for i in range(8): ... array[i][i] = 2 ... if i > 0: array[i][i-1] = 1 ... if i < 7: array[i][i+1] = 1 ... >>> pprint.pprint(array) [[2, 1, 0, 0, 0, 0, 0, 0], [1, 2, 1, 0, 0, 0, 0, 0], [0, 1, 2, 1, 0, 0, 0, 0], [0, 0, 1, 2, 1, 0, 0, 0], [0, 0, 0, 1, 2, 1, 0, 0], [0, 0, 0, 0, 1, 2, 1, 0], [0, 0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 0, 1, 2]] When you stop trying to make everything a one-liner, it's amazing how readable you can make code :) -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 22, 2:21 pm, Andreas Löscher wrote: > > if x in range(a, b): #wrong! > > it feels so natural to check it that way, but we have to write > > if a <= x <= b > > I understand that it's not a big deal, but it would be awesome to have > > some optimisations - it's clearly possible to detect things like that > > "wrong" one and fix it in a bytecode. > > You can implement it yourself: > > class between(object): > def __init__(self, a,b): > super(crang, self).__init__() > self.a=a > self.b=b > def __contains__(self, value): > return self.a <= value <= self.b > > >>> 12.45 in between(-100,100) > > true > > But do you need > > a < x < b > a <= x < b > a <= x <= b or > a < x <= b ? > > Sure, you could set a new parameter for this, but the normal way is not > broken at all. > > Best Of course there are better ways to do this. Your "between", standart comparisons and so, but expressing this as "i in range(a, b)" is just intuitive and declarative. Here is a fresh example of what I meant by my first proposal. You need to build a matrix like this: 2 1 0 ... 1 2 1 ... 0 1 2 ... ... ... 1 2 1 ... 0 1 2 You could do this by one-liner: [[(2 - abs(x - y)) if it > 0 else 0 for x in xrange(8)] for y in xrange(8)] ...but in reality you should write something like this: [[(lambda t: t if t > 0 else 0)(2 - abs(x - y)) for x in xrange(8)] for y in xrange(8)] or this [[(2 - abs(x - y)) if (2 - abs(x - y)) > 0 else 0 for x in xrange(8)] for y in xrange(8)] or even this def foo(x, y): if abs(x - y) == 0: return 2 elif abs(x - y) == 1: return 1 else: return 0 [[foo(x, y) for x in xrange(8)] for y in xrange(8)] It's not THAT matter, but it's just about readability and shortness in some cases. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
> if x in range(a, b): #wrong! > it feels so natural to check it that way, but we have to write > if a <= x <= b > I understand that it's not a big deal, but it would be awesome to have > some optimisations - it's clearly possible to detect things like that > "wrong" one and fix it in a bytecode. You can implement it yourself: class between(object): def __init__(self, a,b): super(crang, self).__init__() self.a=a self.b=b def __contains__(self, value): return self.a <= value <= self.b >>> 12.45 in between(-100,100) true But do you need a < x < b a <= x < b a <= x <= b or a < x <= b ? Sure, you could set a new parameter for this, but the normal way is not broken at all. Best -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Steven D'Aprano writes: > >> Not everything needs to be a one liner. If you need this, do it the > >> old- fashioned way: > >> > >> t = foo() > >> if not pred(t): t = default_value > > > > I already explained how to write it as a one-liner: > > > > t = (lambda y: y if pred(y) else default_value)(foo()) > > I didn't say it couldn't be written as a one-liner. I suggested that it > was better not to. Ahh. I misunderstood the first sentence above as dismissing the possibility. Sorry. I agree that it's not a /nice/ one-liner. ;-) > The costs of the one-liner are: > > * reduced readability; > * requires an increased level of knowledge of the reader ("what's lambda > do?"); > * runtime inefficiency (you create a function object, only to use it once > then throw it away). This last can be obviated by a clever compiler (which, in our case, we have not got). The second could be considered an advantage: it's educational! > The advantages? > > * one fewer line of code. > > In my experience, the obsessiveness in which some people look for one- > liners is far from helpful, and goes against the spirit of Python. This > isn't Perl :) Oh, I agree completely. On the other hand, it's just /fun/. Python is a fun language and using its features in playfully unusual ways is enjoyable; like a good pun in a natural language. Just as puns aren't always appropriate in written language, playful code isn't always appropriate either; but that doesn't mean it's never appropriate. (Java has no sense of humour. C++ does have, but it's a bit weird.) -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Thu, 18 Nov 2010 09:32:23 +, Mark Wooding wrote: [...] > You're wrong. Python evaluates these left-to-right, as I said. > Parentheses override operator associativity; they don't affect > evaluation order at all. Fair enough. I concede your point. [...] >> Not everything needs to be a one liner. If you need this, do it the >> old- fashioned way: >> >> t = foo() >> if not pred(t): t = default_value > > I already explained how to write it as a one-liner: > > t = (lambda y: y if pred(y) else default_value)(foo()) I didn't say it couldn't be written as a one-liner. I suggested that it was better not to. The costs of the one-liner are: * reduced readability; * requires an increased level of knowledge of the reader ("what's lambda do?"); * runtime inefficiency (you create a function object, only to use it once then throw it away). The advantages? * one fewer line of code. In my experience, the obsessiveness in which some people look for one- liners is far from helpful, and goes against the spirit of Python. This isn't Perl :) -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Steven D'Aprano writes: > On Wed, 17 Nov 2010 16:31:40 +, Mark Wooding wrote: > > > But I don't think that's the big problem with this proposal. The real > > problem is that it completely changes the evaluation rule for the > > conditional expression. (The evaluation rule is already pretty screwy: > > Python is consistently left-to-right -- except here.) > > Not quite... > > >>> 1+2*3 > 7 > >>> (1+2)*3 > 9 You're wrong. Python evaluates these left-to-right, as I said. Parentheses override operator associativity; they don't affect evaluation order at all. Consider: def say(x): print 'seen %s' % x return x print say(1) + say(2) * say(3) print (say(1) + say(2)) * say(3) Run this program and you get seen 1 seen 2 seen 3 7 seen 1 seen 2 seen 3 9 So definitely left-to-right. Translating into reverse-Polish, say with Dijkstra's shunting-yard algorithm, is enlightening: you get 1 2 3 * + for the first and 1 2 + 3 * for the second. This preserves evaluation order; indeed, this is a general property of the shunting-yard algorithm. Finally, I quote from the language reference (5.13 of the 2.5 version), just to show that (this time, at least) I'm not trying to impose unfamiliar terminology, and that Python is defined to behave like this and I'm not relying on implementation-specific details. Alas, it also highlights a genuine inconsistency, but one which might be considered tolerable. : 5.13 Evaluation order : = : : Python evaluates expressions from left to right. Notice that while : evaluating an assignment, the right-hand side is evaluated before the : left-hand side. : : In the following lines, expressions will be evaluated in the : arithmetic order of their suffixes: : : expr1, expr2, expr3, expr4 : (expr1, expr2, expr3, expr4) : {expr1: expr2, expr3: expr4} : expr1 + expr2 * (expr3 - expr4) : func(expr1, expr2, *expr3, **expr4) : expr3, expr4 = expr1, expr2 So the above example is /explicitly/ dealt with in the language reference, if only you'd cared to look. > Not everything needs to be a one liner. If you need this, do it the old- > fashioned way: > > t = foo() > if not pred(t): t = default_value I already explained how to write it as a one-liner: t = (lambda y: y if pred(y) else default_value)(foo()) -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Wed, 17 Nov 2010 16:31:40 +, Mark Wooding wrote: > But I don't think that's the big problem with this proposal. The real > problem is that it completely changes the evaluation rule for the > conditional expression. (The evaluation rule is already pretty screwy: > Python is consistently left-to-right -- except here.) Not quite... >>> 1+2*3 7 >>> (1+2)*3 9 But other than that, I agree with your analysis for why Python should not be changed to allow: t = foo() as v if pred(v) else default_value Not everything needs to be a one liner. If you need this, do it the old- fashioned way: t = foo() if not pred(t): t = default_value -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Christopher writes: > i don't like magic names. what about: > > t = foo() as v if pred(v) else default_value This is an improvement on `it'; anaphorics are useful in their place, but they don't seem to fit well with Python. But I don't think that's the big problem with this proposal. The real problem is that it completely changes the evaluation rule for the conditional expression. (The evaluation rule is already pretty screwy: Python is consistently left-to-right -- except here.) Evaluating a conditional expression starts in the middle, by evaluating the condition. If the condition is true, then it evaluates the consequent (to the left); otherwise it evaluates the alternative (to the right). Screwy, but tolerable. The proposal is to evaluate the /consequent/, stash it somewhere, evaluate the condition, and then either output the consequent which we evaluated earlier or the alternative which we must evaluate now. Of course, the implementation must be able to tell which of these evaluation rules to apply. The marker to look for is either `it' (original anaphoric proposal -- this is the real reason why `it' should be a reserved word: its presence radically alters the evaluation rule, so it ought to be a clear syntactic marker) or `as' (as suggested above). Elsewhere in the language, `as' is pretty consistent in what it does: it provides a name for a thing described elsewhere (a `with' context object, or an imported thing) -- but nothing else. It certainly doesn't suggest a change in the way anything else is evaluated. 1/x if x != 0 else None works for any numeric x; it'd be really surprising to me if 1/x as hunoz if x != 0 else None didn't. -1 on this one. -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Wed, 17 Nov 2010 10:18:51 -0500 Mel wrote: > Christopher wrote: > > >> ? Of course we can write it as > >> t = foo() if pred(foo()) else default_value > >> but here we have 2 foo() calls instead of one. Why can't we write > >> just something like this: > >> t = foo() if pred(it) else default_value > >> where "it" means "foo() value"? > > > > i don't like magic names. what about: > > > > t = foo() as v if pred(v) else default_value > > !! so: assignment inside an expression. > I like the idea of having an "as ... if" construct, though. :) /W -- To reach me via email, replace INVALID with the country code of my home country. But if you spam me, I'll be one sour Kraut. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Christopher wrote: >> ? Of course we can write it as >> t = foo() if pred(foo()) else default_value >> but here we have 2 foo() calls instead of one. Why can't we write just >> something like this: >> t = foo() if pred(it) else default_value >> where "it" means "foo() value"? > > i don't like magic names. what about: > > t = foo() as v if pred(v) else default_value !! so: assignment inside an expression. Mel. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
> ? Of course we can write it as > t = foo() if pred(foo()) else default_value > but here we have 2 foo() calls instead of one. Why can't we write just > something like this: > t = foo() if pred(it) else default_value > where "it" means "foo() value"? i don't like magic names. what about: t = foo() as v if pred(v) else default_value -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 14, 11:30 pm, alex23 wrote: > On Nov 15, 4:39 pm, Dmitry Groshev wrote: > > > if x in range(a, b): #wrong! > > Only in Python 3.x, it's perfectly valid in Python 2.x. To achieve the > same in Python 3.x, try: > > if x in list(range(a, b,)): # BUT SEE MY COMMENT BELOW > > > it feels so natural to check it that way, but we have to write > > if a <= x <= b > > I understand that it's not a big deal, but it would be awesome to have > > some optimisations - it's clearly possible to detect things like that > > "wrong" one and fix it in a bytecode. > > This seems more like a pessimisation to me: your range version > constructs a list just to do a single container check. That's a _lot_ > more cumbersome than two simple comparisons chained together. Also: testing for the membership of x in a set is NOT the same thing as testing using inequality operators. The inequality operators will return True for any FLOATING-POINT value within the range (a...b), but the set test will only return True for set members. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 2:39 am, Dmitry Groshev wrote: > Here are some proposals. They are quite useful at my opinion and I'm > interested for suggestions. It's all about some common patterns. > First of all: how many times do you write something like > t = foo() > t = t if pred(t) else default_value Never! [snip] > And the third. The more I use python the more I see how "natural" it > can be. By "natural" I mean the statements like this: > [x.strip() for x in reversed(foo)] > which looks almost like a natural language. But there is some > pitfalls: > if x in range(a, b): #wrong! This is true only if x is an integer such that a <= x < b > it feels so natural to check it that way, but we have to write > if a <= x <= b This is true if x is an integer OR a float. Two very different cases, deserving of different notation. André -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 11/16/2010 3:42 AM, Steven D'Aprano wrote: On Mon, 15 Nov 2010 22:40:00 -0700, Ian Kelly wrote: On 11/15/2010 10:26 PM, Steven D'Aprano wrote: t = foo()+bar()+baz() if pred(it) else baz()-foo()-bar() What does "it" mean here? "it" would mean the result of the expression foo()+bar()+baz(). What else could it mean? It could mean the last expression, baz(). Or the entire compound expression, foo()+bar()+baz(). Unless the precedence rules were to change, the three expressions in the example that are operated on by the ternary are these: 1. foo()+bar()+baz() 2. pred(it) 3. baz()-foo()-bar() So the antecedent would have to be one of those in order to make any sense at all, and obviously the only choice of those that would be useful is the first one. There are valid objections to the proposal, but the intended semantics seem perfectly clear. Fair point, my example was terrible and didn't show the point that was clear in my head. Mea culpa. How about this instead? t = foo()+it if pred(it) else bar() Should that be a SyntaxError, or is `it` a variable that holds its value from statement to statement? SyntaxError. Implementing this without making 'it' a keyword would be very sloppy, IMO. Another option would be to use a special variable named '__', similar to the variable '_' that the REPL uses to store the result of the last command. This might break some existing code, but probably not very much. Mostly it would just be confusing. t = (foo() if pred(it) else bar()) if cond(it) else baz() More problematic: t = foo() if pred(bar() if pred2(it) else str(it)) else bar() Does the first 'it' belong to the inner or outer ternary? Probably the inner one. What about the second 'it'? BTW, I frequently use "it" for iterators, and making "it" a reserved word would break a lot of my code. This would make me quite peeved. I do the same, and yes, it would make upgrading a real pain. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Mon, 15 Nov 2010 22:40:00 -0700, Ian Kelly wrote: > On 11/15/2010 10:26 PM, Steven D'Aprano wrote: >> t = foo()+bar()+baz() if pred(it) else baz()-foo()-bar() >> >> What does "it" mean here? > > "it" would mean the result of the expression foo()+bar()+baz(). What > else could it mean? It could mean the last expression, baz(). Or the entire compound expression, foo()+bar()+baz(). > There are valid objections to the proposal, but the > intended semantics seem perfectly clear. Fair point, my example was terrible and didn't show the point that was clear in my head. Mea culpa. How about this instead? t = foo()+it if pred(it) else bar() Should that be a SyntaxError, or is `it` a variable that holds its value from statement to statement? t = it t = (foo() if pred(it) else bar()) if cond(it) else baz() For what it's worth, Apple's defunct Hypertalk language had a couple of syntax elements very much like that. Hypertalk had a special variable, "it", which you used like this: get the number of cards put it into field "Card number" I trust I don't have to explain this? :) Hypertalk also had a special function, "the result", which worked something like this: ask "This is a dialog box. Please type your answer here:" put the result into field "Your answer" (or you could use "result()" instead). Both of these worked quite well with Hypertalk, particularly with it's focus on non-programmers, but they were designed into the language from the beginning. In Python they would be the proverbial round peg in a square hole. BTW, I frequently use "it" for iterators, and making "it" a reserved word would break a lot of my code. This would make me quite peeved. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 11/15/2010 10:26 PM, Steven D'Aprano wrote: t = foo()+bar()+baz() if pred(it) else baz()-foo()-bar() What does "it" mean here? "it" would mean the result of the expression foo()+bar()+baz(). What else could it mean? There are valid objections to the proposal, but the intended semantics seem perfectly clear. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Sun, 14 Nov 2010 22:39:05 -0800, Dmitry Groshev wrote: > Here are some proposals. They are quite useful at my opinion and I'm > interested for suggestions. It's all about some common patterns. First > of all: how many times do you write something like > t = foo() > t = t if pred(t) else default_value > ? Hardly ever. Not often enough to need special syntax for it. Of course we can write it as > t = foo() if pred(foo()) else default_value > but here we have 2 foo() calls instead of one. Why can't we write just > something like this: > t = foo() if pred(it) else default_value > where "it" means "foo() value"? t = foo()+bar()+baz() if pred(it) else baz()-foo()-bar() What does "it" mean here? > Second, I saw a lot of questions about using dot notation for a > "object-like" dictionaries and a lot of solutions like this: > class dotdict(dict): > def __getattr__(self, attr): > return self.get(attr, None) > __setattr__= dict.__setitem__ > __delattr__= dict.__delitem__ > why there isn't something like this in a standart library? Because dot notation for dictionaries is not something we should encourage. > And the > third. The more I use python the more I see how "natural" it can be. By > "natural" I mean the statements like this: > [x.strip() for x in reversed(foo)] > which looks almost like a natural language. But there is some pitfalls: > if x in range(a, b): #wrong! Why do you say it's wrong? It's perfectly correct: 1 in range(1, 10) => returns True 1.5 in range(1, 10) => returns False 5 in range(1, 10) => returns True 10 in range(1, 10) => returns False exactly as I expect for element testing in a half-open interval. So where's the problem? If you want interval testing, you need to perform an interval test, not an element test. > it feels so natural to check it that way, but we have to write > if a <= x <= b > I understand that it's not a big deal, but it would be awesome to have > some optimisations - it's clearly possible to detect things like that > "wrong" one and fix it in a bytecode. If I write: x in range(1, 10) how do you expect the compiler to read my mind and know if I want the half-open interval or the closed interval? -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 11/14/2010 11:30 PM, alex23 wrote: On Nov 15, 4:39 pm, Dmitry Groshev wrote: First of all: how many times do you write something like Second, I saw a lot of questions about using dot notation for a "object-like" dictionaries and a lot of solutions like this: class dotdict(dict): def __getattr__(self, attr): return self.get(attr, None) __setattr__= dict.__setitem__ __delattr__= dict.__delitem__ why there isn't something like this in a standart library? Personally, I like keeping object attribute references separate from dictionary item references. Right. This isn't JavaScript. If you need a "dict", use a "dict". Don't use attributes as named storage. It leads to problems. Functions and various built-in objects are in the attribute namespace, and this can lead to name clashes. Maybe security holes, if the attribute keys come from external input. There are also some restrictions on the syntax of attribute names, restrictions "dict" does not have. Remember, you can inherit from "dict", which allows you to write obj['abc'] which is almost as short as obj.abc but safer. John Nagle -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 2010, at 1:39 AM, Dmitry Groshev wrote: >if x in range(a, b): #wrong! > it feels so natural to check it that way, but we have to write >if a <= x <= b > I understand that it's not a big deal, but it would be awesome to have > some optimisations - it's clearly possible to detect things like that > "wrong" one and fix it in a bytecode. I don't think anyone has pointed this out, but these are *not* the same thing. observe: x=3 if x in range(1,10): print "yay!" if 1<=x<10: print "yay too!" x=3.2 if x in range(1,10): print "yay!" if 1<=x<10: print "yay too!" output: yay! yay too! yay too! bb -- Brian Blais bbl...@bryant.edu http://web.bryant.edu/~bblais http://bblais.blogspot.com/ -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 11/15/2010 1:39 AM, Dmitry Groshev wrote: Here are some proposals. They are quite useful at my opinion and I'm interested for suggestions. It's all about some common patterns. First of all: how many times do you write something like t = foo() t = t if pred(t) else default_value Never. t=t unbinds and rebinds 't' to the same object. A waste. Only rebind if needed. if not pred(t): t = default_value ? Of course we can write it as t = foo() if pred(foo()) else default_value but here we have 2 foo() calls instead of one. Why can't we write just something like this: t = foo() if pred(it) else default_value where "it" means "foo() value"? Too magical. I agree with most other comments. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On 11/15/2010 12:39 AM, Dmitry Groshev wrote: x in range optimisation I've often thought this would make a nice O(1)-test lookup on an xrange() generator. I don't have strong use-cases for it, but a bit of well-tested code in the standard library would save me from doing the math (along with its potential fenceposting and sign errors) the couple times I've reached for it. Using the x in list(xrange(...)) # or "range()" depending your version ends up with an O(n) lookup, though I suppose one could create a set() for O(1) lookups, but that still requires O(N) storage (where a mathematical lookup would involve O(1) storage *and* time) foo() if foo() else bar() This is usually indicative that you need to cache the object...something like etcc = expensive_to_calculate_constructor() result = foo(etcc) if test(etcc) else bar() That way, you cache the potentially-expensive calculation, indicate to other readers-of-your-code that it's potentially-expensive, and enforce the use of that cache to ensure that you don't duplicate the expensive op. -tkc -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Dmitry Groshev writes: > First of all: how many times do you write something like > t = foo() > t = t if pred(t) else default_value > ? Of course we can write it as > t = foo() if pred(foo()) else default_value > but here we have 2 foo() calls instead of one. Why can't we write just > something like this: > t = foo() if pred(it) else default_value > where "it" means "foo() value"? How about t = (lambda y: y if pred(y) else default_value)(foo(x)) You could even package the lambda into a named function if you get bored of typing or your aesthetic senses are offended. > And the third. The more I use python the more I see how "natural" it > can be. By "natural" I mean the statements like this: > [x.strip() for x in reversed(foo)] > which looks almost like a natural language. But there is some > pitfalls: > if x in range(a, b): #wrong! > it feels so natural to check it that way, but we have to write > if a <= x <= b This, I think, is your error. The test `x in range(a, b)' means the same as `a <= x < b' (only in Python 2 it builds a list and then throws it away again). Such half-open intervals turn out to be what you want most of the time, and I think you'll avoid many bugs if you embrace them rather than trying to cling to the fully-closed intervals above. Python very definitely made the right decision to use half-open intervals pervasively, e.g., for `rangeand 'in sequence slicing. It's a bad idea to fight against it. Advantages of half-open intervals [a, b): * The number of elements is exactly b - a; closed intervals contain an extra element which is often forgotten. * They compose and split nicely: if a <= c <= b then [a, b) is exactly the disjoint union of [a, c) and [c, b). * Sums over these intervals are often better behaved; indeed, there's a rather pretty analogy between sums on half-open intervals and definite integrals which is lost if you use closed intervals. (The above two observations are special cases of this one.) See Concrete Mathematics (Graham, Knuth, Patashnik) for more on this. * It's easy to express an empty interval. You can't do that if you work entirely with closed intervals, but empty sets are an important boundary case and it's annoying to have to handle them separately. -- [mdw] -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
Dmitry Groshev writes: > which looks almost like a natural language. But there is some > pitfalls: > if x in range(a, b): #wrong! > it feels so natural to check it that way, but we have to write > if a <= x <= b For the record, you have to write: if a <= x < b: Ranges are open on the ending side. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 12:03 pm, alex23 wrote: > On Nov 15, 5:50 pm, Dmitry Groshev wrote: > > > On Nov 15, 10:30 am, alex23 wrote: > > > Personally, I like keeping object attribute references separate from > > > dictionary item references. > > > Your Python doesn't - dot notation is just a sugar for __dict__ lookup > > with default metaclass. > > That's a gross oversimplification that tends towards wrong: > > >>> class C(object): > > ... def __init__(self): > ... self._x = None > ... @property > ... def x(self): return self._x > ... @x.setter > ... def x(self, val): self._x = val > ...>>> c = C() > >>> c.x = 1 > >>> c.x > 1 > >>> c.__dict__['x'] > > Traceback (most recent call last): > File "", line 1, in > KeyError: 'x' > > But my concern has _nothing_ to do with the implementation detail of > how objects hold attributes, it's solely over the clarity that comes > from being able to visually tell that something is an object vs a > dictionary. Oh, now I understand you. But this "dotdict" (or "bunch") things don't break anything. You still need to use it explicitly and it is very useful if you need to serialize some JSON data about some entities. s = """[{"name": "Jhon Doe", "age": "12"}, {"name": "Alice", "age": "23"}]""" t = map(dotdict, json.loads(s)) t[0] #{'age': '12', 'name': 'Jhon Doe'} t[0].age #'12' Of course you can do this with namedtuple, but in fact this isn't a tuple at all. It's a list of entities. > > > This seems more like a pessimisation to me: your range version > > > constructs a list just to do a single container check. That's a _lot_ > > > more cumbersome than two simple comparisons chained together. > > > By "wrong" I meant exactly this. I told about "compiler" optimisation > > of statements like this so it would not construct a list. > > So you want this: > > if x in range(1,10): > > ...to effectively emit the same bytecode as a chained comparison while > this: > > for x in range(1,10): > > ...produces a list/generator? > > Never going to happen. "Special cases aren't special enough to break > the rules." The standard form for chained comparisons can handle far > more complex expressions which your 'in' version could not: 0 <= min > <= max <= 100 I know about chained comparisons, thanks. It's not about them. It's about bytecode optimisation. But maybe you are right about "Special cases aren't special enough to break the rules". I kinda forgot that :) -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 5:50 pm, Dmitry Groshev wrote: > On Nov 15, 10:30 am, alex23 wrote: > > Personally, I like keeping object attribute references separate from > > dictionary item references. > > Your Python doesn't - dot notation is just a sugar for __dict__ lookup > with default metaclass. That's a gross oversimplification that tends towards wrong: >>> class C(object): ... def __init__(self): ... self._x = None ... @property ... def x(self): return self._x ... @x.setter ... def x(self, val): self._x = val ... >>> c = C() >>> c.x = 1 >>> c.x 1 >>> c.__dict__['x'] Traceback (most recent call last): File "", line 1, in KeyError: 'x' But my concern has _nothing_ to do with the implementation detail of how objects hold attributes, it's solely over the clarity that comes from being able to visually tell that something is an object vs a dictionary. > > This seems more like a pessimisation to me: your range version > > constructs a list just to do a single container check. That's a _lot_ > > more cumbersome than two simple comparisons chained together. > > By "wrong" I meant exactly this. I told about "compiler" optimisation > of statements like this so it would not construct a list. So you want this: if x in range(1,10): ...to effectively emit the same bytecode as a chained comparison while this: for x in range(1,10): ...produces a list/generator? Never going to happen. "Special cases aren't special enough to break the rules." The standard form for chained comparisons can handle far more complex expressions which your 'in' version could not: 0 <= min <= max <= 100 -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 10:30 am, alex23 wrote: > On Nov 15, 4:39 pm, Dmitry Groshev wrote: > > > First of all: how many times do you write something like > > t = foo() > > t = t if pred(t) else default_value > > ? Of course we can write it as > > t = foo() if pred(foo()) else default_value > > but here we have 2 foo() calls instead of one. Why can't we write just > > something like this: > > t = foo() if pred(it) else default_value > > where "it" means "foo() value"? > > Could you provide an actual use case for this. This seems weird to me: > you're creating an object, testing the object, then possibly throwing > it away and using a default instead. Are you sure you can't > restructure your code as such: > > t = foo(x) if else default Sure. Let's pretend you have some string foo and compiled regular expression bar. Naive code: t = bar.findall(foo) if len(t) < 3: t = [] Code with proposed syntactic sugar: t = bar.findall(foo) if len(it) > 2 else [] > > Second, I saw a lot of questions about using dot notation for a > > "object-like" dictionaries and a lot of solutions like this: > > class dotdict(dict): > > def __getattr__(self, attr): > > return self.get(attr, None) > > __setattr__= dict.__setitem__ > > __delattr__= dict.__delitem__ > > why there isn't something like this in a standart library? > > Personally, I like keeping object attribute references separate from > dictionary item references. Your Python doesn't - dot notation is just a sugar for __dict__ lookup with default metaclass. > This seems more like a pessimisation to me: your range version > constructs a list just to do a single container check. That's a _lot_ > more cumbersome than two simple comparisons chained together. By "wrong" I meant exactly this. I told about "compiler" optimisation of statements like this so it would not construct a list. -- http://mail.python.org/mailman/listinfo/python-list
Re: Some syntactic sugar proposals
On Nov 15, 5:30 pm, alex23 wrote: > t = foo(x) if else default This should read 'test' instead of 'text', sorry. -- http://mail.python.org/mailman/listinfo/python-list