I'm currently writing a Python program using Tkinter. In it, I want to trace the text within several entry boxes. Is there anyway I can pass parameters into the callback function that I call within the trace method? For example:
def cb(*args, var):
do something
some_object.trace("w", cb(var=some_var))
when I try this, I get a None Type error, which I'm assuming is because of how I'm attempting to pass in the argument.
You're calling the function immediately, and passing its return value as the callback argument, not passing the function as a callback.
Use lambda to create a function that calls the function with an extra argument.
some_object.trace("w", lambda *args: cb(*args, var=some_var))
You can also use functools.partial to create a function with some arguments pre-specified.
from functools import partial
some_object.trace("w", partial(cb, var=some_var))
Related
I have a project in which I need to do some things, call one of a few functions, and then do some other things:
def doCommand(function, parameter_for_function):
# do a thing
function(parameter_for_function)
# do a thing
My problem is that I don't know if the function I will be passing will require a parameter of its own!
How can I allow my function to call both functions that have no parameters, and functions that have one?
The preferred method of handling this is probably along these lines:
def doCommand(function, *args, **kwargs):
# do a thing
function(*args, **kwargs)
# do a thing
*args and **kwargs allow arbitrary arguments to be passed along to a method. As the name implies, these allow you to call doCommand with an arbitrary number of arguments and keyword arguments as well that get passed onto function.
I suggest explicitly saying that the function you take is one that's called with no parameters:
from typing import Callable
def doCommand(function: Callable[[], None]) -> None:
# do a thing
function()
# do a thing
If the function needs parameters, it's then explicitly the responsibility of the doCommand caller to provide them, e.g. within a lambda expression:
def foo(param) -> None:
print("foo: ", param)
doCommand(lambda: foo("bar"))
or a named wrapper function:
def foobar() -> None:
foo("bar")
doCommand(foobar)
This is a little bit weird. I want to dynamic initialize part of function's parameters before I call it. But I don't want to use class for some reason. Let's say I have a function:
def inner(a,b,c):
"a,b,c do something"
return result
Before I formally call it, I'd like to initialize it somewhere:
partInitalAbc=inner(,b,c)
Then I'll use it as:
result=partInitialAbc(a)
Please notice I want to do this dynamically. Just as when you initial a class using the constructor, so a decorator may be not appropriate at this time...
Any one have some idea?
It sounds like you're looking for functools.partial:
Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords.
If you pass the arguments to partial as positional arguments, they'll appear at the beginning of the argument list, which isn't exactly what you want. Keyword arguments give you more control over which parameters are passed:
partInitialAbc = functools.partial(inner, b=b_value, c=c_value);
I have a following function
def insert_word(listbox,text):
t_start.insert(INSERT, text)
print "worked"
binded to "< Return >" key via
listbox.bind("<Return>", insert_word(t_start,listbox.get(ACTIVE)))
Why the function is being called when the control flow comes, not when I press Return?
What's the entire idea behind bind function if it can be triggered somehow else then the bind itself?
Would I need a class with __init__ and __call__ methods to resolve this?
The function is called because you are actually calling it.
listbox.bind("<Return>", insert_word(t_start,listbox.get(ACTIVE)))
# ^----this function call is evaluated---^
What you want to do is to provide bind with a callback, that is a function object. You can use a closure do do this.
def callback(t_start, text):
def inner():
t_start.insert(INSERT, text)
return inner # Return the function
listbox.bind("<Return>", callback(t_start, listbox.get(ACTIVE)) )
# ^----this call returns a function----^
# Be aware that ^--this parameter-^ is
# still evaluated when the interpreter
# evaluates the statement
The callback function will be called when the event is triggered.
Like #ddelemeny said, that function is going to be called as it is written. If your program was structured into classes, you normally wouldn't need to pass an argument, because you can interact with variables directly from the function. However, a simple solution for your case would be using a lambda expression, so Python won't call the callback function when the control flow reaches it.
listbox.bind("<Return>", lambda e: insert_word(t_start,listbox.get(ACTIVE)))
http://effbot.org/zone/tkinter-callbacks.htm
Some decorators should only be used in the outermost layer.
A decorator that augments the original function and add a configure parameter is one example.
from functools import wraps
def special_case(f):
#wraps(f)
def _(a, b, config_x=False):
if config_x:
print "Special case here"
return
return f(a, b)
How can I avoid decorators like this getting decorated by another decorator?
EDIT
It is really disgusting to let everyone trying to apply a new decorator worry about the application order.
So, is it possible to avoid this kind of situation? Is it possible to add a config option without introducing a new parameter?
There isn't any way to stop it from being decorated. You just have to document that it needs to apply last and tell people not to use it inside another decorator.
Edit responding to your edit: In Python 3 you can give your function a keyword-only argument. This drastically reduces the impact that the change will have on existing uses of the function. Unfortunately this only works in Python 3.
Ultimately, applying a decorator to a function just means passing the decorated function as an argument to another function. There's no way for a function (or any object) to even know that it's being passed as an argument, let alone what it's being passed to. The reason you can't know about later decorators is the same reason that in an ordinary function call like f(g(x)), the function g can't know that it will later be called by f.
This is one reason writing decorators is tricky. Code that relies on heavy use of decorators that pass explicit arguments to their wrapped functions (as yours passes a and b) is inherently going to be fragile. Fortunately, a lot of the time you can write a decorator that uses *args and **kwargs so it can pass all the arguments it doesn't use along to the decorated function.
If someone takes the code you provide, and writes another decorator that explicitly accepts only a and b as arguments, and then calls the decorated function as f(a, b, True), it's their own fault if it fails. They should have known that other decorators they used might have changed the function signature.
Normally, when one write a decorator to be used generically, one does not estrict the number or name of arguments for the function it is wrapping.
Most decorators out there accept a list o positional arguments, and amapping of keyword arguments as parameters for their wrapper, and pass those, as received, to the decorated function:
def deco(func):
def wrapper(*args, **kwargs):
... decorator stuff here ...
return func(*args, **kwargs)
Threfore, if the decorator is to receive a parameter that it should "consume" - like the config_x you mention, all you have to do is to document it, have it as a keyword parameter, and pick it from kwargs. To avoid name clashes on parameters, one can, for example, prefix this parameter name with the decorator's own name or other distinct name:
def deco(func):
def wrapper(*args, **kwargs):
if "deco_config_x" in kwargs):
config_x = kwargs.pop(deco_config_x)
... decorator stuff here ...
return func(*args, **kwargs)
This way, the decorator may be put anywhere on a "decorator stack" - it will pick the parameter(s) addressed to it, and those bellow it won't get any stranger parameter. Theonly requirement is that your functions and decorators as a whole juts let keyword parametrs they don't know about to pass through.
I'm writing a class which I intend to use to create subroutines, constructor as following:
def __init__(self,menuText,RPC_params,RPC_call):
#Treat the params
#Call the given RPC_call with the treated params
The problem is that I want to call the function on the pattern "rpc.serve.(function name here)(params)",
where rpc is a serverProxy object that I'm using to call XMLRPC functions, and serve.-function name- is the method I'm calling on the XMLRPC-server.
I've looked at Calling a function from a string with the function's name in Python, but seeing how my serverProxy object doesnt know which "remote attributes" it have, I cant use the getattr() function to retrieve the method.
I've seen a example by making a dictionary to call a given function, but is there no way to make the function truly dynamic by creating the function call as you would create a String?
Like running a String as a function?
You can use getattr to get the function name from the server proxy, so calling the function like this will work:
getattr(rpc, function_name)(*params)