Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread Ben Finney
boB Stepp  writes:

> I think this was my key point of confusion.  I was mistakenly thinking
> of f(x) as referring to the function object.

Right.

‘f’ is an expression, that Python resolves as whatever object ‘f’
references.

‘f(x)’ is an expression, that Python resolves by *calling* the object
referenced by ‘f’, and resolves to whatever object that call returns.

Both of them are expressions. ‘f’ is rightly termed a reference in both
of them. Only the first expression (the name ‘f’ alone) is reasonably
termed a reference.

> Instead, it is calling that object with argument x

I hope it will help for you to think in terms of “What value does this
expression resolve to?”

-- 
 \ “Alternative explanations are always welcome in science, if |
  `\   they are better and explain more. Alternative explanations that |
_o__) explain nothing are not welcome.” —Victor J. Stenger, 2001-11-05 |
Ben Finney

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


Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread boB Stepp
On Fri, Sep 30, 2016 at 6:55 AM, Steven D'Aprano  wrote:
> On Thu, Sep 29, 2016 at 09:43:57PM -0500, boB Stepp wrote:

>> But why does Python require
>> separating the function object from its parameters when it is being
>> passed as an argument to another function?
>
> If you pass the function arguments to the function *first*, then it gets
> evaluated before the second function gets to see it. Let's investigate:
>
> def g(*args):
> print("Calling function g with arguments {}".format(args))
> return 999
>
> def f(func, *args):
> print("f received first argument: {}".format(func))
> print("f received additional arguments: {}".format(args))
> return func(*args)
>
>
> Let's try it the right way:
>
> py> f(g, 1, 2, 3)
> f received first argument: 
> f received additional arguments: (1, 2, 3)
> Calling function g with arguments (1, 2, 3)
> 999
>
>
>
> And the wrong way:
>
> py> f(g(1, 2, 3))
> Calling function g with arguments (1, 2, 3)
> f received first argument: 999
> f received additional arguments: ()
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "", line 4, in f
> TypeError: 'int' object is not callable
>
>
>
> Does this help?

Yes.  Thanks, Steve!  Very helpful examples.



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


Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread boB Stepp
On Fri, Sep 30, 2016 at 3:43 AM, Alan Gauld via Tutor  wrote:
> On 30/09/16 03:43, boB Stepp wrote:
>
>> Also, I note that if I just type a function name without the
>> parentheses in the interpreter, I will get something like this:
>>
> def f():
>>pass
>>
> f
>> 
>>
>> So the impression I am getting is that a function name by itself (with
>> no parentheses) is the function *object*.
>
> No.
> The function name is just a name like any other name in Python

I understand this.  It gets tiring to be precise and say something
like, "So the impression I am getting is that a function name by
itself (with no parentheses) references the function object."  But I
probably should strive to be more precise in my writing as you
otherwise have to guess what I know and don't know.

>> But why does Python require separating the function object
>> from its parameters when it is being passed as an argument
>> to another function?
>
> g = f
>
> causes g to become a second reference to the function object
>
> g = f(x)
>
> causes g to become a reference to the result of calling
> the function object referred to by f, passing in the object
> referred to by x.
>
> The parentheses in this case are not there as a container
> of the object x they are there as an indication that f
> is being called.

I think this was my key point of confusion.  I was mistakenly thinking
of f(x) as referring to the function object.  Instead, it is calling
that object with argument x, which is two separate things.

> HTH

It does.  Thanks, Alan!

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


Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread Steven D'Aprano
On Fri, Sep 30, 2016 at 09:43:47AM +0100, Alan Gauld via Tutor wrote:
> On 30/09/16 03:43, boB Stepp wrote:
> 
> > Also, I note that if I just type a function name without the
> > parentheses in the interpreter, I will get something like this:
> > 
>  def f():
> >pass
> > 
>  f
> > 
> > 
> > So the impression I am getting is that a function name by itself (with
> > no parentheses) is the function *object*. 
> 
> No.
> The function name is just a name like any other name in Python

Alan's correct here -- functions aren't treated specially.

But in the same way that is you say:

x = 999
x

the bare `x` on its own returns the int object 999, so:

def func(): ...

func

the bare `func` on its own returns the function object called "func".

So in *that sense alone*, func without the parentheses is the function 
object.

[...]
> So in your example f is not the function object it is a
> reference to a function object.

You say tomahto, I say edible wolf peach:

http://recipes.howstuffworks.com/fresh-ideas/dinner-food-facts/tomato-called-a-love-apple.htm




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


Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread Steven D'Aprano
On Thu, Sep 29, 2016 at 09:43:57PM -0500, boB Stepp wrote:

> I believe I understand the barebone mechanics on how to do this.  But
> I do not understand the rationale of why Python does it the way it
> does.  Say
> 
> def f(g, *args):
> g(*args)

Right. This says:

- Define a function called "f", which takes one named parameter, "g",
  and collect any other arguments under the name "args".
- For the body of "f", simply call that argument "g" with all the other 
  arguments.

You probably want `return g(*args)` rather than just `g(*args)`.

 
> def g(*args):
> # Do something.
> 
> do_things = f(g, *args)


As it stands now, f() is a middle-man that adds nothing to the picture. 
In practice, to be worth calling f() rather than just calling g() 
directly, you would want it to do some sort of additional processing: 
either manipulate the arguments, or the result returned by g().


> is the outline of how I understand the mechanics of doing this.  But
> noob boB initially want to do instead:
> 
> def f(g(*args)):
> g(*args)
[...]
> which, of course, will give me a syntax error.

Of course. I'm not sure what you think a parameter called "g(*args)" 
even means.

When you write this:

def f(x):
return x+1

do you feel the need to write:

def f(x+1):
return x+1

instead? I expect not. Can you see how the two situations are 
equivalent? My example uses +1, your example uses "call the function 
with these arguments" instead, but the two are otherwise equivalent.

In common English, there is a simple name for the +1 part of x+1, 
namely "plus one" or "add one" or similar. But I don't know of any 
simple name for the `(*args)` part of `g(*args)`. "Call g with given 
arguments" perhaps, but that's not really simple. The situations are 
conceptually the same:

+ is a binary (two argument) operator that takes the object on the left, 
x, and the object on the right, 1, and adds them together;

() is an n-ary (n arguments) operator (or perhaps "pseudo-operator" if 
you prefer) that takes the object on the left, g, and the multiple 
arguments inside the brackets, *args, and applies the arguments to 
function g.


> Also, I note that if I just type a function name without the
> parentheses in the interpreter, I will get something like this:
> 
> >>> def f():
>pass
> 
> >>> f
> 
> 
> So the impression I am getting is that a function name by itself (with
> no parentheses) is the function *object*.

Correct.

> But why does Python require
> separating the function object from its parameters when it is being
> passed as an argument to another function?

If you pass the function arguments to the function *first*, then it gets 
evaluated before the second function gets to see it. Let's investigate:

def g(*args):
print("Calling function g with arguments {}".format(args))
return 999

def f(func, *args):
print("f received first argument: {}".format(func))
print("f received additional arguments: {}".format(args))
return func(*args)


Let's try it the right way:

py> f(g, 1, 2, 3)
f received first argument: 
f received additional arguments: (1, 2, 3)
Calling function g with arguments (1, 2, 3)
999



And the wrong way:

py> f(g(1, 2, 3))
Calling function g with arguments (1, 2, 3)
f received first argument: 999
f received additional arguments: ()
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 4, in f
TypeError: 'int' object is not callable



Does this help?



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


Re: [Tutor] Passing functions as arguments to other functions

2016-09-30 Thread Alan Gauld via Tutor
On 30/09/16 03:43, boB Stepp wrote:

> Also, I note that if I just type a function name without the
> parentheses in the interpreter, I will get something like this:
> 
 def f():
>pass
> 
 f
> 
> 
> So the impression I am getting is that a function name by itself (with
> no parentheses) is the function *object*. 

No.
The function name is just a name like any other name in Python

foo = 42
bar = lambda x: x**2

foo and bar are both names. foo refers to the integer object 42
and bar refers to the function object x**2.

But they are just names and we can reassign them at any
time to any other kind of object.

So in your example f is not the function object it is a
reference to a function object.

> But why does Python require separating the function object 
> from its parameters when it is being passed as an argument
> to another function?

g = f

causes g to become a second reference to the function object

g = f(x)

causes g to become a reference to the result of calling
the function object referred to by f, passing in the object
referred to by x.

The parentheses in this case are not there as a container
of the object x they are there as an indication that f
is being called.

Now let us assume that f doesn't care what kind of object
x is it would be perfectly possible to pass f itself as
an argument to f():

g = f(f)

The mechanism is exactly the same as before:
It causes g to become a reference to the result of calling
the function object referred to by f, passing in the object
referred to by f - a function object in this case.

and again if we do

g = f(f())

we apply the same rules. The argument to the outer f
is the result of calling the inner f() and g gets
the result of calling f with that inner result. The
parens after a function name cause that function to
be executed and its result to be returned.

So python is not doing anything different to the "normal"
case when passing functions. They are treated just like
any other function call parameter, as an object.

BTW You don't have to pass the arguments as separate values.
You could use globals(but please don't!) or you could create
local values inside the containing function, or even
read them from a user:

def do_op(aFunc):
x = int(input("type an integer: "))
return aFunc(x)

do_op(lambda x: x**2)

or

def process_3_and_4(aFunc):
return aFunc(3,4)

process_3_and_4(lambda x,y: x**y)

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] Passing functions as arguments to other functions

2016-09-29 Thread Ben Finney
boB Stepp  writes:

> So the impression I am getting is that a function name by itself (with
> no parentheses) is the function *object*.

Yes. The expression ‘func’ resolves to whatever object is referenced by
that name; if it's a function object, you get that object.

The expression ‘func(foo, bar)’ resolves to whatever object is returned
from *calling* the object ‘func’, with the arguments ‘foo, bar’.

> But why does Python require separating the function object from its
> parameters when it is being passed as an argument to another function?

You've already answered your question. An expression resolves to exactly
one object. Either you want the function object, or you want something
else.

In the case of ‘func(foo, bar)’ you will get exactly one object from
that expression. You won't get the ‘func’ object as well; you need a
different expression (the expression ‘func’) to get that.

If you want to talk about different objects at the same time, you need
multiple parameters in which to place those objects.

-- 
 \  “By instructing students how to learn, unlearn, and relearn, a |
  `\ powerful new dimension can be added to education.” —Alvin |
_o__)Toffler, _Future Shock_, 1970 |
Ben Finney

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