Nested Scopes and Lambdas - python

def funct():
x = 4
action = (lambda n: x ** n)
return action
x = funct()
print(x(2)) # prints 16
... I don't quite understand why 2 is assigned to n automatically?

n is the argument of the anonymous function returned by funct. An exactly equivalent defintion of funct is
def funct():
x = 4
def action(n):
return x ** n
return action
Does this form make any more sense?

It's not assigned "automatically": it's assigned very explicitly and non-automatically by your passing it as the actual argument corresponding to the n parameter. That complicated way to set x is almost identical (net of x.__name__ and other minor introspective details) to def x(n): return 4**n.

Related

Are functions and helper functions treated differently in python?

Over here, the main function is g(x) and the helper function is h(). I noticed I can get the output for g(3), simply by binding x=3 and then doing any of the three
print(g(x))
g(x)
z=g(x)
But on the other hand, I noticed h() is outputted only when I type "print(h())". Are my observations correct or did I make a mistake? And also what is the logic behind this weird discrimination?
I like to think of it this way. Usually, if you had a line like "5" or "x=5", python doesn't give an output of 5. But functions have been given a special feature where they are invoked in any of the 3 ways. It's only that this special feature is being 'withdrawn' in the case of helper functions
The code you have written is equivalent to this:
def g(x):
def h():
any_name_you_want = 'abc'
return any_name_you_want
x += 1
print("in g(x)", x)
print(h())
return x
You cannot assign to a non-local variable inside a function. When Python creates the namespace for h, x is local to h because the assignment requires python to add the namespace for x at runtime.
Hence your code is also equivalent to :
def g(x):
def h():
return 'abc'
x += 1
print("in g(x)", x)
print(h())
return x
To get a sense of what is happening, run the following and then read up on UnboundLocalError:
def g(x):
def h():
x = x
return x
x += 1
print("in g(x)", x)
print(h())
return x

How to package a sequence functions that act on parameter in order in Python

Imagine there are three functions, all them accept and return the same type args.
Normally, we can write it as fun3(fun2(fun1(args)), this can be say that a sequence function act on parameter in order, which likes one variety Higher-order functions "map".
You know in Mathematica, we can write this as fun3#fun2#fun1#args.
Now the question is that can we integrate fun3#fun2#fun1 as another fun without modifying their definition, so fun(args) can replace fun3(fun2(fun1(args)), this looks more elegant and concise.
def merge_steps(*fun_list):
def fun(arg):
result = arg
for f in fun_list:
result = f(result)
return result
return fun
def plus_one(arg):
return arg + 1
def double_it(arg):
return arg ** 2
def power_ten(arg):
return arg ** 10
combine1 = merge_steps(power_ten, plus_one, double_it)
combine2 = merge_steps(plus_one, power_ten, double_it)
combine1(3)
> 3486902500
or use lambda:
steps = [power_ten, plus_one, double_it]
reduce(lambda a, f: f(a), steps, 3)
> 3486902500
I think you can use Function Recursion in python to do this.
def function(args, times):
print(f"{times} Times - {args}")
if times > 0 :
function(args,times - 1)
function("test", 2)
Note: I just add times argument to not generate infinite loop.
I'm not certain I understand your question, but are you talking about function composition along these lines?
# Some single-argument functions to experiment with.
def double(x):
return 2 * x
def reciprocal(x):
return 1 / x
# Returns a new function that will execute multiple single-argument functions in order.
def compose(*funcs):
def g(x):
for f in funcs:
x = f(x)
return x
return g
# Demo.
double_recip_abs = compose(double, reciprocal, abs)
print(double_recip_abs(-2)) # 0.25
print(double_recip_abs(.1)) # 5.0

python callback function returning None

I have a simple class that adds 2 nos. Before adding 2 nos I pass a helper function that appends 2 zeros and passes the result.
When I try to print the add_nos.provide(append_zeros) it always shows None.
def append_zeros(x,y):
x = int(str(x) + '00' )
y = int(str(y) + '00')
print x+y
return x + y
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
callback(x,y)
add_nos = Add_Nos([(1,2),(3,4)])
print add_nos.provide(append_zeros)
The method add_nos.provide(self, callback) has no return statement, thus it returns nothing, which in python means that it returns None.
To avoid this, either add a return statement to provide() or simply call the method without print.
It's not entirely clear what you are trying to do, but provide does not return anything. In python, the default return type of any function is None, so implicitly printing add_nos.provide(append_zeros) will do the function call, and then return None behind the scenes.
One option you have is to return self.input_array:
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
callback(x,y)
return self.input_array
Note that you can also do for x, y in self.input_array: :)
Presumably, you actually want to be getting a new list out with the result of the computation. In this case, this is an excellent candidate for a list comprehension:
def provide(self,callback):
return [callback(x, y) for x, y in self.input_array]
This is a one-line equivalent of doing
def provide(self, callback):
ret = []
for x, y in self.input_array:
ret.append(callback(x, y))
return ret
You said:
I want the result to be 300 in the first instance and 700 in the
next instance, kind of generate a iterator object.
So you simply need to turn the .provide method into a generator, and then call it appropriately. Like this:
def append_zeros(x,y):
x = int(str(x) + '00')
y = int(str(y) + '00')
#print x+y
return x + y
class Add_Nos():
def __init__(self,input_array):
self.input_array = input_array
def provide(self,callback):
for each in self.input_array:
x,y = each
yield callback(x,y)
add_nos = Add_Nos([(1,2),(3,4)])
for t in add_nos.provide(append_zeros):
print t
output
300
700
That append_zeros function is a bit strange. Rather than converting the args to strings so you can append the zeros and then converting the results back to ints to do the arithmetic yu should simply multiply each arg by one hundred.
Also, you can make the .provide method a little more streamlined by using "splat" unpacking. And as tyteen4a03 mentioned, in Python 2 your Add_Nos class ought to inherit from object so that you get a new-style class instead of the deprecated old-style class. So here's another version with those changes; it produces the same output as the above code.
def append_zeros(x, y):
return x * 100 + y * 100
class Add_Nos(object):
def __init__(self, input_array):
self.input_array = input_array
def provide(self, callback):
for each in self.input_array:
yield callback(*each)
add_nos = Add_Nos([(1,2),(3,4)])
for t in add_nos.provide(append_zeros):
print t

