Re: [Tutor] Functional Programming in Python

2015-04-04 Thread Steven D'Aprano
On Sat, Apr 04, 2015 at 09:53:28PM -0400, WolfRage wrote:
> 
> So I was surprised I did not get more feedback on my abused coroutine, 
> maybe that is good or bad, not sure.

Perhaps people didn't understand it. Or see it :-)

> Any ways I am on to trying to make that coroutine act more like the 
> State Pattern from Gang of Four. And well reading this:
> http://gameprogrammingpatterns.com/state.html

Now you're fighting the paradigm. Functional programming works best for 
code that avoids side-effects. But changes of state are naturally a 
side-effect! I was sitting, now I am walking. It's still me, but my 
state is different.

Now of course you can emulate state changes using purely functional 
code, but its harder and less efficient.


> I am not sure how to do this:
> class Heroine
> {
> public:
>   virtual void handleInput(Input input)
>   {
> state_->handleInput(*this, input);
>   }
> 
>   virtual void update()
>   {
> state_->update(*this);
>   }
> 
>   // Other methods...
> private:
>   HeroineState* state_;
> };
> 
> (Pointing to the different classes. Since C++ has virtual methods but 
> Python does not?) in Python? Do I just reference the new method? Because 
> state_ will always be the correct object?

Hmmm, I'm not sure, but I think that we would say that *all* Python 
methods are virtual in C++ terms. They are all resolved at runtime.

There are a few ways we might do this in Python.

class Heroine:
def __init__(self):
self.state = "standing"  # Or use an Enum in Python 3.4

def jump(self):
if self.state == "standing":
self.state = "jumping"
...
elif self.state == "jumping":
pass

# Dispatch table of keys to actions.
KEYMAP = {'b': jump,
  'd': duck,
  'f': run,
  ...
 }

def handle_keypress(self, key):
method = self.KEYMAP.get(key, None)
if method:
method(self)


We look up the key press, and get a reference to the method itself, not 
the name of the method. (Or None.) We then call that method by providing 
self as the first argument. Nice and easy. It's so easy that I'm not 
sure if it's even worth discussing alternatives.

Another alternative might be to use delegation, or object composition. 
Give the Heroine class all the methods which don't change. For the 
methods which do change, create a separate FooState class for each 
state:

class JumpingState:
def jump(self):
pass

def duck(self):
...

class RunningState: 
...


class Heroine:
def __init__(self):
self.state = StandingState()

# Dispatch table of keys to method names.
KEYMAP = {'b': 'jump',
  'd': 'duck',
  'f': 'run',
  ...
 }

def handle_keypress(self, key):
name = self.KEYMAP.get(key, None)
if name:
newstate = getattr(self.state, name)()
if newstate:
self.state = newstate()


Methods of the state object can signal a change of state by returning 
the class representing the new state. Otherwise, they can return None to 
signal no change of state.

Here is how we might do this using inheritence instead of composition. 
Start with a base class and a bunch of default methods which 
conditionally raise:


class BaseHeroine:

def jump(self):
if self.__class__ is BaseHeroine:
raise RuntimeError

def run(self):
if self.__class__ is BaseHeroine:
raise RuntimeError

def duck(self):
if self.__class__ is BaseHeroine:
raise RuntimeError

# Dispatch table of keys to method names.
KEYMAP = {'b': 'jump',
  'd': 'duck',
  'f': 'run',
  ...
 }

def handle_keypress(self, key):
name = self.KEYMAP.get(key, None)
if name:
getattr(self.state, name)()


Now have a bunch of subclasses, one for each state. Override only the 
methods you need. (Remember, the default behaviour for each method is to 
do nothing, if called from a subclass. They only raise if called from 
the base class.)

class JumpHeroine(BaseHeroine):  ...

class StandHeroine(BaseHeroine):  ...

class RunHeroine(BaseHeroine): ...



Now create an instance, and set its state:

heroine = BaseHeroine()
heroine.__class__ = StandHeroine


State transitions are managed by *changing the instance's class*. 
Methods can do that themselves:

