mirror of
https://github.com/python/cpython.git
synced 2024-11-23 18:04:37 +08:00
bpo-45735: Promise the long-time truth that args=list
works (GH-30982)
For threads, and for multiprocessing, it's always been the case that ``args=list`` works fine when passed to ``Process()`` or ``Thread()``, and such code is common in the wild. But, according to the docs, only a tuple can be used. This brings the docs into synch with reality. Doc changes by Charlie Zhao. Co-authored-by: Tim Peters <tim.peters@gmail.com>
This commit is contained in:
parent
5ab745fc51
commit
e466faa9df
@ -485,7 +485,9 @@ The :mod:`multiprocessing` package mostly replicates the API of the
|
||||
to ``True`` or ``False``. If ``None`` (the default), this flag will be
|
||||
inherited from the creating process.
|
||||
|
||||
By default, no arguments are passed to *target*.
|
||||
By default, no arguments are passed to *target*. The *args* argument,
|
||||
which defaults to ``()``, can be used to specify a list or tuple of the arguments
|
||||
to pass to *target*.
|
||||
|
||||
If a subclass overrides the constructor, it must make sure it invokes the
|
||||
base class constructor (:meth:`Process.__init__`) before doing anything else
|
||||
@ -503,6 +505,19 @@ The :mod:`multiprocessing` package mostly replicates the API of the
|
||||
the target argument, if any, with sequential and keyword arguments taken
|
||||
from the *args* and *kwargs* arguments, respectively.
|
||||
|
||||
Using a list or tuple as the *args* argument passed to :class:`Process`
|
||||
achieves the same effect.
|
||||
|
||||
Example::
|
||||
|
||||
>>> from multiprocessing import Process
|
||||
>>> p = Process(target=print, args=[1])
|
||||
>>> p.run()
|
||||
1
|
||||
>>> p = Process(target=print, args=(1,))
|
||||
>>> p.run()
|
||||
1
|
||||
|
||||
.. method:: start()
|
||||
|
||||
Start the process's activity.
|
||||
|
@ -314,7 +314,7 @@ since it is impossible to detect the termination of alien threads.
|
||||
or "Thread-*N* (target)" where "target" is ``target.__name__`` if the
|
||||
*target* argument is specified.
|
||||
|
||||
*args* is the argument tuple for the target invocation. Defaults to ``()``.
|
||||
*args* is a list or tuple of arguments for the target invocation. Defaults to ``()``.
|
||||
|
||||
*kwargs* is a dictionary of keyword arguments for the target invocation.
|
||||
Defaults to ``{}``.
|
||||
@ -353,6 +353,19 @@ since it is impossible to detect the termination of alien threads.
|
||||
the *target* argument, if any, with positional and keyword arguments taken
|
||||
from the *args* and *kwargs* arguments, respectively.
|
||||
|
||||
Using list or tuple as the *args* argument which passed to the :class:`Thread`
|
||||
could achieve the same effect.
|
||||
|
||||
Example::
|
||||
|
||||
>>> from threading import Thread
|
||||
>>> t = Thread(target=print, args=[1])
|
||||
>>> t.run()
|
||||
1
|
||||
>>> t = Thread(target=print, args=(1,))
|
||||
>>> t.run()
|
||||
1
|
||||
|
||||
.. method:: join(timeout=None)
|
||||
|
||||
Wait until the thread terminates. This blocks the calling thread until
|
||||
|
@ -247,6 +247,30 @@ class _TestProcess(BaseTestCase):
|
||||
self.assertEqual(current.ident, os.getpid())
|
||||
self.assertEqual(current.exitcode, None)
|
||||
|
||||
def test_args_argument(self):
|
||||
# bpo-45735: Using list or tuple as *args* in constructor could
|
||||
# achieve the same effect.
|
||||
args_cases = (1, "str", [1], (1,))
|
||||
args_types = (list, tuple)
|
||||
|
||||
test_cases = itertools.product(args_cases, args_types)
|
||||
|
||||
for args, args_type in test_cases:
|
||||
with self.subTest(args=args, args_type=args_type):
|
||||
q = self.Queue(1)
|
||||
# pass a tuple or list as args
|
||||
p = self.Process(target=self._test_args, args=args_type((q, args)))
|
||||
p.daemon = True
|
||||
p.start()
|
||||
child_args = q.get()
|
||||
self.assertEqual(child_args, args)
|
||||
p.join()
|
||||
close_queue(q)
|
||||
|
||||
@classmethod
|
||||
def _test_args(cls, q, arg):
|
||||
q.put(arg)
|
||||
|
||||
def test_daemon_argument(self):
|
||||
if self.TYPE == "threads":
|
||||
self.skipTest('test not appropriate for {}'.format(self.TYPE))
|
||||
|
@ -123,6 +123,32 @@ class ThreadTests(BaseTestCase):
|
||||
thread = threading.Thread(target=func)
|
||||
self.assertEqual(thread.name, "Thread-5 (func)")
|
||||
|
||||
def test_args_argument(self):
|
||||
# bpo-45735: Using list or tuple as *args* in constructor could
|
||||
# achieve the same effect.
|
||||
num_list = [1]
|
||||
num_tuple = (1,)
|
||||
|
||||
str_list = ["str"]
|
||||
str_tuple = ("str",)
|
||||
|
||||
list_in_tuple = ([1],)
|
||||
tuple_in_list = [(1,)]
|
||||
|
||||
test_cases = (
|
||||
(num_list, lambda arg: self.assertEqual(arg, 1)),
|
||||
(num_tuple, lambda arg: self.assertEqual(arg, 1)),
|
||||
(str_list, lambda arg: self.assertEqual(arg, "str")),
|
||||
(str_tuple, lambda arg: self.assertEqual(arg, "str")),
|
||||
(list_in_tuple, lambda arg: self.assertEqual(arg, [1])),
|
||||
(tuple_in_list, lambda arg: self.assertEqual(arg, (1,)))
|
||||
)
|
||||
|
||||
for args, target in test_cases:
|
||||
with self.subTest(target=target, args=args):
|
||||
t = threading.Thread(target=target, args=args)
|
||||
t.start()
|
||||
|
||||
@cpython_only
|
||||
def test_disallow_instantiation(self):
|
||||
# Ensure that the type disallows instantiation (bpo-43916)
|
||||
|
@ -852,7 +852,7 @@ class Thread:
|
||||
*name* is the thread name. By default, a unique name is constructed of
|
||||
the form "Thread-N" where N is a small decimal number.
|
||||
|
||||
*args* is the argument tuple for the target invocation. Defaults to ().
|
||||
*args* is a list or tuple of arguments for the target invocation. Defaults to ().
|
||||
|
||||
*kwargs* is a dictionary of keyword arguments for the target
|
||||
invocation. Defaults to {}.
|
||||
|
Loading…
Reference in New Issue
Block a user