Passing arguments through QtGui.QAction to the triggered method - python

Let's say I have a method like:
def open(self, opt):
if opt == True:
...
if opt == False:
...
how do I pass the argument to it with QtGui.QAction like:
self.openAct = QtGui.QAction("O&pen", self, shortcut="Ctrl+O",
statusTip="Opens a location", triggered=self.open)

I found the answer it is from functools import partial. It was in This thread.

Related

python passing function to thread

how is possible to pass a function to a thread like a standard variable,
when i pass function on args , i have a non iterable error
there is a summary of my code
from CallbackThread import CallbackThread
import time
import threading
class foo:
def runSomthing(self,callback):
#do things
callthread = threading.Thread(target=self.newthread, args=(callback))
callthread.start()
def newthread(self,calback):
print("runiing")
while True:
#if receve data (udp)
data = 0
#run mycallbacktest
calback(data)
def mycallbacktest(i):
print("hello world", i)
myobj = foo()
myobj.runSomthing(mycallbacktest)
i have see on similar topics things like that
https://gist.github.com/amirasaran/e91c7253c03518b8f7b7955df0e954bb
and i have try this based on this bu i not sure what this is doing, for me is just call a callback when thread if finished
class BaseThread(threading.Thread):
def __init__(self, callback=None, callback_args=None, *args, **kwargs):
target = kwargs.pop('target')
super(BaseThread, self).__init__(target=self.target_with_callback, *args, **kwargs)
self.callback = callback
self.method = target
self.callback_args = callback_args
def target_with_callback(self):
self.method()
if self.callback is not None:
self.callback(*self.callback_args)
but this d'ont solve what i tring to do
as suggested MisterMiyagi, the awnser a missig comma,
It should be args=(callback,) instead of args=(callback)
(this post is to mark this post close)

How to pass arguments to a function that itself is passed as a kwarg

In the following example I'm trying to pass arguments to a function that itself has been passed as a kwarg. I have not been successful in passing arguments to the function 'func' from within the class 'TestClass' in the following example:
import sys, threading; from threading import Thread
def func(kwargs):
print('IN:', sys._getframe(0).f_code.co_name)
for key, value in kwargs.items() :
print ('KEY:', key, ', VAL:', value, sep='')
class TestClass(Thread):
def __init__(self, name = sys._getframe(0).f_code.co_name, kwargs = None):
Thread.__init__(self)
self.name = name
self.kwargs = kwargs
print('IN:', self.name)
def run(self):
func = self.kwargs['func']
func_kwargs_inner = {'arg_1': 'INNER-1', 'arg_2': 'INNER-2'}
func() # how to pass func_kwargs_inner to func?
def main():
func_kwargs = {'arg_1': 'OUTER-1', 'arg_2': 'OUTER-2'} # these get passed
# func_kwargs = {} # func_kwargs never gets populated
kwargs = {'func': (lambda: func(func_kwargs))}
test = TestClass(name='my-test', kwargs=kwargs)
test.start()
print('PROGRAM END')
if __name__ == '__main__':
main()
If I try to pass 'func_kwargs_inner' to 'func()', I get syntax errors; if I leave the argument list empty - as in the example - the result is:
IN: my-test
IN: func
KEY:arg_1, VAL:OUTER-1
KEY:arg_2, VAL:OUTER-2
PROGRAM END
whereas the required output once I find a way to pass the arguments correctly is:
IN: my-test
IN: func
KEY:arg_1, VAL:INNER-1
KEY:arg_2, VAL:INNER-2
PROGRAM END
How do I pass 'func_kwargs_inner' to 'func()'?
It seems that if you do the obvious thing, then it will work, and that your code at present explicitly avoids passing the arguments that you want. Specifically, in your TestClass.run you are not passing any arguments to func but instead relies on function arguments that are hard-coded into the lambda expression. So change your line:
func() # how to pass func_kwargs_inner to func?
to pass the arguments:
func(func_kwargs_inner)
Then in main, instead of that lambda expression:
kwargs = {'func': (lambda: func(func_kwargs))}
simply pass the function object itself:
kwargs = {'func': func}
Then you get the expected output:
IN: my-test
IN: func
PROGRAM END
KEY:arg_1, VAL:INNER-1
KEY:arg_2, VAL:INNER-2

