Using event in definition's argument - python

I am trying to make a definition, what includes event (you know, to see the place of the click), and other four args. I want to call it, but I don't know how. I tried to give it a default value, but no success, I don't know what to write in the place of 'event'
My code is:
def example(event,a,b,c,d):

Your bound function will already be called like callback(event) from within tkinter's system, so your def header takes one positional argument by default and is usually written def callback(event): and bound with some_widget.bind(sequence, callback), just passing the function object to bind and letting event get passed along internally.
That having been said, there are two ways to use other variables from outside within event callbacks and still use the event object too.
Use lambda as a wrapper to pass along arbitrary args:
a, b, c, d = some_bbox
def on_click(event, a, b, c, d):
print(event.x, event.y, a, b, c, d)
# do the rest of your processing
some_widget.bind("<Button-1>", lambda event, a=a, b=b, c=c, d=d: on_click(event, a, b, c, d)
Use either the global or nonlocal keyword to specify variables to take from the outer scope:
a, b, c, d = some_bbox
def on_click(event):
# use global if a, b, c, and d exist at the module level
global a, b, c, d
# use nonlocal if a, b, c, and d exist within the scope of another function
# nonlocal a, b, c, d
print(event.x, event.y, a, b, c, d)
# do the rest of your processing
some_widget.bind("<Button-1>", on_click)
python 3.8 tkinter 8.6

Related

iterating functions definitions, based on a parent function

I am trying to write some code to perform a statistical test called model-reduction. Basically what I want to know is whether each variable in my function makes a meaningful contribution (i.e. significantly explains variance). Say for example my original fit-function looks like this:
full_model(x, a, b, c, d):
return a + b*x + c*x**3 + sin(d*x)
I want to compare reduced forms of this model. The once I need to check are:
reduced = lambda x, b, c, d: full_model(x, 0, b, c, d)
reduced = lambda x, a, c, d: full_model(x, a, 0, c, d)
reduced = lambda x, a, b, d: full_model(x, a, b, 0, d)
reduced = lambda x, a, b, c: full_model(x, a, b, c, 0)
For each case, I run some sort of test that I don't go into detail:
compare_models(full_model, reduced, x, y)
In reality, my fit function has more parameters, and I want test even further reduced functions. The code will be really messy if I have to explicitly define all possible models. Is there any way to define the reduced function in a for-loop? And is there any existing python module that can achieve what I want to do?
I would harness functools.partial for that following way, consider following simplified example:
import functools
def sum3(x, y, z):
return x+y+z
args = ["x", "y", "z"]
red_dict = {}
for arg in args:
red_dict[arg] = functools.partial(sum3, **{arg: 0})
print(red_dict["x"](y=10,z=10))
print(red_dict["y"](x=10,z=10))
print(red_dict["z"](x=10,y=10))
Output:
20
20
20
Explanation: args is list of args names you want to zero, in for-loop I use argument unpacking (**) to fix selected argument value to zero, then I store result in red_dict. Use loop is equivalent to doing:
red_dict["x"] = functools.partial(sum3, x=0)
red_dict["y"] = functools.partial(sum3, y=0)
red_dict["z"] = functools.partial(sum3, z=0)

Closure after function definition

Is it possible to define a closure for a function which is already defined?
For example I'd like to have a "raw" function and a function which already has some predefined values set by a surrounding closure.
Here is some code showing what I can do with a closure to add predefined variables to a function definition:
def outer(a, b, c):
def fun(d):
print(a + b + c - d)
return fun
foo = outer(4, 5, 6)
foo(10)
Now I want to have a definition of fun outside of a wrapping closure function, to be able to call fun either with variables from a closure or by passing variables directly. I know that I need to redefine a function to make it usable in a closure, thus I tried using lambda for it:
def fun(a, b, c, d): # raw function
print(a + b + c - d)
def clsr(func): # make a "closure" decorator
def wrap(*args):
return lambda *args: func(*args)
return wrap
foo = clsr(fun)(5, 6, 7) # make a closure with values already defined
foo(10) # raises TypeError: fun() missing 3 required positional arguments: 'a', 'b', and 'c'
fun(5, 6, 7, 10) # prints 8
What I also tried is using wraps from functools, but I was not able to make it work.
But is this even possible? And if yes: Is there any module which already implements decorators for this?
You can just define the wrap on the fly:
def fun(a, b, c, d): # raw function
print(a + b + c - d)
def closed(d): fun(5,6,7,d)
closed(10)
You can use this with lambda, but #juanpa points out you should not if there is no reason to. The above code will result in 8. This method by the way is not Python specific, most languages would support this.
But if you need a closure in a sense that it relies on the wrapper variables, than no, and there is good reason not to. This will create essentially a non-working function, that relies on wrapping. In this case using a class maybe better:
class fun:
def __init__(self,*args): #Can use specific things, not just *args.
self.args = args #Or meaningful names
def __call__(self,a, b, c, d): # raw function
print(a + b + c - d,self.args)
def closed(d):
fun("some",3,"more",['args'])(5,6,7,d)
closed(10)
or using *args/**kwargs directly and passing extra variables through that. Otherwise I am not familiar with a "inner function" construct that only works after wrapping.

Python - Passing arguments back and forth between functions

Say I have some arguments passed to a function, I use those arguments to do some calculations, and then pass the results to another function, where they are further used. How would I go about passing the results back to the first function and skipping to a point such that data is not sent back to the second function to avoid getting stuck in a loop.
The two functions are in two different python scripts.
The way I'm currently doing it is by adding any new arguments supposed to be coming from the second script as non keyword arguments, and passing all the arguments from the first function to the second even if they are not needed in the second. The second function passes all the arguments back to the first, and an if condition on the non keyword argument to check whether it has its default value is used to determine if the data has been sent back by the second function.
In f1.py:
def calc1(a, b, c, d = []):
a = a+b
c = a*c
import f2
f2.calc2(a, b, c)
If d != []: # This checks whether data has been sent by the second argument, in which case d will not have its default value
print(b, d) # This should print the results from f2, so 'b' should
# retain its value from calc1.
return
In the another script (f2.py)
def calc2(a, b, c):
d = a + c
import f1
f1.calc1(a, b, c, d) # So even though 'b' wasn't used it is there in
# f2 to be sent back to calc1
return
Having two methods recursively call each other is usually a bad idea. It's especially bad between two files. It looks like you want to call calc1(), have it call calc2() internally, and then make a decision about what to do based on the result of calc2().
Is this what you are trying to do?
#### f1.py
import f2
def calc1(a, b, c):
a = a+b
c = a*c
d = f2.calc2(a, b, c)
# This checks whether data has been sent by the second argument,
# in which case d will not have its default value
if d:
# This should print the results from f2, so 'b' should retain
# its value from calc1.
print(b, d)
#### f2.py
def calc2(a, b, c):
return a + c

Optional Parameters, certain combination of them required

I have a general question as well as a specific use case.
Optional parameters are easy enough: def func(a, b, c=None): ... and then anywhere c might be used in the body just write if c: first, or something along those lines. But what about when a certain combination of parameters is required? The general case is to consider any arbitrary situation of which exact parameters exist or not. For a function def func(a, b, c=None, d=None, e=None, f=None): ... this would include silly things like: provide c and d but not e and f, or provide e only, or provide at least 3 of c, d, e, and f. But my use case doesn't require such generality.
For def func(a, b, c=None, d=None): ..., I want EXACTLY ONE OF c and d to be provided.
Solutions I've thought of include:
- in the body, manually check how many of c and d are not None, and if it's not exactly 1, return an error saying exactly 1 needs to be specified
ex.
def func(a, b, c=None, d=None):
how_many_provided = len([arg for arg in [c, d] if arg]) # count the non-None optional args
if not how_many_provided == 1:
return "Hey, provide exactly 1 of 'c' and 'd'"
if c:
# stuff to do if c is provided
elif d:
# stuff to do if d is provided
- change the function to be def func(a, b, e, f): ... where e represents either c or d and f indicates which one of those e represents.
ex.
def func(a, b, e, f):
if f == 'c':
# stuff to do if c is provided, with e as c
if f == 'd':
# stuff to do if d is provided, with e as d
These would work, but what is the standard/accepted/pythonic way of doing this?
I would say the easiest way for your user in your simple case is to refactor to separate functions. Each function does the different work as described and then a common one e.g. for your last case
def funcC(a, b, c):
# stuff to do if c is provided, with e as c
common_func(a,b,c, None)
def funcD(a, b, d):
# stuff to do if d is provided, with e as d
common_func(a,b,None, d)
The user then knows what parameters matter and only the valid possible combinations can be used, the user does not have to guess or have a chance to call them incorrectly. You as providing the function can provide whatever is needed for the parameter the caller does not supply.
There are longer explanations of these found by googling for "flag parameters" e.g. Martin Fowler Stack Overflow these tend to mention Boolean arguments but this in effect the same thing a different code path depending on a parameter which has no other effect.
Another phrase to look for is "control coupling"
You could just use the keyword args dict:
def func(a, b, **kwargs):
valid_args = len(kwargs) == 1 and ('c' in kwargs or 'd' in kwargs)
if not valid_args:
return "Hey, provide exactly 1 of 'c' and 'd'"
if 'c' in kwargs:
# stuff to do if c is provided
elif 'd' in kwargs:
# stuff to do if d is provided
Here is another one, which will allow the arguments be specified, and differentiates between c=None and c not given, while still providing the argument names explicitly:
undefined = object()
def func(a, b, c=undefined, d=undefined):
if (c is undefined) ^ (d is undefined):
raise TypeError("Hey, provide exactly 1 of 'c' and 'd'")
...
On Python 3, keyword only arguments make it even nicer, making sure that the caller explicitly specifies c or d:
def func(a, b, *, c=undefined, d=undefined):
if (c is undefined) ^ (d is undefined):
raise TypeError("Hey, provide exactly 1 of 'c' and 'd'")

Using current scope as kwargs in python

I basically want to expand the current scope as you would a dictionary when calling a function.
I remember seeing something about this somewhere but I cannot remember where or how to do it.
Here is a simple example
def bar(a, b, c, d, e, f):
pass
def foo(a, b, c, d, e, f):
# Instead of doing this
bar(a, b, c, d, e, f)
# or
bar(a=a, b=b, c=c, d=d, e=e, f=f)
# I'd like to do this
bar(**local_scope)
Am I imagining things or can this really be done?
You can use locals() (or globals() depending on what you need), which returns a dictionary mapping variable names to values.
bar(**locals())
if foo was written like this
def foo(**kwargs):
bar(**kwargs)
Other than that the other two examples you posted are better, expanding all locals is a bad idea.

Categories

Resources