def spam(self):
self.__class__ = RunHeroine  # Don't instantiate the class.
print("Spam spam spam lovery spam")




Now, I haven't tested any of the above code, but here is a short and 
simple demonstration showing that it does work:


py> class X:
... def display(self):
... print("in X")
... def method(self):
... self.display()
... print(self, type(self), self.__class__)
...
py> class Y(X):
... def display(self):
.

Re: [Tutor] Functional Programming in Python

2015-04-04 Thread Dave Angel

On 04/04/2015 09:53 PM, WolfRage wrote:






(Pointing to the different classes. Since C++ has virtual methods but
Python does not?)


I'd say that all methods in Python are virtual, except for those which 
are classmethod or staticmethod.



--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Cameron Simpson

On 04Apr2015 22:45, boB Stepp  wrote:

On Sat, Apr 4, 2015 at 6:55 PM, Alan Gauld  wrote:

lambda : all([print('Hello lambda world!'), sys.exit()] )


Well, now I am curious as to why the "all" form evaluates BOTH
elements. Apparently it does not apply the short-circuit logic we have
been discussing, or it would stop evaluating after the print statement
return.  Why is that?


Because the list/tuple is constructed entirely before all() is called. All() 
operates only on the final values.


Cheers,
Cameron Simpson 

Yesterday, I was running a CNC plasma cutter that's controlled by Windows XP.
This is a machine that moves around a plasma torch that cuts thick steel
plate. �A "New Java update is available" window popped up while I was
working. �Not good. - John Nagle
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread boB Stepp
On Sat, Apr 4, 2015 at 6:55 PM, Alan Gauld  wrote:
> On 04/04/15 22:57, boB Stepp wrote:
>>
>> On Sat, Apr 4, 2015 at 3:35 PM, Alan Gauld 
>> wrote:
>>>
>>> He could have done it in various other ways too:
>>>
>>> eg.
>>> lambda : all(print('Hello lambda world!'), sys.exit() )
>>
>>
>> Is this what you meant? Because print will always return False. Or did
>> you actually mean:
>>
>> lambda: any(print('Hello lambda world!'), sys.exit())
>
>
> any() would be more obvious, but in my interpreter
> both any() and all() evaluate both functions before
> testing the results. At least they do once you
> fix the TypeError : they should be in a list/tuple...
>
> lambda : all([print('Hello lambda world!'), sys.exit()] )

Well, now I am curious as to why the "all" form evaluates BOTH
elements. Apparently it does not apply the short-circuit logic we have
been discussing, or it would stop evaluating after the print statement
return.  Why is that?

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Functional Programming in Python

2015-04-04 Thread Steven D'Aprano
On Thu, Apr 02, 2015 at 12:18:28PM -0400, WolfRage wrote:
> These are just some questions that I have regarding the topic of 
> Functional Programming. I am working towards a more functional approach 
> to programming but acknowledge that it is far from Functional, 
> especially since this is mostly impossible in Python.

You might like to read this:

https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming

I'm not sure whether I agree with the author, but it's worth reading.


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Steven D'Aprano
On Sun, Apr 05, 2015 at 12:55:16AM +0100, Alan Gauld wrote:
> On 04/04/15 22:57, boB Stepp wrote:
> >On Sat, Apr 4, 2015 at 3:35 PM, Alan Gauld  
> >wrote:
> >>He could have done it in various other ways too:
> >>
> >>eg.
> >>lambda : all(print('Hello lambda world!'), sys.exit() )
> >
> >Is this what you meant? Because print will always return False. Or did
> >you actually mean:
> >
> >lambda: any(print('Hello lambda world!'), sys.exit())
> 
> any() would be more obvious, but in my interpreter
> both any() and all() evaluate both functions before
> testing the results. At least they do once you
> fix the TypeError : they should be in a list/tuple...
> 
> lambda : all([print('Hello lambda world!'), sys.exit()] )


That's because the sys.exit() call leaves the interpreter because any() 
gets a chance to raise TypeError :-) Your code:

