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.
Related
I'm attempting to thread a function call in my Python catastr^H^H^H^H^H^Hreation, and I've read up on how to use the threading.Thread() call. My function takes a simple string argument, so theoretically it should be as easy as:
thread = threading.Thread(target = my_func, args = (string_var, ))
bearing in mind that the args() needs to be a tuple. Got it. However, it appears as though I'm still doing something wrong because I continually get the barffage from Python:
TypeError: my_func() takes 1 positional argument but 2 were given
I'm a bit stumped here. Any guidance?
Thanks!
please provide some code for us to help you.
But before you do your post could be a possible duplicate of this post.
Seems the issue is that because it's a method (thanks gribvirus74 for the idea) and I'm attempting to thread it, it won't inherit the self. And that appears to be the issue. I moved the function outside of the class and called it with the Thread(). Works fine now.
If it's a method, then you can write the following code (assuming the class name is SomeClass and it has a method called foo with one argument):
x = SomeClass()
thread = threading.Thread(target=SomeClass.foo, args=(x, 'your method argument'))
Is it possible to have the below code without raising an exception?
The hello function represents code outside my control. It is only here for the sake of clarity.
def hello():
print("hellowed")
def callsCallback(callback):
callback(*["dd"])
callsCallback(hello)
The idea is for a library to receive a callback function for when something happens. For backwards compatibility, the function being called may or may not receive parameters.
I'm aware of this answer: How can I find the number of arguments of a Python function? but I'd rather avoid inspection, if I can.
If you used *args in a wrapper function then it would never throw an exception because of the incorrect number of arguments.
def hello():
print("hellowed")
def wrapper(f):
def g(*args):
f()
return g
def callsCallback(callback):
callback = wrapper(callback)
callback(*["dd"])
callsCallback(hello)
You could use a decorator style function. This may be overkill for what you want to do.
If you don't know ahead of time how many arguments hello takes, you would have to introspect as you suggested to call the function appropriately.
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.
I want to have a function in main class which has parameters not only self.
class Ui_Form(object):
def clearTextEdit(self, x):
self.plainTextEdit.setPlainText(" ")
print("Script in Textbox is Cleaned!",)
x will be my additional parameter and I want clearTextEdit to be called by click.
self.pushButton_3.clicked.connect(self.clearTextEdit(x))
it does not allow me to write x as parameter in clicked. Can you help me!
Solution
This is a perfect place to use a lambda:
self.pushButton_3.clicked.connect(lambda: self.clearTextEdit(x))
Remember, connect expects a function of no arguments, so we have to wrap up the function call in another function.
Explanation
Your original statement
self.pushButton_3.clicked.connect(self.clearTextEdit(x)) # Incorrect
was actually calling self.clearTextEdit(x) when you made the call to connect, and then you got an error because clearTextEdit doesn't return a function of no arguments, which is what connect wanted.
Lambda?
Instead, by passing lambda: self.clearTextEdit(x), we give connect a function of no arguments, which when called, will call self.clearTextEdit(x). The code above is equivalent to
def callback():
return self.clearTextEdit(x)
self.pushButton_3.clicked.connect(callback)
But with a lambda, we don't have to name "callback", we just pass it in directly.
If you want to know more about lambda functions, you can check out this question for more detail.
On an unrelated note, I notice that you don't use x anywhere in clearTextEdit. Is it necessary for clearTextEdit to take an argument in the first place?
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)