Python + Kivy: Clock doesn't work with partial(keywords) - python

def _procedural_reloading(self,gen=[],*args):
if len(gen):
gen.pop().reload()
Clock.schedule_interval(functools.partial(
self._procedural_reloading,gen=gen),.5)
In above code, _procedural_reloading() is a method of a class and it gets a list which contains some images and tries to reload() them one by one.
Guess what, it doesn't work because it says that _procedural_reloading got multiple values for keyword gen!
The odd thing is if I pass gen as an argument (not as a keyword argument) it works just fine, here:
def _procedural_reloading(self,gen=[],*args):
if len(gen):
gen.pop().reload()
Clock.schedule_interval(functools.partial(
self._procedural_reloading,gen),.5)
why gen=gen doesn't work?
To elaborate it more, until now I couldn't pass any keyword argument with Clock even once! I always have to arrange the arguments one by one by order and pass them... is it a known issue? or have I done something wrong there? I feel stupid!
Edit:
gen without default value also doesn't work in my case:
def _procedural_reloading(self,gen,*args):
if len(gen):
gen.pop().reload()
Clock.schedule_interval(functools.partial(
self._procedural_reloading,gen=gen),.5)

When you create
functools.partial(self._procedural_reloading,gen=gen)
partial saves gen=gen into kwargs.
kwargs would probably look like {'gen': gen}, nothing to do with positional arguments, none have been given yet. When this partial function is called, you can see by your function definition:
def _procedural_reloading(self,gen=[],*args):
gen is the first positional argument, so now the caller of the partial function, calls it with a certain number of arguments, the first of which, is set to gen! because it is the first positional argument, so you are setting it twice! (Which isn't allowed). It's weird and problematic (as can be seen) to define positional args like that (with a default arg before it), the solution is:
def _procedural_reloading(self,*args, **kwargs):
Now you are handling args differently from kwargs, you can get gen like kwargs.get(gen, default)

I'm trying to put #jamylak method to work, meantime here my own solution to this problem:
As I have expected, the problem was due to Kivy's Clock, it seems it passes it's parameter to the function first! got it? no?
When Clock calls a function, it passes a parameter to it called dt.
So if you have a function and want to call it with Clock it should have at least one argument:
def clock_callback_function(dt):
...
In my case, I always give my functions *args, so Kivy can do what ever it wants with them! but it seems Clock always overwrite the first argument of the callback functions.
to wrap it nicely, I should write my code like this:
def _procedural_reloading(self,dt=0,gen=[]):
if len(gen):
gen.pop().reload()
Clock.schedule_interval(functools.partial(
self._procedural_reloading,gen=gen),.5)
the above code works without exceptions but bellow code doesn't work as we already know:
def _procedural_reloading(self,gen=[],dt=0):
if len(gen):
gen.pop().reload()
Clock.schedule_interval(functools.partial(
self._procedural_reloading,gen=gen),.5)

Related

Why does function run without paramater?

I'm currently learning curses in python, and I found this piece of code online that is confusing me.
import curses
def draw_menu(stdscr):
# do stuff
# if you want more code just let me know
def main():
curses.wrapper(draw_menu)
if __name__ == "__main__":
main()
When I run this I don't get the expected missing 1 required positional argument error, since there is no parameter being passed in the curses.wrapper(draw_menu) line. Is this a curses thing? Any help is greatly appreciated.
A function is a datatype, just as much as strings, integers, and so on.
def my_function(txt):
print(txt)
here type(my_function) # => <class 'function'>
You invoke the code inside the function when you call it with parenthesis : my_function('hello') # => prints hello
Until then you can perfectly pass a function as an argument to another function.
And that last one can call the one you passed giving it some parameters.
Like in your case, I'd guess that curses.wrapper() creates a screen interface that it passes as argument your draw_menu() function.
And you can probably use that screen object to build your curse app.
See this : Python function as a function argument?
There's a big difference between curses.wrapper(draw_menu) and curses.wrapper(draw_menu()). curses.wrapper(draw_menu) calls curses.wrapper and passes the function draw_menu into it as an argument. In contrast, curses.wrapper(draw_menu()) would call draw_menu and pass its return value into curses.wrapper.
curses.wrapper will call the function you pass it. From that link:
Initialize curses and call another callable object, func, which should be the rest of your curses-using application.
E.g., it will call draw_menu when curses is completely initialized.
Here is the signature for curses.wrapper from here.
curses.wrapper(func, /, *args, **kwargs)
It says that you need to give curses.wrapper a function reference argument followed by zero or more arguments and keyword arguments. Your code satisfies those requirements.
Python allows function signatures like this to enable developers a lot of flexibility regarding what can be passed in by the caller.

Skip a positional argument when calling a function

I am trying to call a python function defined/created by a different person. That function explicitly requries 3 arguments inputs as
def function_name (argument1 argument2 argument3):
However, inside the function, only the argument1 and argument3 are used with the argument2 completely ignored. If I can not modify this function definition and need to call this function, how should I skip providing the argument2?
like
function_name (value1, *, value3)
or
function_name(value1, whatever_fake_value, value3)
I know the latter option is definitely going to work, but can I explicitly show (to minimize future confusion) that a argument has been skipped in this function call.
Create a wrapper function that calls the old function you can't change with the arguments you care about being passed through and a default in place of the "dead" argument and a clear concise comment explaining the exact situation for future posterity and so your future self is happy with you.
def new_wrapper_function(arg1, arg2):
# this function is a wrapper that calls old_function with a default argument in position 2 because it is unused
old_function(arg1, default_dead_arg, arg2)
You would probably have the wrapper function pass None as the "dead" argument, for example:
def new_wrapper_function(arg1, arg2):
# this function is a wrapper that calls old_function with a default argument in position 2 because it is unused
old_function(arg1, None, arg2)
You can make argument2 an optional argument and give it a default value. For instance:
def function_name(arg1, arg3, arg2=None):
pass
Then you can check if arg2 is valid, otherwise ignore it.
Why can't you change the definition? If you absolutely have to use it as is, you can pass None or an empty list.
function_name(arg1,None,arg2)
Pass None as the second argument. No harm no foul.
Since the arguments are all required and no defaults, skipping the second one in any way even by passing named arguments would raise a TypeError exception.

Does python allow me to pass dynamic variables to a decorator at runtime?

I am attempting to integrate a very old system and a newer system at work. The best I can do is to utilize an RSS firehouse type feed the system utilizes. The goal is to use this RSS feed to make the other system perform certain actions when certain people do things.
My idea is to wrap a decorator around certain functions to check if the user (a user ID provided in the RSS feed) has permissions in the new system.
My current solution has a lot of functions that look like this, which are called based on an action field in the feed:
actions_dict = {
...
'action1': function1
}
actions_dict[RSSFEED['action_taken']](RSSFEED['user_id'])
def function1(user_id):
if has_permissions(user_id):
# Do this function
I want to create a has_permissions decorator that takes the user_id so that I can remove this redundant has_permissions check in each of my functions.
#has_permissions(user_id)
def function1():
# Do this function
Unfortunately, I am not sure how to write such a decorator. All the tutorials I see have the #has_permissions() line with a hardcoded value, but in my case it needs to be passed at runtime and will be different each time the function is called.
How can I achieve this functionality?
In your question, you've named both, the check of the user_id, as well as the wanted decorator has_permissions, so I'm going with an example where names are more clear: Let's make a decorator that calls the underlying (decorated) function when the color (a string) is 'green'.
Python decorators are function factories
The decorator itself (if_green in my example below) is a function. It takes a function to be decorated as argument (named function in my example) and returns a function (run_function_if_green in the example). Usually, the returned function calls the passed function at some point, thereby "decorating" it with other actions it might run before or after it, or both.
Of course, it might only conditionally run it, as you seem to need:
def if_green(function):
def run_function_if_green(color, *args, **kwargs):
if color == 'green':
return function(*args, **kwargs)
return run_function_if_green
#if_green
def print_if_green():
print('what a nice color!')
print_if_green('red') # nothing happens
print_if_green('green') # => what a nice color!
What happens when you decorate a function with the decorator (as I did with print_if_green, here), is that the decorator (the function factory, if_green in my example) gets called with the original function (print_if_green as you see it in the code above). As is its nature, it returns a different function. Python then replaces the original function with the one returned by the decorator.
So in the subsequent calls, it's the returned function (run_function_if_green with the original print_if_green as function) that gets called as print_if_green and which conditionally calls further to that original print_if_green.
Functions factories can produce functions that take arguments
The call to the decorator (if_green) only happens once for each decorated function, not every time the decorated functions are called. But as the function returned by the decorator that one time permanently replaces the original function, it gets called instead of the original function every time that original function is invoked. And it can take arguments, if we allow it.
I've given it an argument color, which it uses itself to decide whether to call the decorated function. Further, I've given it the idiomatic vararg arguments, which it uses to call the wrapped function (if it calls it), so that I'm allowed to decorate functions taking an arbitrary number of positional and keyword arguments:
#if_green
def exclaim_if_green(exclamation):
print(exclamation, 'that IS a nice color!')
exclaim_if_green('red', 'Yay') # again, nothing
exclaim_if_green('green', 'Wow') # => Wow that IS a nice color!
The result of decorating a function with if_green is that a new first argument gets prepended to its signature, which will be invisible to the original function (as run_function_if_green doesn't forward it). As you are free in how you implement the function returned by the decorator, it could also call the original function with less, more or different arguments, do any required transformation on them before passing them to the original function or do other crazy stuff.
Concepts, concepts, concepts
Understanding decorators requires knowledge and understanding of various other concepts of the Python language. (Most of which aren't specific to Python, but one might still not be aware of them.)
For brevity's sake (this answer is long enough as it is), I've skipped or glossed over most of them. For a more comprehensive speedrun through (I think) all relevant ones, consult e.g. Understanding Python Decorators in 12 Easy Steps!.
The inputs to decorators (arguments, wrapped function) are rather static in python. There is no way to dynamically pass an argument like you're asking. If the user id can be extracted from somewhere at runtime inside the decorator function however, you can achieve what you want..
In Django for example, things like #login_required expect that the function they're wrapping has request as the first argument, and Request objects have a user attribute that they can utilize. Another, uglier option is to have some sort of global object you can get the current user from (see thread local storage).
The short answer is no: you cannot pass dynamic parameters to decorators.
But... you can certainly invoke them programmatically:
First let's create a decorator that can perform a permission check before executing a function:
import functools
def check_permissions(user_id):
def decorator(f):
#functools.wraps(f)
def wrapper(*args, **kw):
if has_permissions(user_id):
return f(*args, **kw)
else:
# what do you want to do if there aren't permissions?
...
return wrapper
return decorator
Now, when extracting an action from your dictionary, wrap it using the decorator to create a new callable that does an automatic permission check:
checked_action = check_permissions(RSSFEED['user_id'])(
actions_dict[RSSFEED['action_taken']])
Now, when you call checked_action it will first check the permissions corresponding to the user_id before executing the underlying action.
You may easily work around it, example:
from functools import wraps
def some_function():
print("some_function executed")
def some_decorator(decorator_arg1, decorator_arg2):
def decorate(func):
#wraps(func)
def wrapper(*args, **kwargs):
print(decorator_arg1)
ret = func(*args, **kwargs)
print(decorator_arg2)
return ret
return wrapper
return decorate
arg1 = "pre"
arg2 = "post"
decorated = some_decorator(arg1, arg2)(some_function)
In [4]: decorated()
pre
some_function executed
post

Callback to method in Python

I'm just starting to learn Python and I have the following problem.
Using a package with method "bind", the following code works:
def callback(data):
print data
channel.bind(callback)
but when I try to wrap this inside a class:
class myclass:
def callback(data):
print data
def register_callback:
channel.bind(self.callback)
the call_back method is never called. I tried both "self.callback" and just "callback". Any ideas?
It is not clear to me how your code works, as (1) you did not post the implementation of channel.bind, and (2) your second example is incorrect in the definition of register_callback (it is using a self argument that is not part of the list of parameters of the method, and it lacks parentheses).
Nevertheless, remember that methods usually require a "self" parameter, which is implicitly passed every time you run self.function(), as this is converted internally to a function call with self as its first parameter: function(self, ...). Since your callback has just one argument data, this is probably the problem.
You cannot declare a method bind that is able to accept either a function or a class method (the same problem happens with every OOP language I know: C++, Pascal...).
There are many ways to do this, but, again, without a self-contained example that can be compiled, it is difficult to give suggestions.
You need to pass the self object as well:
def register_callback(self):
channel.bind(self.callback)
What you're doing is entirely possible, but I'm not sure exactly what your issue is, because your sample code as posted is not even syntactically valid. (The second method has no argument list whatsoever.)
Regardless, you might find the following sample code helpful:
def send_data(callback):
callback('my_data')
def callback(data):
print 'Free function callback called with data:', data
# The follwing prints "Free function callback called with data: my_data"
send_data(callback)
class ClassWithCallback(object):
def callback(self, data):
print 'Object method callback called with data:', data
def apply_callback(self):
send_data(self.callback)
# The following prints "Object method callback called with data: my_data"
ClassWithCallback().apply_callback()
# Indeed, the following does the same
send_data(ClassWithCallback().callback)
In Python it is possible to use free functions (callback in the example above) or bound methods (self.callback in the example above) in more or less the same situations, at least for simple tasks like the one you've outlined.

How do I call a method from a superclass, whos definition is completely deferred to the subclasses?

I want to envoke a method in my code in a supercass, to do some subclass- specific processing before continuing on. I come to python recently from C#... there, I'd probably use an interface. Here's the gist of it (as I picture it, but it's not working):
class superClass:
def do_specific_stuff(self): #To be implemented entirely by the subclass,
#but called from the superclass
pass
def do_general_stuff1(self):
#do misc
def do_general_stuff2(self):
#do more misc
def main_general_stuff(self):
do_general_stuff1()
do_specific_stuff()
do_general_stuff2()
I have a rather complicated implementation of this; this example is exactly what I need and far less painful to understand for a first- time viewer. Calling do_specific_stuff() at the moment gives me the error
'global name 'do_specific_stuff' is not defined.
When I add 'self' as in self.do_specific_stuff I get the error
'TypeError: do_specific_stuff() takes 0 positional arguments but 1 was given.' Any takers? Thanks in advance...
It needs to be
def main_general_stuff(self):
self.do_general_stuff1()
self.do_specific_stuff()
...
The problem is that you are missing the explicit reference to self: Python thinks you mean a global function without it. Note that there is no implicit this like in Java: You need to specify it.

Categories

Resources