6 ms·
It's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally. I actually
by neutronicus 16y ago
It's easy to read. You can determine how to interpret something—a string, a list, a function call, a definition—just by looking at the code locally.
I actually find that Lisp scores some local-readability points over Python in a few cases, mainly because Lisp is more explicit about scope, e.g.
(let ((a (something))
(b (other-thing))
(frobnicate a b))
...other code
versus
a = something()
b = other_thing()
frobnicate(a, b)
...other code
is more explicit about the intended lifetimes and consumers of the data "a" and "b". Lisp also has the "with a = (blah)" keyword for "loop" so the assignment can be made specifically in the context of loop preparation.
All in all I'm actually happier with my ability to signal my intent (and gauge other programmers' intent) in Lisp than I am in Python.
- Locke1689 16y agoPython is explicit about scope by using the same indentation block. I can glance at python code and immediately tell what the scope is because it's in the same indentation block (removing for the moment things like the global keyword, which tend not to be a problem in practice).
- neutronicus 16y agoCan you increase indentation arbitrarily, though? Like, say I want to initialize some data for a loop, that I wouldn't need later, could I: main_scope_stuff() c = create_context() for foo in foos: do_something(foo, c) do_other_thing(foo, c) accumulate(foos, c) more_main_scope_stuff() to emphasize that c was only important to the loop and the call to "accumulate"?
- Locke1689 16y agoOf course it's possible to increase indentation arbitrarily: simply create a new function. Any programmer should know that too many immediate levels of lexical context is bound to confuse the reader anyway. I'm not really sure what you're trying to show with that code, though. Is your objection that every do_ function is requiring a context? Edit: I see what the parent was saying now, see bottom comment. Also, see StavrosK's comment if you're fine using Python 2.5 (released 2006).
- neutronicus 16y agoI want to communicate, using indentation, that more_main_scope_stuff() and subsequent code do not depend on c. c is conceptually part of the loop, and not of the surrounding code. (Like the initialization statement in C/C++). The code I wrote does this (because c is 1 indentation level deeper than the main_scope functions). I do not know if it is legal Python to simply increase indentation level to demarcate a new scope, but I suspect it is not, and it is certainly not common practice. This is really a minor gripe - but then again so are the article's - it's pretty easy to tell a binding from a function call.
- Locke1689 16y agoAh, I see -- this is a really good point, thanks for bringing it up. You're right, one can not arbitrarily increase scope in Python. The most common way I've seen of demarcating this kind of structure is actually using a blank line. For example, the code would instead look more like: c = create_context() for foo in foos: do_something(foo, c) do_other_thing(foo, c) accumulate(foos, c) do_other_stuff One could also throw the separate stuff into a new function.
- neutronicus 16y agoOne could also throw the separate stuff into a new function. That's the elephant in the room in all of these "my language is more readable" discussions, isn't it?
- euccastro 16y agoTo be fair, that's what Lisp's let is syntactic sugar for, too.
- deleted 16y ago[deleted]
- StavrosK 16y agoYes: main_scope_stuff() with create_context() as c: for foo in foos: do_something(foo, c) do_other_thing(foo, c) accumulate(foos, c) more_main_scope_stuff() That signifies that "c" isn't supposed to be available after scope of the "with" statement. The variable will still be bound, but conceptually it's unavailable, since it's not supposed to be used. Also, the object in create_context() needs to support being called like that (i.e. it should contain __enter__ and __exit__ methods).
- euccastro 16y ago> The variable will still be bound, but conceptually it's unavailable, since it's not supposed to be used. Which, in all fairness, is the same as saying that this does not indeed create a new scope. If you're going to rely on convention, you might as well dispense with the 'with' statement at all and use blank lines. An explicit and safe (if not very elegant) way to put a variable out of scope is just deleting it after you're done with it: main_scope_stuff() if True: # Let's say we _really_ want indentation here.. c = create_context() for foo in foos: do_something(foo, c) do_other_thing(foo, c) accumulate(foos, c) del c # something_or_other(c) <--- raises UnboundLocalError more_main_scope_stuff() That said, if it got to the point of going to this trouble I'd just make a nested function instead.
- neutronicus 16y agoThat's nice, I didn't know about that, thanks. I'll definitely be using it the next time I have to use Python. It's a little bit unsatisfying, since all of the context has to be wrapped in a single object, but that does cover a common class of Lisp macro use cases.
- deleted 16y ago[deleted]
- sausagefeet 16y agoThis isn't true, consider: if 1 < 2: c = 2 else: c = 3 print c (I'm retarded and don't know how to do comments that have new lines in the, but hopefully you catch the drift. The 'print c' is at 0 indentation)
- euccastro 16y agoAdd at least two spaces at the beginning of each line and it will be treated as a preformatted block. What you try to do is not legal Python. The else clause can't go in the same line. I get your point, though. Python's scope is not in terms of literally 'indentation' blocks. Scope units are: module toplevel, and (possibly nested) function and class definitions. To create a new scope you create a new function. This is what Lisp does too (you can define let as a macro over lambda). I have oscillated between liking either way better and at present I find Python's sloppier way more practical.
- sausagefeet 16y agoFixed, thank you for the tip. Yeah the point I was showing was that the 'c' exists after the if or else, showing that scope is not bound to indentation level. On the subject of scope, this behavior has gotten me a few times (I find it unintuitive although I understand why it works this way): x = 2 f = lambda : x print f() x = 3 print f()
- euccastro 16y agoYes, the first assignment works as a Scheme 'define', and all subsequent ones as 'set!'s. The whole function/class/module is a monolithic scope, inherited/superseded/extended by functions and classes defined within.