lambda: all(print('Hello lambda world!'), sys.exit())

is equivalent to this:

a = print('Hello lambda world!')
b = sys.exit()  # Goodbye cruel world!
all(a, b)  # this never gets called


so you could replace the call to all() with any(), or len(), or 
zxcvbnm() if you like, it makes no difference at all.

The moral equivalent of the original `or` trick would be something like 
this:

any(spam() for spam in [lambda: print("Hello lambda world!"), os.exit])

which now avoids calling os.exit until necessary. E.g. we might write a 
function which prints a message, then has a 50% chance of exiting:


any(spam() for spam in [lambda: print("Hello lambda world!"), 
lambda: random.random() > 0.5,
lambda: print("Goodbye cruel world!"),
os.exit]
)

will always print Hello, and fifty percent of the time will print 
Goodbye then exit, otherwise it will return True.


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Cameron Simpson

On 05Apr2015 03:34, Steven D'Aprano  wrote:

On Sat, Apr 04, 2015 at 11:49:08AM -0500, boB Stepp wrote:

widget = Button(None,
text='Hello event world!',
command=(lambda: print('Hello lambda world!') or sys.exit()))


That's either the most horrible misuse of lambda I've ever seen, or a
really cool and rather nifty trick. I'm not sure which :-)


I think it is misuse. When I need to run two functions like that I tend to use 
a tuple:


 lambda: (f1(), f2())

Since Python evaluates left to right, these functions are called f1 first, then 
f2.


Using "or" introduces a reliance on f1 returning a falsish value. Dodgy and 
unreliable. Not to mention conflating the supposed Boolean value computed by 
the expression with the program's purpose.


Like others, I agree it is generally better to define a function more normally 
and just name in instead of inlining a lambda. But sometimes (rarely) that 
makes for harder to read code structure (though easier to read function 
internals).


Anyway, faced with a desire to use a lambda here, I would choose a tuple.

Cheers,
Cameron Simpson 

This is my simple religion. There is no need for temples; no need for
complicated philosophy. Our own brain, our own heart is our temple; the
philosophy is kindness. - Dalai Lama
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Steven D'Aprano
On Sat, Apr 04, 2015 at 02:21:19PM -0500, boB Stepp wrote:

> To my mind, would:
> 
> def quit():
> print('Hello lambda world!')
> sys.exit()
> 
> and:
> 
> widget = Button(None, text='Hello event world!', command=quit)
> 
> be preferable Python style?

Hell yes!


Using `or` to run functions purely for their side-effects (in this case, 
printing and exiting) makes a nice trick, but I wouldn't use for real.

On the other hand, using `or` for its value is perfectly acceptable. 
E.g. one common idiom might be to iterate over something which might be 
None:

for value in maybe_list or []:
...


If `maybe_list` is a non-empty list, it is used; if it is an empty list, 
the second operand (also an empty list) is used, but that's okay since 
they are both empty lists; and if it is None, then the second operand is 
used instead. This is a reasonable idiom to use, and prior to Python 2.5 
it was the closest thing the language had to a "ternary if operator".

These days, the `or` idiom is less common except in old code or code 
that has to run on Python 2.4 or older. Instead, we might write:

for value in (maybe_list if maybe_list is not None else []):
...

I'm not entirely sure that's an improvement :-)

-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Functional Programming in Python

2015-04-04 Thread WolfRage


So I was surprised I did not get more feedback on my abused coroutine, 
maybe that is good or bad, not sure.
Any ways I am on to trying to make that coroutine act more like the 
State Pattern from Gang of Four. And well reading this:

http://gameprogrammingpatterns.com/state.html
I am not sure how to do this:
class Heroine
{
public:
  virtual void handleInput(Input input)
  {
state_->handleInput(*this, input);
  }

  virtual void update()
  {
state_->update(*this);
  }

  // Other methods...
private:
  HeroineState* state_;
};

(Pointing to the different classes. Since C++ has virtual methods but 
Python does not?) in Python? Do I just reference the new method? Because 
state_ will always be the correct object?

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Alan Gauld