Parsing arguments in python

I have a question about parsing arguments in python. Example code below.
Class Parser:
def __init__(self):
self.args = argparse.ArgumentParser()
self.args.add_argument("--email")
self.args.add_argument("--file")
self.args.add_argument("--save")
self.args.add_argument("--time")
self.args_parsed = self.args.parse_args()
def get_email(self):
return self.args_parsed.email
def get_file(self):
return self.args_parsed.file
def get_save(self):
return self.args_parsed.save
def get_time(self):
return self.args_parsed.time
Class functions(Parser):
def __init__(self):
super().__init__()
def Function1(self):
pass
def Function2(self):
pass
def Function3(self):
pass
def Function4(self):
pass
if __name__ == '__main__':
try:
arguments = sys.argv[1:]
if "--file" in arguments:
Function1()
elif "--save" in arguments:
Function2()
elif "--email" in arguments:
Function3()
elif "--time" in arguments:
Function4()
except IndexError:
print("Invalid argument")
Basically what my question is I want to add a lot more options then I already have, and I would have to keep on continuing the if elif chain. Is there a way to reduce this to only parse the arguments the user chooses? thanks
I know that you can do something like this:
my_dict = {
"file": Function1,
"save": Function2,
"email": Function3,
"time": Function4
}
if __name__ == '__main__':
try:
arguments = sys.argv[1]
if arguments:
my_dicts[arguments]()
But how can I do that with multiple values? Thanks
Welcome to Stack Overflow! Like the other commenters have said it's difficult to help you because there's a lot of different things you could do depending on what you intend to do beyond the code you showed us. In the future, I would suggest that you read how to ask a good question
That being said, here's something that could help you:
#!/usr/bin/env python3
import argparse
def email_handler(email_argument):
print(f'The email {email_argument} has been chosen')
def file_handler(file_argument):
print('I have to do something different with this file:',
file_argument)
def save_handler(save_argument):
print('Maybe you want to save', save_argument)
def time_handler(time_argument):
print(f'We have to take time {time_argument} into account')
options_handlers = {
'email' : email_handler,
'file' : file_handler,
'save' : save_handler,
'time' : time_handler
}
parser = argparse.ArgumentParser()
for current_option in options_handlers:
parser.add_argument(f'--{current_option}')
arguments_extracted = parser.parse_args()
arguments_accessible = vars(arguments_extracted)
for (current_argument, current_value) in arguments_accessible.items():
if current_value is not None:
current_handler = options_handlers[current_argument]
current_handler(current_value)
Does that answer some of your questions?

Pass extra optional arguments to callbacks without breaking existing callbacks

