Re: [Tutor] Passing functions as arguments to other functions
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
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
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
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
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
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
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