On 04/04/15 22:57, boB Stepp wrote:

On Sat, Apr 4, 2015 at 3:35 PM, Alan Gauld  wrote:

He could have done it in various other ways too:

eg.
lambda : all(print('Hello lambda world!'), sys.exit() )


Is this what you meant? Because print will always return False. Or did
you actually mean:

lambda: any(print('Hello lambda world!'), sys.exit())


any() would be more obvious, but in my interpreter
both any() and all() evaluate both functions before
testing the results. At least they do once you
fix the TypeError : they should be in a list/tuple...

lambda : all([print('Hello lambda world!'), sys.exit()] )


So this is not unusual for Python. BTW, what are some of the other
languages where this type of expression might be commonly used?


It's sometimes used in Turbo Pascal/Delphi and also in Perl  (a lot!).
I think I've seen it used in PHP too.

HTH
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Mark Lawrence

On 04/04/2015 17:49, boB Stepp wrote:

Windows 7, Python 3.4.3

This code snippet is "Example 7-13" on page 383 from "Programming
Python, 4th ed." by Mark Lutz :

import sys
from tkinter import *

widget = Button(None,
 text='Hello event world!',
 command=(lambda: print('Hello lambda world!') or sys.exit()))
widget.pack()
widget.mainloop()

My question is about the lambda expression. The author states "...this
version uses an or operator to force two expressions to be run..."  I
am not understanding how 'or' causes this to happen. I guess I am
expecting the 'or' to result only in the print running without
executing sys.exit(). But that is not what happens--of course. I tried
substituting 'and' for 'or', but this results in only the print being
run! Obviously I have a significant misunderstanding of what is going
on.

Thanks!



The print function in Python 3 always returns None, which is a false 
value.  As we're talking 'or' here the second part wills always get run, 
hence in this case sys.exit() gets called.


I'd try the same thing by using your own function.

def myprint(mystr):
print(mystr)
return 0

Substitute print in the lambda with myprint and try it, then replace the 
'0' with a '1' and see what happens.


--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Dave Angel

On 04/04/2015 05:57 PM, boB Stepp wrote:

On Sat, Apr 4, 2015 at 3:35 PM, Alan Gauld  wrote:

He could have done it in various other ways too:

eg.
lambda : all(print('Hello lambda world!'), sys.exit() )


Is this what you meant? Because print will always return False. Or did
you actually mean:

lambda: any(print('Hello lambda world!'), sys.exit())


But the OR style is established as a kind of idiom,
not just in Python but several other languages too.


So this is not unusual for Python. BTW, what are some of the other
languages where this type of expression might be commonly used?




I don't think I've ever seen it used in Python.  But it's quite common 
in Perl scripts and bash scripts that I've seen.  In the case of bash, 
one might do something like:


 prog1   &&   prog2

and prog2 gets executed only if prog1 had a successful completion

--
DaveA
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread boB Stepp
On Sat, Apr 4, 2015 at 3:35 PM, Alan Gauld  wrote:
> He could have done it in various other ways too:
>
> eg.
> lambda : all(print('Hello lambda world!'), sys.exit() )

Is this what you meant? Because print will always return False. Or did
you actually mean:

lambda: any(print('Hello lambda world!'), sys.exit())

> But the OR style is established as a kind of idiom,
> not just in Python but several other languages too.

So this is not unusual for Python. BTW, what are some of the other
languages where this type of expression might be commonly used?


-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Alan Gauld

On 04/04/15 17:49, boB Stepp wrote:


widget = Button(None,
 text='Hello event world!',
 command=(lambda: print('Hello lambda world!') or sys.exit()))



am not understanding how 'or' causes this to happen. I guess I am
expecting the 'or' to result only in the print running without


This is explained in more detail in the functional programming
topic of my tutorial. It's called short circuit evaluation of
boolean expressions if you want to look it up on wikipedia
or elsewhere.

The short version is that to evaluate an OR Python looks at
the first expression and if its true it returns the result
 - since any single True expression makes the OR true too.

