How to simplify several functions with the same purpose - python

Let's say I have several functions that basically do the same thing but on a set of different variables. I think about something like that:
def changex():
if x:
# do procedure1 with x as variable
else:
# do procedure2 with x as variable
def changey():
if y:
# do procedure1 with y as variable
else:
# do procedure2 with y as variable
def changez():
...
How can I simplify that set of functions, such that I only have to write the function once but it does the job for all variables? I already looked into decorators which I think can do the job, but I can't make out how to make it work for my purpose.

Functions can accept variables as parameters.
Something like this:
def change(p):
if p:
# do procedure1 with p as variable
else:
# do procedure2 with p as variable
Then changex() becomes change(x); changey() becomes change(y) etc.

Decorators are way too complex for what you are trying to do. Functions can take arguments, so you can pass in the variable you want to do stuff with:
def change(var):
if var:
procedure1(var)
else:
procedure2(var)
Notice that I used if/else instead of checking both conditions with an if. I also recommend not testing explicitly against True/False. If you must do so, however, it is considered better practice to use is instead of == since True and False are singleton objects in Python: if x is True is better than if x == True.

Related

python lambda evaluate expression

I am trying out lambda in python and came across this question:
def foo(y):
return lambda x: x(x(y))
def bar(x):
return lambda y: x(y)
print((bar)(bar)(foo)(2)(lambda x:x+1))
can someone explain/breakdown how this code works? I am having problems trying to figure out what is x and y.
Lambda functions are just functions. They're almost syntatic sugar, as you can think of this structure:
anony_mouse = lambda x: x # don't actually assign lambdas
as equivalent to this structure:
def anony_mouse(x):
return x
(Almost, as there is no other way of getting a function without assigning it to some variable, and the syntax prevents you doing some things with them, such as using multiple lines.)
Thus let's write out the top example using standard function notation:
def foo(y):
# note that y exists here
def baz(x):
return x(x(y))
return baz
So we have a factory function, which generates a function which... expects to be called with a function (x), and returns x(x(arg_to_factory_function)). Consider:
>>> def add_six(x):
return x + 6
>>> bazzer = foo(3)
>>> bazzer(add_six) # add_six(add_six(3)) = 6+(6+3)
I could go on, but does that make it clearer?
Incidentally that code is horrible, and almost makes me agree with Guido that lambdas are bad.
The 1st ‘(bar)’ is equal to just ‘bar’ so it is an ordinary function call, the 2nd — argument to that call, i.e. bar(bar) — substitute ‘x’ to ‘bar’ there any you will get what is result of bar(bar); the’(foo)’ argument passing to the result of bar(bar) it will be a lambda-function with some arg. — substitute it to ‘foo’ and get result and so on until you reach the end of expression
I slightly modify your original function to make clearer what's going on (so it should be clearer which parameter is callable!)
# given a function it evaluates it at value p
def eval(func): # your foo
return lambda p: func(p)
# given a value p perform a double composition of the function at this value (2-step recursion)
def iter_2(p): # your bar
return lambda func: func(func(p))
increment = lambda x: x + 1 # variable binding only for readability
This example is quite hard to understand because one of the function, eval just do nothing special, and it composition is equivalent to the identity! ... so it could be quite confusing.
(foo)(2)(lambda x:x+1)):
x = 2
iter_2(x)(increment) # increment by 2 because iter_2 calls increment twice
# 4
idempotency: (or composition with itself return the identity function)
increment(3) == eval(increment)(3)
# True
# idempotency - second composition is equivalent to the identity
eval(increment)(3) == eval(eval)(increment)(3)
# True
eval(increment)(3) == eval(eval)(eval)(increment)(3)
# True
# ... and so on
final: consequence of idempotency -> bar do nothing, just confusion
eval(eval)(iter_2)(x)(increment) == iter_2(x)(increment)
# True
Remark:
in (bar)(bar)(foo)(2)(lambda x:x+1) you can omit the brackets around the 1st term, just bar(bar)(foo)(2)(lambda x:x+1)
Digression: [since you example is quite scaring]
Lambda functions are also known as anonymous function. Why this? Simply because that they don't need to be declared. They are designed to be single purpose, so you should "never" assign to a variable. The arise for example in the context of functional programming where the basic ingredients are... functions! They are used to modify the behavior of other functions (for example by decoration!). Your example it is just a standalone syntactical one... essentially a nonsense example which hides the truth "power" of the lambda functions. There is also a branch mathematics which based on them called lambda calculus.
Here a totally different example of application of the lambda functions, useful for decoration (but this is another story):
def action(func1):
return lambda func2: lambda p: func2(p, func1())
def save(path, content):
print(f'content saved to "{path}"')
def content():
return 'content' # i.e. from a file, url, ...
# call
action(content)(save)('./path')
# with each key-parameter would be
action(func1=content)(func2=save)(p='./path')
Output
content saved to "./path"

Python: using a function that returns two items in an If statement, without executing twice

I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])

Can one use closures to simplify functions in Python?

