0
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)
Peter Badida
  • 11,310
  • 10
  • 44
  • 90
Dusk
  • 1,729
  • 10
  • 17
  • possible duplicate of [Django error: got multiple values for keyword argument](http://stackoverflow.com/questions/1941812/django-error-got-multiple-values-for-keyword-argument) – jamylak Apr 21 '13 at 10:02
  • By the way, have a look at: [“Least Astonishment” in Python: The Mutable Default Argument](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) (not related to your problem, but it will bite you if you're not aware of it) – Bakuriu Apr 21 '13 at 10:05
  • @Bakuriu good point! Damin, you should definitely read that in regards to this probably buggy statement: `gen=[]` – jamylak Apr 21 '13 at 10:10
  • @Bakuiru: I don' think it's because of gen=[] expression cause without giving gen a default value it still doesn't work. I edit my post for that. – Dusk Apr 21 '13 at 10:56
  • @jamylak I still don't get what is wrong after reading the post about Django problem. This issue is really funny. I have tried passing 2,3,etc more keyword arguments as well then if I remove the first keyword argument python pass this error to the second one, if I remove the second one, python pass the error to the third one until I remove all of keyword arguments and replace them with arguments! – Dusk Apr 21 '13 at 11:01
  • @Damin Ok I've provided an answer – jamylak Apr 21 '13 at 11:21

2 Answers2

2

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)

jamylak
  • 128,818
  • 30
  • 231
  • 230
0

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)
Dusk
  • 1,729
  • 10
  • 17
  • Side note, you shouldn't use [] as default argument in a function/method definition, this is a pretty well known gotcha for beginners, python will reuse the same list at every call, so if you modify it, the next call will not have a new [], but really what was there at the end of the last call, this can lead to very hard to understand bugs. If it's intended, you should probably comment about it, as a lot of people will think it's a potential bug. (I guess here, if you have two different places where you use it, with different "gen" values, things will break appart). – Tshirtman May 25 '13 at 12:16