<div dir="auto"><div>Thanks for answering each line. If someone wants "too long didn't read", just check my code at the paragraph "<span style="font-family:sans-serif">readlines is a toy example, but maybe the code would be more creative".</span></div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr">Le ven. 3 août 2018 à 03:07, Steven D'Aprano <<a href="mailto:steve@pearwood.info">steve@pearwood.info</a>> a écrit :<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thu, Aug 02, 2018 at 03:13:25PM +0200, Robert Vanden Eynde wrote:<br>
<br>
> This brings the discussion of variable assignement in Expression. Functional<br>
> programming community seems to be more interested in python.<br>
<br>
I'm not sure what you mean there. Your English grammar is just slightly <br>
off, enough to make your meaning unclear,</blockquote></div></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">sorry.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">When I say "functional programming", I speak about the paradigm used in language like Haskell. In language like those, all constructs are "expression-based". I consider the code "result = 5 if condition else 2" more "functional style" than "if condition: result = 5; else: result = 2". Functional style focus on the result, uses expressions. Imperative focus on the process, "we must do a condition, then we set the variable, else, we set a variable to something else".</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
<br>
> lines = (f.readlines() with open('hello') as f)<br>
<br>
readlines has the same problems as read, as I described earlier, and the <br>
same trivial three-line solution.<br>
<br>
<br>
> digit = (int('hello') except ValueError: 5)<br>
<br>
try...except exceptions have been proposed before and rejected.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I'm wondering why, that must have been the same reasons of not accepting "with".</div><div dir="auto"><br></div><div dir="auto">if condition:</div><div dir="auto"> something = x</div><div dir="auto">else:</div><div dir="auto"> something = y</div><div dir="auto"><br></div><div dir="auto">Can be refactored</div><div dir="auto"><br></div><div dir="auto">something = x if condition else y</div><div dir="auto"><br></div><div dir="auto">Or</div><div dir="auto"><br></div><div dir="auto">something = (x if condition else</div><div dir="auto"> y)</div><div dir="auto"><br></div><div dir="auto">But,</div><div dir="auto"><br></div><div dir="auto">try:</div><div dir="auto"> something = x</div><div dir="auto">except:</div><div dir="auto"> something = y</div><div dir="auto"><br></div><div dir="auto">Can't?</div><div dir="auto"><br></div><div dir="auto">The use cases seems similar.</div><div dir="auto"><br></div><div dir="auto">One can use the first form, using more of a imperative programming, or the second line, which is more "functional programming", more expressions oriented.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
> value = (x+y**2 where x,y = (2,4))<br>
<br>
A "where" *statement* is interesting, but this is not a good example of <br>
it. The above is better written in the normal syntax:<br>
<br>
value = 2 + 4**2</blockquote></div></div><div dir="auto"><br></div><div dir="auto">That's the discussion we had on the list called "variable assignement in expressions". What you did here is inlining the variables, technically it's not possible if you're calling a function and using the variable more than once.</div><div dir="auto"><br></div><div dir="auto">So we're really comparing it to :</div><div dir="auto"><br></div><div dir="auto">x,y = (2,4)</div><div dir="auto">value = x+y**2</div><div dir="auto"><br></div><div dir="auto">Or</div><div dir="auto"><br></div><div dir="auto">x = 2</div><div dir="auto">y = 4</div><div dir="auto">value = x+y**2</div><div dir="auto"><br></div><div dir="auto">Where the idea is to separate the steps of a computation, introducing temporary variables with a meaningful name is useful (And as mentioned, if a function is called and the variable reused, it's called once, but that's not the main point).</div><div dir="auto"><br></div><div dir="auto">In Haskell there is "value = (x = 2 in y = 4 in x+y**2)" or similar.</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">position = initial + speed * time</div><div dir="auto" style="font-family:sans-serif">position_inch = distance / 2.54</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">Vs</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif"><div dir="auto"><div dir="auto">position_inch = (initial + speed * time) / 2.54</div></div></div></div><div dir="auto"><br></div><div dir="auto">The programmer chooses what's more clear given the context and the audience.</div><div dir="auto"><br></div><div dir="auto">Or maybe he wants to emphasize that the code creates a position_inch variable usable in the code after ?</div><div dir="auto"><br></div><div dir="auto">Or both, he wants to explain how he computes position_inch using a temporary variable but doesn't want the rest of the code depend o "position" ?).</div><div dir="auto"><br></div><div dir="auto">Yes the del is generally useless, more about leaking below.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
no need to introduce temporary variables that exist only to obfuscate <br>
the code.<br>
<br>
<br>
> values = [x+y**2 for x in range(5) for y in range(7)]<br>
> values = [x+y**2 for x,y in product (range(5), range(7))]<br>
> y = 5 if condition else 2<br>
<br>
These already exist, because they are useful.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I see those as a refactoring of imperative programming style as well (values = []; for ...: values.append(...))</div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
> y = (lambda x: x+2)(x=5)<br>
<br>
This is not a good example of the use of a lambda. Better:<br>
<br>
y = 5 + 2<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Same thing as in the where syntax. However, some constructs are easier to refactor as </div><div dir="auto"><br></div><div dir="auto">def meaningfulname(x):</div><div dir="auto"> return x+2</div><div dir="auto"><br></div><div dir="auto">y = meaningfulname(5)</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Why bother writing a function with such a simple body if you are going <br>
to immediately call it on the spot? Unless the body is more complex, or <br>
you are going to call it elsewhere, or call it repeatedly, the lambda <br>
adds nothing.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Indeed, in complex expressions.</div><div dir="auto"><br></div><div dir="auto">Or if I want to separate the steps of a computation.</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">position = initial + speed * time</div><div dir="auto" style="font-family:sans-serif">position_inch = distance / 2.54</div></div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Nobody denies that *some* statements are well-suited and useful as <br>
expressions. The question is whether "with" is one of those.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I'm just pointing out those constructs are very similar, it kind of makes sense to compare them.</div><div dir="auto"><br></div><div dir="auto">Of course I don't know about real world examples that would simplify a code. But often as I'm a "expression first" guy</div><div dir="auto"><br></div><div dir="auto">I write:</div><div dir="auto"><br></div><div dir="auto">result = ...</div><div dir="auto"># code using result and that doesn't care about the temporary variable it uses.</div><div dir="auto"><br></div><div dir="auto">Then I figure how to compute result, without polluting the namespace. Again adding temporary variables before "result = ..." Is totally fine and that's the way to go in imperative programming.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
> with open('hello') as f:<br>
> lines = f.readlines()<br>
> del f # f is leaked !<br>
<br>
99% of the time, I would think that "del f" was a waste of time. If that <br>
code is in function, then f will be closed when the "with" block is <br>
exited, and garbage collected when the function returns.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Yes of course, but what if "f" was defined before? We lose its value, even if "f" was created only as a temporary variable to have the variables lines.</div><div dir="auto"><br></div><div dir="auto">Maybe it came from:</div><div dir="auto"><br></div><div dir="auto">lines = ...</div><div dir="auto"># code using lines</div><div dir="auto"><br></div><div dir="auto">Yes naming it "f" where one has a 'f' in the same block is confusing, yes it could be named "_". But maybe we are in a script and we have a lots of variables? That kind of questions arise, when we wanted a temporary variable.</div><div dir="auto"><br></div><div dir="auto">readlines is a toy example, but maybe the code would be more creative, something like :</div><div dir="auto"><br></div><div dir="auto">if condition:</div><div dir="auto"> filename = <span style="font-family:sans-serif">"session-{}-{}.txt".format(x, y*10)</span></div><div dir="auto"><span style="font-family:sans-serif">else:</span></div><div dir="auto"> filename = "<span style="font-family:sans-serif">data_{}_{}.txt".format(w, z)</span></div><div dir="auto"><span style="font-family:sans-serif"><br></span></div><div dir="auto">with open('hello') as f:</div><div dir="auto"> lines = [l.strip('\n') for l in f</div><div dir="auto"> if len(l) > 0</div><div dir="auto"> if not l.stri().startswith('#')]</div><div dir="auto"><br></div><div dir="auto">parsed_data = [</div><div dir="auto"> ... # list expression mapping lines</div><div dir="auto">]</div><div dir="auto"><br></div><div dir="auto">The extra indent seems a bit weird, opening a file is just a secondary effect of wanting to compute "lines = ..."</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif"><div dir="auto">filename = ("session-{}-{}.txt".format(x, y*10) if condition else</div><div dir="auto"> "data_{}_{}.txt".format(w,z))</div><div dir="auto"><br></div></div><div dir="auto" style="font-family:sans-serif"><div dir="auto">lines = ... # Implement that later</div><div dir="auto"><br></div><div dir="auto">parsed_data = [</div><div dir="auto"> ... # list expression mapping lines</div><div dir="auto">]</div><div dir="auto"><br></div><div dir="auto">To:</div></div></div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">filename = ("session-{}-{}.txt".format(x, y*10) if ... else</div><div dir="auto" style="font-family:sans-serif"> "data_{}_{}.txt".format(x, y))</div><div dir="auto" style="font-family:sans-serif"><br></div></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">lines = ([l.strip('\n') for l in f</div><div dir="auto" style="font-family:sans-serif"> if len(l) > 0</div><div dir="auto" style="font-family:sans-serif"> if not l.stri().startswith('#')] with open (filename) as f)</div><div dir="auto" style="font-family:sans-serif"><br></div><div dir="auto" style="font-family:sans-serif">parsed_data = [</div><div dir="auto" style="font-family:sans-serif"> ... # list expression mapping lines</div><div dir="auto" style="font-family:sans-serif">]</div><div dir="auto" style="font-family:sans-serif"><div dir="auto"><div dir="auto"><br></div><div dir="auto">The creator chose to keep exactly the three variables because they have a meaning, f is just an implementation detail. The creator wanted to emphasize that the code is simply:</div><div dir="auto"><br></div><div dir="auto">filename = ...</div><div dir="auto">lines = ...</div><div dir="auto">parsed_data = ...</div><div dir="auto"><br></div><div dir="auto">But the "..." being not so useful to have their own function.</div><div dir="auto"><br></div><div dir="auto">#Very verbose</div><div dir="auto">def compute_filename(x,y,w,z):</div><div dir="auto"> ...</div><div dir="auto">def compute_lines(..., filename):</div><div dir="auto"> ...</div><div dir="auto">def compute_parsed_data(..., lines, filename):</div><div dir="auto"> ...</div><div dir="auto"><div dir="auto">filename = compute_filename(...)</div><div dir="auto">lines = compute_lines(...)</div><div dir="auto">parsed_data = compute_parsed_data(...)</div><div dir="auto"><br></div><div dir="auto">The functions there should be anonymous, but lambda invoked directly are not very readable.</div></div></div></div></div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
If you are worried about the memory efficiency of one tiny closed file <br>
object, then Python is the wrong language for you.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Yes I don't talk about the "free" of C or "delete" of C++.</div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
If that code is in the top-level of a script, who cares about f? You <br>
surely don't delete all your variables when you are done with them:<br>
<br>
name = input("what is your name?")<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
print("Hello,", name)<br>
del name<br>
play_game()<br>
<br>
<br>
The only time I would explicitly delete f like you do above was if I was <br>
writing a library which specifically and explicitly supported the "from <br>
module import *" syntax, AND there were too many exportable names to <br>
list them all in __all__ by hand. Only in that very rare case would I <br>
care about tidying up the global namespace by using del.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Yes that's a good example of me not wanting to "pollute the namespace, not wanting to create simple functions, not wanting to indent sometimes, but wanting to have tempory variables".</div><div dir="auto"><br></div><div dir="auto">If someone reads the module to see its content, they look for all the lines at zero indent begining with 'something = ...' or 'def ...'</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
> x,y = 2,4<br>
> value = x+y**2<br>
> del x, y # x,y are leaked !<br>
<br>
If you are writing code like this, you are just obscuring the code. Much <br>
better to just use the values where you need them, not to invent <br>
unnecessary temporary variables that you don't need!<br>
<br>
value = 2 + 4**2<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Temporary variable has always been a choice to the programmer, they explain more the intermediary steps, but focus less on the final result.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
[...]<br>
> If we add one, it's Logical to add the others to be consistent.<br>
<br>
My car has round wheels. Since we use one shape (circle) for wheels, it <br>
must be "logical" to make wheels in all other shapes, to be consistent:<br>
<br>
- triangular wheels<br>
- square wheels<br>
<br>
etc. Consistency just for the sake of consistency is *not* a virtue. <br>
Unless those expression forms justify *themselves* on their own merits, <br>
it is just a waste of time and effort to let them sneak into the <br>
language "for consistency".<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I agree, that's why I said earlier "I didn't think so much about the use cases". But trust me, when I write code, I'm really often in "something = ..." Case. And sometimes the ... must depending on a try except, sometimes on a with, sometimes on other variables that are temporary.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
<br>
> Of course, one can always write functions like read_text but the ide of<br>
> those construction is like the lambda, we want anonymous.<br>
<br>
We can say:<br>
<br>
text = read('filename')<br>
<br>
text = f.read() with open('filename') as f<br>
<br>
and both are equally unanonymous (both use a named variable), or we can <br>
say:<br>
<br>
process(spam, eggs, read('filename'), foo, bar)<br>
<br>
process(spam, eggs, f.read with open('filename') as f, foo, bar)<br>
<br>
and both are equally anonymous.<br>
<br>
If Python had a built-in function "read", surely you wouldn't refuse to <br>
use it because it was a named function? We don't complain that map() and <br>
filter() are named functions and demand "anonymous" ways to do the same <br>
thing. A read function should be no different.<br>
<br>
The only point of difference is that it is not built-in, you have to <br>
write it yourself. But not every trivial three-line function must be <br>
built-in.<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Of course naming stuff is important (that's one of the reasons to build temporary variables).</div><div dir="auto"><br></div><div dir="auto">One difficultly of finding use cases, it that it's about changing the paradigm, probably all cases have a really readable implementation in current python / imperative style. But when I see:</div><div dir="auto"><br></div><div dir="auto">try:</div><div dir="auto"> a_variable = int(input("..."))</div><div dir="auto">except ValueError:</div><div dir="auto"> try:</div><div dir="auto"> a_variable = fetch_db()</div><div dir="auto"> except DbError:</div><div dir="auto"> a_variable = default</div><div dir="auto"><br></div><div dir="auto">I really think "why can't I put it one one line like I do with if".</div><div dir="auto"><br></div><div dir="auto"><div dir="auto" style="font-family:sans-serif">a_variable = (int(input("...")) except ValueError:</div><div dir="auto" style="font-family:sans-serif"> fetch_db() except DbError:</div><div dir="auto" style="font-family:sans-serif"> default)</div></div><div dir="auto"><br></div><div dir="auto">For "with", I'm just wondering "why do I have to indent, it will lose the focus of the reader on the result itself".</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote" dir="auto"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
-- <br>
Steve<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div></div></div>