If the first expression is false-like (eg None returned from
a print() ) then it must evaluate the second expression to
be sure of the overall OR result.

So by putting a print() which returns None, first Lutz
ensures the second expression is also evaluated.

He could have done it in various other ways too:

eg.
lambda : all(print('Hello lambda world!'), sys.exit() )

But the OR style is established as a kind of idiom,
not just in Python but several other languages too.

HTH
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Danny Yoo
>
> To my mind, would:
>
> def quit():
> print('Hello lambda world!')
> sys.exit()
>
> and:
>
> widget = Button(None, text='Hello event world!', command=quit)
>
> be preferable Python style?
>

Yes, I'd prefer this much more, compared to  the original.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Request review: A DSL for scraping a web page

2015-04-04 Thread boB Stepp
On Thu, Apr 2, 2015 at 2:49 PM, Albert-Jan Roskam
 wrote:
>
> -
> On Thu, Apr 2, 2015 1:17 PM CEST Alan Gauld wrote:
>
>>On 02/04/15 12:09, Dave Angel wrote:
>>
>>> Ah, Jon Bentley (notice the extra 'e').  I should dig out my *Pearls
>>> books, and have a trip down memory lane.  I bet 95% of those are still
>>> useful, even if they refer to much earlier versions of language(s).
>>
>>Yes, the Pearls books should be required reading for all new programmers. The 
>>lessons are pretty timeless, it's only the
>>languages that change - and most of his examples seem to be
>>in a kind of pseudo Pascal dialect rather than real code anyway.
>>
>>I believe they've been re-released as a single volume now.
>
> Is this the book you are referring to?
> http://www.amazon.com/Programming-Pearls-2nd-Edition-Bentley/dp/0201657880

This thread inspired me to order both books from Amazon. The one
linked to above by Alan is an expanded and somewhat rewritten edition
of the original. It does NOT include "More Programming Pearls". I just
today received my copy of "Programming Pearls, 2nd ed."  To quote from
part of the author's preface of "Programming Pearls, 2nd ed.":

"To Readers of the First Edition

 I hope that your first response as you thumb through this edition
of the book is, 'This sure looks familiar.' A few minutes later, I
hope that you'll observe, 'I've never seen that before.'
 This version has the same focus as the first edition, but is set
in a larger context. Computing has grown substantially in important
areas such as databases, networking and user interfaces. Most
programmers should be familiar users of such technologies. At the
center of each of those areas, though, is a hard core of programming
problems. Those programs remain the theme of this book. This edition
of the book is a slightly larger fish in a much larger pond.
 ..."

HTH
-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread boB Stepp
On Sat, Apr 4, 2015 at 12:34 PM, Steven D'Aprano  wrote:
> On Sat, Apr 04, 2015 at 11:49:08AM -0500, boB Stepp wrote:
>> Windows 7, Python 3.4.3
>>
>> This code snippet is "Example 7-13" on page 383 from "Programming
>> Python, 4th ed." by Mark Lutz :
>>
>> import sys
>> from tkinter import *
>>
>> widget = Button(None,
>> text='Hello event world!',
>> command=(lambda: print('Hello lambda world!') or sys.exit()))
>
> o_O
>
> That's either the most horrible misuse of lambda I've ever seen, or a
> really cool and rather nifty trick. I'm not sure which :-)

Re-reading the paragraph relevant to Mr. Lutz's example, perhaps I
should quote the full paragraph:

"This code is a bit tricky because lambdas can contain only an
expression; to emulate the original script, this version uses an or
operator to force two expressions to be run (print works as the first,
because it's a function call in Python 3.X--we don't need to resort to
using sys.stdout directly)."

I think the key thought of the author here is he showing how to
rewrite an earlier example that explicitly defines a quit() function,
which both prints and then exits the program,  to using a lambda
expression. I don't think his intent is to say that the lambda
expression is to be preferred (Or is he?).

To my mind, would:

def quit():
print('Hello lambda world!')
sys.exit()

and:

widget = Button(None, text='Hello event world!', command=quit)

