Function called by the control flow, not by tkinter bind - python

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

Related

Passing arguments into a callback function

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))

how can a python decorator change calls in decorated function?

I can't figure out how to do this, and frankly, I don't know if it's possible.
I want to write a decorator that changes the way a function is called. It's easiest to see with example code:
def my_print(*args, **kwargs):
print(args[0].upper())
#reroute_decorator('print', my_print)
def my_func():
print('normally this print function is just a print function...')
print('but since my_func is decorated with a special reroute_decorator...')
print('it is replaced with a different function, and its args sent there.')
my_func()
# NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
# BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
# IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.
Is a decorator with this kind of functionality even possible in python?
Now, I don't really need this if it's too complex, I just can't figure out how to do it in a simple way.
Is this kind of a problem trivial? Or is it really complex?
You can create a new function with an updated globals dictionary so that to that function it appears that the global was bound to the desired value.
Note that this is weaker than actual dynamic scope as any functions called by the function will see the original bindings and not the modified one.
See namespaced_function referenced in How does Python's types.FunctionType create dynamic Functions?
To elaborate on #Dan D.'s answer, you would create a new function object to replace the original, something like this:
from types import FunctionType
def reroute_decorator(**kwargs):
def actual_decorator(func):
globals = func.__globals__.copy()
globals.update(kwargs)
new_func = FunctionType(
func.__code__, globals, name=func.__name__,
argdefs=func.__defaults__, closure=func.__closure__)
new_func.__dict__.update(func.__dict__)
return new_func
return actual_decorator
The only catch here is that the updated function object is the only one that will see whatever kwargs you passed in, since they will be spoofed into globals. Additionally, any modifications you make to the module after calling the decorator function will not be visible to the decorated function, but that should not be an issue. You can go a layer deeper and create a proxy dictionary that would allow you to interact normally with the original, except for keys you explicitly defined, like print, but that's a bit out of scope here.
I've updated your print implementation to be a bit more general, and made the input to the decorator function more pythonic (less MATLABy):
def my_print(*args, **kwargs):
print(*(str(x).upper() for x in args), **kwargs)
#reroute_decorator(print=my_print)
def my_func():
print('normally this print function is just a print function...')
print('but since my_func is decorated with a special reroute_decorator...')
print('it is replaced with a different function, and its args sent there.')
Which results in:
>>> my_func()
NORMALLY THIS PRINT FUNCTION IS JUST A PRINT FUNCTION...
BUT SINCE MY_FUNC IS DECORATED WITH A SPECIAL REROUTE_DECORATOR...
IT IS REPLACED WITH A DIFFERENT FUNCTION, AND ITS ARGS SENT THERE.

How to pass a function to another function in order to create an action listener

I've been programming in Java for ~2 years, and have just started learning Python(about 1 week in) and PyGame, and have been wanting to create a simple button class, but I don't want the action of the button(what happens when it's pressed) to be hard coded in. What is the best way of doing this in Python/PyGame?
I've also thought of having a variable in the constructor, which is set to a function when it's called, like:
def __init__(self, func)
and called like
act = action()
obj = Button(act),
I don't think this will work, but will get back to you all when I test it.
In Java, it would be called like:
button = new Button("Text");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println("ACTION");
}
}
The only way I know you can pass a function object to another function is by passing its identifier:
# listener function
def listener():
print('listening...')
class Button:
def __init__(self, mouse_listener):
mouse_listener() # you call the function inside __init__
button = Button(listener)
In Python, you can receive a function as parameter because functions are actually objects, but they are special objects, because they can be called or they are callable objects, in fact you could also call explicitly their __call__ default function to invoke a function:
listener.__call__()
but usually you don't do that.

Decorator with parameters

Can you explain me how the following decorator works:
def set_ev_cls(ev_cls, dispatchers=None):
def _set_ev_cls_dec(handler):
if 'callers' not in dir(handler):
handler.callers = {}
for e in _listify(ev_cls):
handler.callers[e] = _Caller(_listify(dispatchers), e.__module__)
return handler
return _set_ev_cls_dec
#set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def _switch_features_handler(self, ev):
datapath = ev.msg.datapath
....
Please, don't go into details on what's going on inside the function. I'm interested in how the decorator with parameters wrap methods here. By the way, it's a code snippet from Ryu (event registration mechanism).
Thank you in advance
First, a decorator is just a function that gets called with a function. In particular, the following are (almost) the same thing:
#spam
def eggs(arg): pass
def eggs(arg): pass
eggs = spam(eggs)
So, what happens when the decorator takes parameters? Same thing:
#spam(arg2)
def eggs(arg): pass
def eggs(arg): pass
eggs = spam(arg2)(eggs)
Now, notice that the function _set_ev_cls_dec, which is ultimately returned and used in place of _switch_features_handler, is a local function, defined inside the decorator. That means it can be a closure over variables from the outer function—including the parameters of the outer function. So, it can use the handler argument at call time, plus the ev_cls and dispatchers arguments that it got at decoration time.
So:
set_ev_cls_dev creates a local function and returns a closure around its ev_cls and dispatchers arguments, and returns that function.
That closure gets called with _switch_features_handler as its parameter, and it modifies and returns that parameter by adding a callers attribute, which is a dict of _Caller objects built from that closed-over dispatchers parameter and keyed off that closed-over ev_cls parameter.
Explain how it works without detailing what's going on inside? That kind of sounds like "explain without explaining," but here's a rough walkthrough:
Think of set_ev_cls as a factory for decorators. It's there to catch the arguments at the time the decorator is invoked:
#set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
And return a function, _set_ev_cls_dec that has its variables bound to:
ev_cls = ofp_event.EventOFPSwitchFeatures
dispatchers = CONFIG_DISPATCHER
Or put another way, you now have a 'customized' or 'parametrized' dispatcher that's logically equivalent to:
def custom_decorator(handler):
if 'callers' not in dir(handler):
handler.callers = {}
for e in _listify(ofp_event.EventOFPSwitchFeatures):
handler.callers[e] = _Caller(_listify(CONFIG_DISPATCHER), e.__module__)
return handler
(If you captured the values of ofp_event.EventOFPSwitchFeatures and CONFIG_DISPATCHER at the moment the #set_ev_cls(...) was called).
The custom_decorator of step 1 is applied to _switch_features_handleras a more traditional unparameterized decorator.

Problem with decorator

def my_decorator(func) :
print "I am a ordinary function"
def wrapper() :
print "I am function returned by the decorator"
func()
return wrapper
def lazy_function() :
print "zzzzzzzz"
functionDecorator=my_decorator(lazy_function)
I have in Debug IO
I am a ordinary function
I don't get it why there is any output. I understand why this line:
functionDecorator()
returns me:
I am function returned by the decorator
another___zzzzzzzz
But for the rest I think I miss something
When you first call my_decorator, before it returns the the function wrapper, it will print your message.
Try calling functionDecorator() again, you won't get the output a second time because the function has already been decorated by my_decorator. Each time you call my_decorator, however, it will print your message, because it is a normal function call (that happens to also return a decorated function).
Also, see http://www.python.org/dev/peps/pep-0318/#current-syntax for alternative syntax for implementing decorators.
Decorator is a normal function, that takes another function and returns some modified function.
When you call:
functionDecorator=my_decorator(lazy_function)
code inside your decorator is instantly executed and so print statement is executed, new function is created and returned. Then, when you run decorated function (which is simply a new function built inside a decorator), only internal print is executed and the external is not executed ever again. Is that clear?

Categories