Using a list from one function, inside another function python

I am new to python. This might be a simple question, but if I have many functions that are dependent on each other how would I access lists from one function to use in another.
So...
def function_1():
list_1=[]
def function_2():
list_2= [2*x for x in list_1]
def function_3():
list_3= [x * y for x, y in zip(list_1, list_2)]
That is not the exact code but that is the idea of my problem. I would just put them all together in one function but I need them to be separate.
The correct way to do this would be to use a class. A class is an object that has internal variables (in your case, the three lists), and methods (functions that can access the internal methods). So, this would be:
class Foo(object):
def __init__(self, data=None):
self.list_1 = data if not data is None else []
def function_2():
self.list_2 = [2 * x for x in self.list_1]
And so on. For calling it:
foo = Foo() # list_1 is empty
foo2 = Foo([1,2,3]) # list_1 is not empty
foo2.function_2()
print foo2.list_2
# prints [2, 4, 6]
Make them arguments and return values:
def function_1():
return []
def function_2(list_1):
return [2*x for x in list_1]
def function_3(list_1, list_2):
return [x * y for x, y in zip(list_1, list_2)]
(this suggests that function_1 isn't much worth having...)
The exact way will depend on exactly how you want things to work, but here is a simple example:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]
The key point is that functions do not generally just "do" things, they return things. If you have a value in one function that you want to use in another function, the first function should return that value. The second function should call the first function, and use its return value.
Functions are basically black boxes -- the outside world doesn't really know what goes on inside or what variables exist there. From the outside, other code only sees what goes in (the function's arguments) and what goes out (its return value).
So if your function computes some value that is to be used elsewhere, it should be returned as the result of the function.
E.g.,
def square(x):
return x * x
Takes a number, computes its square, and returns it.
Then you could do:
print(square(5))
and it will print 25.
So in your case you can return the lists and use them in the other functions, as the other answers showed:
def function_1():
return []
def function_2():
return [2*x for x in function_1()]
def function_3():
return [x * y for x, y in zip(function_1(), function_2())]

Referencing a class' method, not an instance's