be preferable Python style?

boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread boB Stepp
On Sat, Apr 4, 2015 at 12:34 PM, Steven D'Aprano  wrote:
> On Sat, Apr 04, 2015 at 11:49:08AM -0500, boB Stepp wrote:
>> Windows 7, Python 3.4.3
>>
>> This code snippet is "Example 7-13" on page 383 from "Programming
>> Python, 4th ed." by Mark Lutz :
>>
>> import sys
>> from tkinter import *
>>
>> widget = Button(None,
>> text='Hello event world!',
>> command=(lambda: print('Hello lambda world!') or sys.exit()))
>
> o_O
>
> That's either the most horrible misuse of lambda I've ever seen, or a
> really cool and rather nifty trick. I'm not sure which :-)

Now that I have read (and hopefully understand) your entire response,
I am wondering the same thing in the sense that my understanding of
Python's intent is for clearly readable code and this usage isn't
clear without some thought (At least for me!).

>> widget.pack()
>> widget.mainloop()
>>
>> My question is about the lambda expression. The author states "...this
>> version uses an or operator to force two expressions to be run..."  I
>> am not understanding how 'or' causes this to happen. I guess I am
>> expecting the 'or' to result only in the print running without
>> executing sys.exit(). But that is not what happens--of course. I tried
>> substituting 'and' for 'or', but this results in only the print being
>> run! Obviously I have a significant misunderstanding of what is going
>> on.
>
>
> Both `or` and `and` are "short-circuit" operators. Here is a truth-table

I get and understand the short-circuit logic. This isn't what got me!

[...]

> expression unless needed. So this piece of code:
>
> print(msg) or sys.exit()
>
> runs like this:
>
> (1) Evaluate the expression on the left of the operator: print(msg).
> (2) That has the side-effect of printing the message, and returns
> the value None.

This was my 'gotcha'. I forgot (but knew) that print functions return
None. Perhaps this constant switching back and forth between using
Python 2 at work and Python 3 at home is addling my brain? Also, even
if I had recalled the return of None, I might have missed that the
"side-effect" still occurs, i.e., the actual printing.

[...]

> The `and` operator is similar, except the truth-table looks like this:
>
>
>|a = True   False
> ---+-
> b = True   |True   False
> False  |False  False

And of course since print returns None, the short-circuit evaluation
causes the sys.exit() never to be seen.

Even though I snipped out most of your very well-constructed examples,
Steve, I have to say, you have a knack for making things abundantly
clear! You tutor very well, indeed, and I am appreciative!


-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Use of "or" in a lambda expression

2015-04-04 Thread Steven D'Aprano
On Sat, Apr 04, 2015 at 11:49:08AM -0500, boB Stepp wrote:
> Windows 7, Python 3.4.3
> 
> This code snippet is "Example 7-13" on page 383 from "Programming
> Python, 4th ed." by Mark Lutz :
> 
> import sys
> from tkinter import *
> 
> widget = Button(None,
> text='Hello event world!',
> command=(lambda: print('Hello lambda world!') or sys.exit()))

o_O

That's either the most horrible misuse of lambda I've ever seen, or a 
really cool and rather nifty trick. I'm not sure which :-)


> widget.pack()
> widget.mainloop()
> 
> My question is about the lambda expression. The author states "...this
> version uses an or operator to force two expressions to be run..."  I
> am not understanding how 'or' causes this to happen. I guess I am
> expecting the 'or' to result only in the print running without
> executing sys.exit(). But that is not what happens--of course. I tried
> substituting 'and' for 'or', but this results in only the print being
> run! Obviously I have a significant misunderstanding of what is going
> on.


Both `or` and `and` are "short-circuit" operators. Here is a truth-table 
for `a or b`:

   |a = True   False
---+-
b = True   |True   True
False  |True   False


If `a` is true, then `a or b` is true, regardless of whether b is true 
or false. So we can say that if `a` is true, `a or b` returns `a`.

If `a` is false, then `a or b` returns true if, and only if, `b` is 
true; otherwise it returns false. So we can say that if `a` is false, 
then `a or b` returns `b`.