I have an API method that accepts a callback. The callback expects one argument.
I would like this method to pass a second argument to callbacks that accept it. However, I must maintain compatibility with callbacks that accept only the original argument. (In fact, I expect that most users will not care about the additional argument, so it would be annoying to force them to explicitly ignore it.)
I know that this can be done using inspect. I'm wondering if there is an "idiomatic" or commonly used solution that's not quite so heavyweight.
I think you can use __code__ to look how much arguments needed by the callback.
if callback.__code__.co_argcount == 2:
callback(arg1, arg2)
else:
callback(arg1)
This code isn't tested but it should work.
A simpler solution would be to use a try block to try calling the callback with a second argument first, before falling back to calling with just one argument in the except block:
try:
callback(first, second)
except TypeError as e:
if e.__traceback__.tb_frame.f_code.co_name != 'func_name':
raise
callback(first)
Using a function wrapper:
from inspect import signature, Parameter
def ignore_extra_arguments(function):
positional_count = 0
var_positional = False
keyword_names = set()
var_keyword = False
for p in signature(function).parameters.values():
if p.kind == Parameter.POSITIONAL_ONLY:
positional_count += 1
elif p.kind == Parameter.POSITIONAL_OR_KEYWORD:
positional_count += 1
keyword_names.add(p.name)
elif p.kind == Parameter.VAR_POSITIONAL:
var_positional = True
elif p.kind == Parameter.KEYWORD_ONLY:
keyword_names.add(p.name)
elif p.kind == Parameter.VAR_KEYWORD:
var_keyword = True
if var_positional:
new_args = lambda args: args
else:
new_args = lambda args: args[:positional_count]
if var_keyword:
new_kwargs = lambda kwargs: kwargs
else:
new_kwargs = lambda kwargs: {
name: value for name, value in kwargs.items()
if name in keyword_names
}
def wrapped(*args, **kwargs):
return function(
*new_args(args),
**new_kwargs(kwargs)
)
return wrapped
It works, but it's a bit brute-force.
A simpler version, assuming that function has no keyword or variadic parameters:
from inspect import signature
def ignore_simple(function):
count = len(signature(function).parameters)
return lambda *args: function(*args[:count])

Can two methods point to the same code?

I have a class which exposes two methods. These methods are actually visual syntax sugar, they ultimately point to the same code which behaves differently, depending on the payload it receives:
class Action:
def on(self):
self.action(1)
def off(self):
self.action(2)
def action(self, payload):
# a long function which does many things and uses the payload from on() and off()
print(payload)
a = Action()
a.on()
a.off()
Is there a way to define on() and off() so that they point to the same code (the one in action()), which would behave differently depending on the name of the method which was called?
I could of course pass the action in the call:
class Action:
def action(self, what):
payload = 1 if what == 'on' else 0
# a long function which does many things and uses the payload from on() and off()
print(payload)
a = Action()
a.action('on')
a.action('off')
but I want to keep an on/off structure of the class methods.
This is very similar to your first example, but are you looking for functools.partial?
You can use it to automatically set some arguments into a function, and the return value is a function object as well. Using it, you could do this:
import functools
class Abc(object):
def action(self, payload):
print(payload)
def __init__(self):
self.off = functools.partial(self.action, payload=1)
self.on = functools.partial(self.action, payload=2)
Then, you have your action, on, and off function, all working as expected:
foo = Abc()
foo.on()
>>> 2
foo.off()
>>> 1
foo.action(9)
>>> 9
Using partial is a semantically stronger way to say that this is syntactic sugar for calling another function. A function declaration such as def on(self): ... could be anything, while self.on = functools.partial(action,...) explicitly states that your tying one function to the other.
def _action_maker(payload):
def _action(self):
return self.action(payload)
return _action
class Action:
on = _action_maker(1)
off = _action_maker(2)
def action(self, payload):
# a long function which does many things and uses the payload from on() and off()
print(payload)
But personally I don't like this because my editor doesn't understand it and gives me false warnings.
Try inspect
import inspect
class Action:
def on(self):
self.action(1)
def off(self):
self.action(2)
def action(self, payload):
# a long function which does many things and uses the payload from on() and off()
currentframe = inspect.currentframe()
callername = inspect.getouterframes(currentframe, 2)[1][3]
if callername =='on':
print('on')
elif callername == 'off':
print('off')
a = Action()
a.on() #on
a.off() #off
Or simply pass hidden argument
class Action:
def on(self):
self.action(1,'on')
def off(self):
self.action(2, 'off')
def action(self, payload, callername):
# a long function which does many things and uses the payload from on() and off()
if callername =='on':
print('on')
elif callername == 'off':
print('off')
a = Action()
a.on() #on
a.off() #off

Categories

Resources