Just started learning python and came across this
def f(g):
return g(2)
def square(x):
return x ** 2
print(f(square)) # which gives 4
How does inputting square into the f function equate to 4?
When you call a function, the value of the argument is assigned to the named parameter. The call
print(f(square))
can be thought of as "expanding" to
g = square
print(g(2))
Calling f(square) is square(2) which is 2**2 so 4
In python functions are first-class values, considered objects as anything else, hence you can pass them as parameters to another function.
In your case, you are "composing" f with g, which in turn has an invocation with fixed 2 inside f. In this sense, f is a function whose purpose is to feed 2 into another function, given as argument.
Knowing that g squares a number, it's easy to see how g(2) is 4, then f(g) will return 4.
Related
I am learning to program, and I had a question regarding the functions.
Basically because I should use arguments in functions if I can get all the result by doing everything in the function. What are the benefits? Is it good practice?
Sorry if the question is very basic.
Here an example using python:
num1,num2 = 2,3
def sum(a,b):
z= a+b
print(z)
sum(num1,num2)
def sum():
a,b = 2,3
z= a+b
print(z)
sum()
In theory, both functions do the same, but in which cases is it advisable to use arguments or not?
If you are going to be calling the function just once, we could say there is not benefit from it. Now, let's say you want to perform the same operation multiple times, but with different input data. Then, you see the improvement:
def sum(a, b):
z = a + b
print(z)
sum(1, 2)
sum(2, 3)
sum(4, 5)
would be better than:
z = 1 + 2
print(z)
z = 2 + 3
print(z)
z = 4 + 5
print(z)
It depends on the application of use. If it needs some dynamic content like in the first case
num1,num2 = 2,3
def sum(a,b):
z= a+b
print(z)
sum(num1,num2)
but if it is some basic content,
use the second one.
def sum():
a,b = 2,3
z= a+b
print(z)
sum()
The main benefit of adding arguments to a function is that you can use the function multiple times with different arguments every time.
This can be very practical when you are building a calculator program, for example, and want to be able to find the sum of any two numbers not only of specific ones.
p.s.: If you want to use the functionality of your function only once, maybe you should consider not using a function at all (unless you need to find the sum of specific numbers a few times, in which case, as said, you wouldn't use arguments)
The problem is, if I define a function in python with 3 parameters and then I input only 2 parameters, I will get an error.
Can I define the function so if there is one parameter missing (user has given 2 inputs instead of 3), it will use a default value for that missing parameter such as 0?
def sum(a, b, c):
return a+b+c
If I use:
add = sum(1, 2)
print(add)
It will give me an error. Now I want to define the function so it will add the missing value as 0, but if I give all the 3 values, it will not use 0 as a default value.
you can use default parameters:
def my_sum(a, b, c=0):
return a + b + c
When defining the defining a function if you set a value to a parameter, then you are tellign the function to use that value as default, except a value is specified.
This means that by setting a=0,b=0,c=0 AS #Olvin Roght said, you will by default pass a 0 to those parameters (hence not affecting your sum) unless something else is specified.
Example:
def sum(a=0, b=0, c=0):
return a+b+c
Output:
print(sum(a=1,b=2))
3 #1+2+0
print(sum(a=1,b=2,c=3))
6 #1+2+3
print(sum())
0 #0+0+0
I have come across this example from Python hitchhikers guide:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
The example above is the solution to some issues caused with late binding, where variables used in closures are looked up at the time the inner function is called.
What does the i=i mean and why is it making such difference?
It's actually not just for lambdas; any function that takes default parameters will use the same syntax. For example
def my_range(start, end, increment=1):
ans = []
while start < end:
ans.append(start)
start += increment
return ans
(This is not actually how range works, I just thought it would be a simple example to understand). In this case, you can call my_range(5,10) and you will get [5,6,7,8,9]. But you can also call my_range(5,10,increment=2), which will give you [5, 7, 9].
You can get some surprising results with default arguments. As this excellent post describes, the argument is bound at function definition, not at function invocation as you might expect. That causes some strange behavior, but it actually helps us here. Consider the incorrect code provided in your link:
def create_multipliers():
return [lambda x : i * x for i in range(5)]
for multiplier in create_multipliers():
print multiplier(2)
When you call multiplier(2), what is it actually doing? It's taking your input parameter, 2, and returning i * 2. But what is i? The function doesn't have any variable called i in its own scope, so it checks the surrounding scope. In the surrounding scope, the value of i is just whatever value you left it -- in this case 4. So every function gives you 8.
On the other hand, if you provide a default parameter, the function has a variable called i in its own scope. What's the value of i? Well, you didn't provide one, so it uses its default value, which was bound when the function was defined. And when the function was defined, i had a different value for each of the functions in your list!
It is a bit confusing that they've used the same name for the parameter variable as they did for the iterating variable. I suspect you could get the same result with greater readability with
def create_multipliers():
return [(lambda x, y=i: y*x) for i in range(5)]
In that case, each number in the range, will be assigned to the optional parameters of each lambda function:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]
lambda x, i=0
lambda x, i=1
lambda x, i=2
lambda x, i=3
lambda x, i=4
So, you can call the functions now with one parameter (because they already have the default)
for f in create_multipliers():
print(f(3))
0
3
6
9
12
Or you can call the function and give the parameter you want, that's why is optional
for f in create_multipliers():
print(f(3,2))
6
6
6
6
6
There are examples where optional parameter are needed, such as recursion
For example, square in terms of square:
square = lambda n, m=0: 0 if n==m else n+square(n,m+1)
Look that the optional parameter there is used as accumulator
I'm new to programming.
def start():
x = 4
def addition():
n = 3
def exponential():
z = 2
def multiplication():
l = 2
print(x + n ** z * l)
return multiplication
equals = start()
equals()
why am I getting a "Nonetype" object is not callable error?
You're confusing a bunch of programming concepts:
Don't declare a function whenever you only need a statement
You're confusing function declaration with function call (invocation), and also the nesting is pointless. Declaring nested fn2 inside of fn1 doesn't magically also call fn2 and also transmit its return-value back to fn1. You still have to use an explicit return-statement from each fn.(If you forget that, you're implicitly returning None, which is almost surely not what you want)
For now, just don't ever nest functions at all.
Functions with no arguments are essentially useless, they can't take inputs and compute a result. Figure out what their arguments should be.
Specifically for the code you posted, addition(), multiplication() don't have any return value at all, i.e. None. exponential() returns multiplication, i.e. a function which only returns None. But then, both addition() and start() ignore that anyway, since they don't have a return-statement either, hence they implicitly return None.
Calling start() just gives you None, so you're just assigning equals = None. Not the result of some mathematical expression like you intended.
So:
reduce every unnecessary function to just a statement
declare each of your functions separately (non-nested)
each fn must have args (in this case at least two args, to make any sense)
each fn must have a return statement returning some value
only declaring a function and never calling it means it never gets run.
put an empty line in between function declarations (Then it's obvious if you forgot the return-statement)
Credits goes to #BrenBarn for being first to answer this. But I wanna post the code to make it more clear, and point out to some ways to make it better.
def start():
x = 4
def addition():
n = 3
def exponential():
z = 2
def multiplication():
l = 2
print (x + n ** z * l)
return multiplication()
return exponential()
return addition()
equals = start()
print equals #Output: 22
However, this is not the best way to list different methods. You should learn how to use a class in your python code.
I am going to define a class called "mathOperations". I will define three methods (functions): addition,exponential, multiplication. These functions are reusable.
class mathOperations():
def addition(self,x,y):
return x+y
def exponential(self,x,y):
return x**y
def multiplication(self,x,y):
return x*y
m= mathOperations()
z=2
l=2
x=4
n=3
result= m.addition(x,m.multiplication(m.exponential(n,z),l))
print result #Output:22
You should learn how to make your code reusable, try to google "procedural programming"; "Oriented Object Programming", or check "Learn Python the hard way" book. These are first and most used approach to make your code reusable. Think of it like a generic mathematical function to solve problems.
I saw this example in a Python book, which showcases how to use a function as an argument to another function:
def diff2(f, x, h=1E-6):
r = (f(x-h) - 2*f(x) + f(x+h))/float(h*h)
return r
def g(t):
return t**(-6)
t = 1.2
d2g = diff2(g, t)
print d2g
My question is, how does this script work without providing an argument to function g? The line in question is:
d2g = diff2(g,t)
Shouldn't it be done like:
d2g = diff2(g(t), t)
g is passed as an argument to diff2. In diff2, that argument is called f, so inside diff2 the name f refers to the function g. When diff2 calls f(x-h) (and the other calls it does), it is calling g, and providing the argument.
In other words, when you do diff2(g, t), you are telling diff2 that g is the function to call. The arguments to g are provided in diff2:
f(x-h) # calls g with x-h as the argument
f(x) # calls g with x as the argument
f(x+h) # calls g with x+h as the argument
If you called diff2(g(t), t), you would be passing the result of g(1.2) as the argument. g would be called before calling diff2, and diff2 would then fail when it tries to call f, because f would be a number (the value g(1.2)) instead of a function.
The functions in question are rather random, and perhaps difficult to understand. Let's consider a simple example, a function sum which takes two numbers a and b, and returns their sum. Actually, we can easily define another function prod, which returns their product too.
def sum(a,b):
return a + b
def prod(a,b):
return a * b
Let's say we have another function compute, which takes as its arguments the operation (a function), and two operands (two numbers to call the function on). In compute, we call the given operation on the arguments.
def compute(fn, a, b):
return fn(a, b)
We can compute different things. We can compute the sum of two numbers:
compute(sum, 1, 3)
We can compute the product of two numbers:
compute(prod, 1, 3)
Basically, without parentheses after the function name, we're not actually calling the function, it's just another object in the namespace (which happens to be a function which we can call). We don't call the function until inside of compute, when we do fn(a,b).
Let's see what the console outputs look like:
>>> compute(sum,1,3)
4
>>> compute(prod,1,3)
3
>>> sum
<function sum at mem-address>
>>> prod
<function prod at mem-address>
>>> sum(1,2)
3