So we can define our own "or" function like this:

def or_ (a, b):
if a: return a
else: return b

Unlike this function version, the `or` operator doesn't evaluate the `b` 
expression unless needed. So this piece of code:

print(msg) or sys.exit()

runs like this:

(1) Evaluate the expression on the left of the operator: print(msg).
(2) That has the side-effect of printing the message, and returns
the value None.
(3) Is None a true value? If so, `or` can short-circuit, and return
it as its result.
(4) But None is a false value, so evaluate the expression on the
right of the operator: sys.exit()
(5) Which has the side-effect of exiting the interpreter.
(6) The `or` operator would now return the result of sys.exit(), 
if it had one; but it doesn't, since the interpreter has just 
exited.


A cleaner example might be this:


py> def true():
... print("calling true")
... return 23  # a true-ish value
...
py> def false():
... print("calling false")
... return 0  # a false-ish value
...
py> true() or false()  # only the left operand is evaluated
calling true
23
py> true() or true()
calling true
23
py> false() or true()  # both operands are evaluated
calling false
calling true
23
py> false() or false()
calling false
calling false
0


The `and` operator is similar, except the truth-table looks like this:


   |a = True   False
---+-
b = True   |True   False
False  |False  False


Again, the right-hand operand is only evaluated if it is needed. This 
lets us write code like this:

if mylist and mylist[0] == spam: eggs()


If mylist is empty, then `mylist and ...` doesn't even need to evaluate 
the right-hand operand, mylist[0] doesn't run and so does not fail. Only 
if mylist is a truthy value does mylist[0] run.


-- 
Steve
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Use of "or" in a lambda expression

2015-04-04 Thread boB Stepp
Windows 7, Python 3.4.3

This code snippet is "Example 7-13" on page 383 from "Programming
Python, 4th ed." by Mark Lutz :

import sys
from tkinter import *

widget = Button(None,
text='Hello event world!',
command=(lambda: print('Hello lambda world!') or sys.exit()))
widget.pack()
widget.mainloop()

My question is about the lambda expression. The author states "...this
version uses an or operator to force two expressions to be run..."  I
am not understanding how 'or' causes this to happen. I guess I am
expecting the 'or' to result only in the print running without
executing sys.exit(). But that is not what happens--of course. I tried
substituting 'and' for 'or', but this results in only the print being
run! Obviously I have a significant misunderstanding of what is going
on.

Thanks!

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Request review: A DSL for scraping a web page

2015-04-04 Thread Joe Farro
Joe Farro  gmail.com> writes:
> indentation doesn't (always) reflect the hierarchy of the data being 
> generated, which seems more clear.

Meant to say: 

However, the indentation doesn't (always) reflect the hierarchy of
the data being generated, which seems more clear **in the bs4
version**.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Request review: A DSL for scraping a web page

2015-04-04 Thread Joe Farro
Joe Farro  gmail.com> writes:

> 
> Thanks, Peter.
> 
> Peter Otten <__peter__  web.de> writes:
> 
> > Can you give a real-world example where your DSL is significantly cleaner 
> > than the corresponding code using bs4, or lxml.xpath, or lxml.objectify?

Peter, I worked up what I hope is a fairly representative example. It scrapes
metadata from the 10 newest web-scraping questions on stackoverflow.
It's done with bs4 and take.

https://github.com/tiffon/take-examples/tree/master/samples/stackoverflow

I've posted on the bs4 discussion group asking for feedback on the bs4
version to make sure it's up to snuff. (The post is in new-member
purgatory, at the moment.)

In my opinion, the fact that take lacks an ability to define sub-routines is
a brutal deficiency. (As compared to defining functions like
`get_poster_details()` and `get_comment_activity()` in the bs4 version.)

On the bright side, I do like that the indentation of the take templates
semi-reflect the structure of the HTML document. However, the
indentation doesn't (always) reflect the hierarchy of the data being 
generated, which seems more clear.

Feedback is definitely welcome.

Thanks again!

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor