[New-bugs-announce] [issue17435] threading.Timer.__init__() should use immutable argument defaults for args and kwargs

Denver Coneybeare report at bugs.python.org
Sat Mar 16 01:17:20 CET 2013


New submission from Denver Coneybeare:

The __init__() method of threading.Timer uses *mutable* default values for the "args" and "kwargs" arguments.  Since the default argument objects are created once and re-used for each instance, this means that changing the args list or kwargs dict of a Timer object that used the argument defaults will specify those arguments to all future Timer objects that use the defaults too.

def __init__(self, interval, function, args=[], kwargs={}):

A fully backwards-compatible way to fix this is to instead use None as the default value for args and kwargs and just create a new list and/or dict inside __init__() if they are None.  That way each new instance of Timer will get its very own args list and kwargs dict object.

def __init__(self, interval, function, args=None, kwargs=None):
    ...
    self.args = args if args is not None else []
    self.kwargs = kwargs if kwargs is not None else {}

Here is a sample script that reproduces the issue:

    import threading

    event = threading.Event()
    def func(*args, **kwargs):
        print("args={!r} kwargs={!r}".format(args, kwargs))
        event.set()

    timer1 = threading.Timer(1, func)
    timer1.args.append("blah")
    timer1.kwargs["foo"] = "bar"

    timer2 = threading.Timer(1, func)
    timer2.start()
    event.wait()

Here is the example output when run before the fix:

c:\dev\cpython>PCbuild\python_d.exe ThreadingTimerInitDefaultArgsIssueDemo.py
args=('blah',) kwargs={'foo': 'bar'}
[44758 refs, 17198 blocks]

And after the fix:

c:\dev\cpython>PCbuild\python_d.exe ThreadingTimerInitDefaultArgsIssueDemo.py
args=() kwargs={}
[47189 refs, 18460 blocks]

As you can see, in the version without the fix, the elements added to timer1's args and kwargs were also given to timer2, which is almost certainly not what a user would expect.

A proposed patch, ThreadingTimerInitDefaultArgsIssueDemo.01.patch, is attached.  This fixes the issue, updates the docs, and adds a unit test.

----------
components: Library (Lib)
files: ThreadingTimerInitDefaultArgsIssueDemo.01.patch
keywords: patch
messages: 184278
nosy: denversc
priority: normal
severity: normal
status: open
title: threading.Timer.__init__() should use immutable argument defaults for args and kwargs
type: behavior
versions: Python 2.7, Python 3.1, Python 3.2, Python 3.3, Python 3.4
Added file: http://bugs.python.org/file29422/ThreadingTimerInitDefaultArgsIssueDemo.01.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue17435>
_______________________________________


More information about the New-bugs-announce mailing list