Is a general-purpose function/object doubling decorator feasible in Python?
Question: **Background:** Let's say that we have a function that opens a frequently-used
database connection, something essentially like the following but with
additional bells and whistles:

    
    
    import getpass
    
    import MySQLdb
    
    def myspecialconnect(user='foo', host='bar', port=80085):
        password = getpass.getpassword('Enter your password: ')
        return MySQLdb.connect(user, password, host, port)
    

And maybe sometimes, we want to open two connections, along the lines of:

    
    
    read_connection = myspecialconnect()
    write_connection = myspecialconnect()
    

What a pain - I have to enter my password twice, when all I want is the same
thing again. Of course, there are many ways to modify this one example to
avoid that - _for example_ , an argument could be added like
`myspecialconnect(multi=True)` to return two connections instead of one, or
`myspecialconnect(copies=9)` if you want to get crazy, with the corresponding
code to make that happen inside this one function. However, this special case
prompted me to wonder about a more general application.

**Question** : What if I wanted to be able to get this functionality (return
multiple copies of whatever we want) from any arbitrary function? Hmm - this
could be tricky.

First, just to confirm that it doesn't work, I tried this:

    
    
    def doubled(function):
        def Wrapper(*args, **kwargs):
            return (function(*args, **kwargs),function(*args, **kwargs))
        return Wrapper
    

That's okay for a function that requires no user input; otherwise, you still
have to sit there and input the exact same thing twice in a row. That's easy
enough to fix, but by now you might be able to see where this is going:

    
    
    def doubled(function):
        def Wrapper(*args, **kwargs):
            result = function(*args, **kwargs)
            return (result, result)
        return Wrapper
    

This version takes user input only once, but it returns the same reference
twice, making it nothing more than a needlessly convoluted way to do `foo =
bar = object()`. "Aha!" says I, "maybe I should take a look at the `copy`
module." Which is what I did, only I don't quite know how it works yet...

    
    
    >>> import copy
    >>> a = (i for i in [1,2])
    >>> a
    <generator object <genexpr> at 0x03FB0878>
    >>> copy.copy(a)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy.py", line 96, in copy
        return _reconstruct(x, rv, 0)
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy.py", line 329, in _reconstruct
        y = callable(*args)
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy_reg.py", line 93, in __newobj__
        return cls.__new__(cls, *args)
    TypeError: object.__new__(generator) is not safe, use generator.__new__()
    >>> copy.deepcopy(a)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy.py", line 190, in deepcopy
        y = _reconstruct(x, rv, 1, memo)
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy.py", line 329, in _reconstruct
        y = callable(*args)
      File "C:\WinPython-32bit-2.7.5.1\python-2.7.5\lib\copy_reg.py", line 93, in __newobj__
        return cls.__new__(cls, *args)
    TypeError: object.__new__(generator) is not safe, use generator.__new__()
    

Of course by now I've spent about as much time as I can possibly justify (or
more) on this little side problem, which means I'm incredibly curious. Can
this be done in a way that returns copies of arbitrary instances, without
turning into a monster that is forced to explicitly handle dozens of cases,
each in their own special way?


Answer: There's no general way to do what you want. It'd be simple if you just wanted
to replay the first function call - your first try would've worked.
Unfortunately, the requirement to replay user input complicates things.

First, you don't want a copy. How would you copy a database connection?
There's state over on the other side of a network connection that you'd have
to duplicate, and you'd have to pick new ports, and it wouldn't end up really
being a copy in the sense of having the same state and properties. You want to
open up a new connection with the same parameters as the old one.

Second, there's no way for the decorator to know which inputs to replay.
Calling a function twice with the same arguments is easy. Calling a function
twice, replaying the user's input from the first call into the second call, is
messy but possible. However, if the decorator tried to replay absolutely all
input from the first call into the second call, it would end up replaying the
database's TCP responses, too. Instead of talking to the database and setting
up a connection, the second call would talk to the decorator and return a
connection object that doesn't work.

Instead of trying to double `myspecialconnect`, make a function that doesn't
need to read user input and double that. Read the password once, then pass
that into a doubled function.

