将* args或** kwargs传递给threading.Thread()

时间:2017-12-09 22:34:50

标签: python multithreading

使用线程库,我试图将各种args / keyword args传递给线程函数。有三种不同的情况。每个函数都包含一个在线程函数之前运行的函数,该函数将选项传递给线程函数,以告诉它为线程调用的函数和参数。在某些情况下,在某些参数中会有关键字参数,在某些参数中会有。以下是线程函数的示例代码:

def create_some_threads(my_target, *my_args, **my_keyword_args):
        for DeviceName in Devices:
            device_ip = Devices[DeviceName]['mgmt_ip']
            my_thread = threading.Thread(target=my_target, args=(device_ip, DeviceName, *my_args, **my_keyword_args))
            my_thread.start()

不幸的是,我收到错误:

    my_thread = threading.Thread(target=my_target, args=(device_ip, DeviceName, *args, **kwargs))
                                                                                ^                                                                
SyntaxError: invalid syntax

这是我在* my_args中调用的函数:

pingable_devices = {}
unpingable_devices = {}
with open(os.devnull, "wb") as limbo:
    print("\n[+] Progress:\n")
    pbar = tqdm(total=100)
    my_args = (pingable_devices, unpingable_devices, pbar, limbo)
    my_target = ping_em_all
    create_some_threads(my_target, *my_args)

问题是,对于我在调用线程函数之前使用的每个函数,我将调用一组不同的参数/关键字参数。我试图让它自己成为一个功能,但如果我不能像这样运行它,那么我可能需要探索其他途径。

编辑:第一个问题是由unutbu解决的,但现在我遇到了第二个问题。似乎线程函数调用的函数没有识别传递给线程的变量my_args。错误如下:

Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 754, in run
    self.__target(*self.__args, **self.__kwargs)
  File "Automatelab.py", line 157, in ping_em_all
    ping_reply = subprocess.Popen(['ping', '-c', '2', '-w', '2', '-q', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()
NameError: global name 'device_ip' is not defined

这是ping_em_all函数:

def ping_em_all(*my_args, **my_keyword_args):
    """.rstrip is needed for the ip as .readline adds a \n to
    the lines' text"""
    if "Linux" in platform.system():
        ping_reply = subprocess.Popen(['ping', '-c', '2', '-w', '2', '-q', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()
    #Darwin is Mac OSX
    elif "Darwin" in platform.system():
        ping_reply = subprocess.Popen(['ping', '-c', '2', '-t', '2', '-q', '-n', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()
        """Subprocess for Cygwin still not supported"""
    else:
    #Only other would be Windows
        ping_reply = subprocess.Popen(['ping', '-n', '2', '-w', '2', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()

2 个答案:

答案 0 :(得分:1)

目标是called with

self._target(*self._args, **self._kwargs)

因此,您可以使用:

def create_some_threads(my_target, *my_args, **my_keyword_args):
    for DeviceName in Devices:
        device_ip = Devices[DeviceName]['mgmt_ip']
        my_args = (device_ip, DeviceName,) + my_args
        my_thread = threading.Thread(target=my_target, 
                                     args=my_args, kwargs=my_keyword_args))
        my_thread.start()

当您定义在其调用签名中定义*my_args**my_keyword_args的函数时,请注意my_args成为该函数正文中的元组,my_keyword_args成为一个字典。

my_args = (device_ip, DeviceName,) + my_args

简单地将另外两个值连接到my_args元组的前面。

错误消息

NameError: global name 'device_ip' is not defined

表示在device_ip发生的位置尚未定义变量名NameError in a scope that is accessible。查看ping_em_all函数可以看出这是真的:

def ping_em_all(*my_args, **my_keyword_args):
    """.rstrip is needed for the ip as .readline adds a \n to
    the lines' text"""
    if "Linux" in platform.system():
        ping_reply = subprocess.Popen(['ping', '-c', '2', '-w', '2', '-q', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()
    ...            

device_ipmy_args中的第一个值:

my_args = (device_ip, DeviceName,) + my_args

因此,请将ping_em_all更改为

def ping_em_all(*my_args, **my_keyword_args):
    """.rstrip is needed for the ip as .readline adds a \n to
    the lines' text"""
    device_ip, DeviceName, my_args = my_args    #<-- This defines device_ip
    if "Linux" in platform.system():
        ping_reply = subprocess.Popen(['ping', '-c', '2', '-w', '2', '-q', device_ip.rstrip('\n')],stdout=limbo, stderr=limbo).wait()
    ...            

my_args元组中解压缩值并为其赋予变量名称。

答案 1 :(得分:0)

我看到了一些可能的问题。

在这一行:

my_thread = threading.Thread(target=my_target, args=(device_ip, DeviceName, *my_args, **my_keyword_args))

您不需要在*my_args**my_keyword_args前面加上星号,但是在函数内部可以将它们称为my_args或{ {1}}。其次,对于my_keyword_args参数,您可以从中删除args并将其放在最后。这是有助于澄清的基本格式:

my_keyword_args

输出看起来像这样:

import threading

def start_thread(function_name, *args, **kwargs):
    t = threading.Thread(target=function_name, args=args, kwargs=kwargs)
    t.daemon = True
    t.start()

def this_and_that(input_data, started=False, finished=False):
    for i in names_list:
        if started is True and finished is False:
            print(i, started, finished)
        elif started is True and finished is True:
            print(i, started, finished)
        else:
            print(i, started, finished)

n = ['Steve','Smith']

start_thread(this_and_that, n, started=True, finished=True)