I'm writing a function that exponentiates an object, i.e. given a and n, returns an. Since a needs not be a built-in type, the function accepts, as a keyword argument, a function to perform multiplications. If undefined, it defaults to the objects __mul__ method, i.e. the object itself is expected to have multiplication defined. That part is sort of easy:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
if mul is None :
mul = lambda x,y : x*y
The thing is that in the process of calculating an the are a lot of intermediate squarings, and there often are more efficient ways to compute them than simply multiplying the object by itself. It is easy to define another function that computes the square and pass it as another keyword argument, something like:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
The problem here comes if the function to square the object is not a standalone function, but is a method of the object being exponentiated, which would be a very reasonable thing to do. The only way of doing this I can think of is something like this:
import inspect
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
elif inspect.isfunction(sqr) == False : # if not a function, it is a string
sqr = lambda x : eval('x.'+sqr+'()')
It does work, but I find it an extremely unelegant way of doing things... My mastery of OOP is limited, but if there was a way to have sqr point to the class' function, not to an instance's one, then I could get away with something like sqr = lambda x : sqr(x), or maybe sqr = lambda x: x.sqr(). Can this be done? Is there any other more pythonic way?
You can call unbound methods with the instance as the first parameter:
class A(int):
def sqr(self):
return A(self*self)
sqr = A.sqr
a = A(5)
print sqr(a) # Prints 25
So in your case you don't actually need to do anything specific, just the following:
bin_pow(a, n, sqr=A.sqr)
Be aware that this is early binding, so if you have a subclass B that overrides sqr then still A.sqr is called. For late binding you can use a lambda at the callsite:
bin_pow(a, n, sqr=lambda x: x.sqr())
here's how I'd do it:
import operator
def bin_pow(a, n, **kwargs) :
pow_function = kwargs.pop('pow' ,None)
if pow_function is None:
pow_function = operator.pow
return pow_function(a, n)
That's the fastest way. See also object.__pow__ and the operator module documentations.
Now, to pass an object method you can pass it directly, no need to pass a string with the name. In fact, never use strings for this kind of thing, using the object directly is much better.
If you want the unbound method, you can pass it just as well:
class MyClass(object):
def mymethod(self, other):
return do_something_with_self_and_other
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
If you want the class method, so just pass it instead:
class MyClass(object):
#classmethod
def mymethod(cls, x, y):
return do_something_with_x_and_y
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
If you want to call the class's method, and not the (possibly overridden) instance's method, you can do
instance.__class__.method(instance)
instead of
instance.method()
I'm not sure though if that's what you want.
If I understand the design goals of the library function, you want to provide a library "power" function which will raise any object passed to it to the Nth power. But you also want to provide a "shortcut" for efficiency.
The design goals seem a little odd--Python already defines the mul method to allow the designer of a class to multiply it by an arbitrary value, and the pow method to allow the designer of a class to support raising it to a power. If I were building this, I'd expect and require the users to have a mul method, and I'd do something like this:
def bin_or_pow(a, x):
pow_func = getattr(a, '__pow__', None)
if pow_func is None:
def pow_func(n):
v = 1
for i in xrange(n):
v = a * v
return v
return pow_func(x)
That will let you do the following:
class Multable(object):
def __init__(self, x):
self.x = x
def __mul__(self, n):
print 'in mul'
n = getattr(n, 'x', n)
return type(self)(self.x * n)
class Powable(Multable):
def __pow__(self, n):
print 'in pow'
n = getattr(n, 'x', n)
return type(self)(self.x ** n)
print bin_or_pow(5, 3)
print
print bin_or_pow(Multable(5), 5).x
print
print bin_or_pow(Powable(5), 5).x
... and you get ...
125
in mul
in mul
in mul
in mul
in mul
3125
in pow
3125
I understand it's the sqr-bit at the end you want to fix. If so, I suggest getattr. Example:
class SquarableThingy:
def __init__(self, i):
self.i = i
def squarify(self):
return self.i**2
class MultipliableThingy:
def __init__(self, i):
self.i = i
def __mul__(self, other):
return self.i * other.i
x = SquarableThingy(3)
y = MultipliableThingy(4)
z = 5
sqr = 'squarify'
sqrFunX = getattr(x, sqr, lambda: x*x)
sqrFunY = getattr(y, sqr, lambda: y*y)
sqrFunZ = getattr(z, sqr, lambda: z*z)
assert sqrFunX() == 9
assert sqrFunY() == 16
assert sqrFunZ() == 25

Categories

Resources