Imagine if you want to make a closure function that decides some option for what its inner function does. In this example, we have an inner function that decides whether a number is even, but the generator decides whether the number zero is even, as if there were a debate.
def generate_is_even(reject_zero):
def is_even(x):
return (x % 2 == 0 and x != 0) if reject_zero else x % 2 == 0
return is_even
If is_even(x) is run millions of times, it appears reject_zero will still be checked every single time is_even(x) is run! My actual code has many similar 'options' to create a function that is run millions of times, and it would be inconvenient to write functions for every combination of options. Is there a way to prevent this inefficiency, or does some implementation of Python simplify this?
You seem to be looking for something like macros in C. Unfortunately, Python is not compiled (not the same way as C, for purists), and I don't see direct solutions for your need.
Still, you could set all your parameters at the beginning of runtime, and select the functions at this moment according to the values of the parameters. For instance, your function generator would be something like:
def generate_is_even(reject_zero):
def is_even_true(x):
return (x % 2 == 0 and x != 0)
def is_even_false(x):
return x % 2 == 0
return (is_even_true if reject_zero else is_even_false)
def setup(reject_zero, arg2, arg3):
is_even = generate_is_even(reject_zero)
The backlash of this is having to write a generator for each function that handles such a parameter. In the case you present, this is not a big problem, because there are only two versions of the function, that are not very long.
You need to ask yourself when it is useful to do so. In your situation, there is only one boolean comparison, which is not really resource-consuming, but there might be situations where generating the functions before could become worthwhile.
consider caching all your options in a list, and the generated function only iterates the chosen function
def generate_is_even(**kwargs):
options = {'reject_zero': lambda x: x != 0}
enabled = [options[o] for o in options if o in kwargs and kwargs[o]]
def is_even(x):
return all([fn(x) for fn in enabled]) and x % 2 == 0
return is_even
then you could use
is_even_nozero = generate_is_even(reject_zero=True)
is_even_nozero(0) # gives False
is_even = generate_is_even()
is_even(0) # gives True
if you need add options then add it to the options dict, and you could usee new_option=True is the generate_is_even function to enable it

How to save value returned from python function if call does not capture return

Let's say I have a python function, where x and y are relatively large objects (lists, NumPy matrices, etc.):
def myfun(x):
y=some complicated function of x
return y
If in an interactive session the user calls this as:
myfun(5)
The call is basically useless, since y is lost. Let's also suppose the function takes a while to run. Is there a way to retrieve the answer, so the user doesn't have to re-run, i.e. answer=myfun(5)? Alternatively, what is a good (pythonic) way to write the function to make it 'fool-proof' for this scenario? Some not-so-great options are:
Require a parameter that stores the value, e.g.
def myfun(x,y):
y = some complicated function of x
return y
Or maybe:
def myfun(x):
y = some complicated function of x
global temp
temp = y
return y
In the latter case, if a user then mistakenly called myfun(5), there's the option of y=temp to get the answer back.. but using global just seems wrong.
y=_
assuming you are in the interactive python console. _ is magic that holds the last "result"

How to make two functions share the same non global variable (Python)

Is there a way to make function B to be able to access a non global variable that was declared in only in function A, without return statements from function A.
As asked, the question:
Define two functions:
p: prints the value of a variable
q: increments the variable
such that
Initial value of the variable is 0. You can't define the variable in the global
enviroment.
Variable is not located in the global environment and the only way to change it is by invoking q().
The global enviroment should know only p() and q().
Tip: 1) In python, a function can return more than 1 value. 2) A function can be
assigned to a variable.
# Example:
>>> p()
0
>>> q()
>>> q()
>>> p()
2
The question says the global enviroment should know only p and q.
So, taking that literally, it could be done inline using a single function scope:
>>> p, q = (lambda x=[0]: (lambda: print(x[0]), lambda: x.__setitem__(0, x[0] + 1)))()
>>> p()
0
>>> q()
>>> q()
>>> p()
2
Using the tips provided as clues, it could be done something like this:
def make_p_and_q():
context = {'local_var': 0}
def p():
print('{}'.format(context['local_var']))
def q():
context['local_var'] += 1
return p, q
p, q = make_p_and_q()
p() # --> 0
q()
q()
p() # --> 2
The collection of things that functions can access is generally called its scope. One interpretation of your question is whether B can access a "local variable" of A; that is, one that is defined normally as
def A():
x = 1
The answer here is "not easily": Python lets you do a lot, but local variables are one of the things that are not meant to be accessed inside a function.
I suspect what your teacher is getting at is that A can modify things outside of its scope, in order to send information out without sending it through the return value. (Whether this is good coding practise is another matter.) For example, functions are themselves Python objects, and you can assign arbitrary properties to Python objects, so you can actually store values on the function object and read them from outside it.
def a():
a.key = "value"
a()
print a.key
Introspection and hacking with function objects
In fact, you can sort of get at the constant values defined in A by looking at the compiled Python object generated when you define a function. For example, in the example above, "value" is a constant, and constants are stored on the code object:
In [9]: a.func_code.co_consts
Out[9]: (None, 'value')
This is probably not what you meant.
Firstly, it's bad practise to do so. Such variables make debugging difficult and are easy to lose track of, especially in complex code.
Having said that, you can accomplish what you want by declaring a variable as global:
def funcA():
global foo
foo = 3
def funcB():
print foo # output is 3
That's one weird homework assignment; especially the tips make me suspect that you've misunderstood or left out something.
Anyway, here's a simpler solution than the accepted answer: Since calls to q increment the value of the variable, it must be a persistent ("static") variable of some sort. Store it somewhere other than the global namespace, and tell p about it. The obvious place to store it is as an attribute of q:
def q():
q.x += 1
q.x = 0 # Initialize
def p():
print(q.x)

Categories