背景: 假设我们有一个打开常用数据库连接的函数,基本上类似于以下内容,但有额外的花里胡哨:
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)
也许有时,我们想打开两个连接,大致如下:
read_connection = myspecialconnect()
write_connection = myspecialconnect()
多么痛苦-我必须输入两次密码,而我想要的只是再次相同的东西。当然,有很多方法可以修改这个例子来避免这种情况 -例如,可以添加一个参数,比如myspecialconnect(multi=True)
返回两个连接而不是一个,或者myspecialconnect(copies=9)
如果你想发疯,使用相应的代码来实现它这一功能。然而,这种特殊情况促使我想知道一个更通用的应用程序。
问题:如果我希望能够从任意函数获得此功能(返回我们想要的任何内容的多个副本)怎么办?嗯 - 这可能很棘手。
首先,为了确认它不起作用,我尝试了这个:
def doubled(function):
def Wrapper(*args, **kwargs):
return (function(*args, **kwargs),function(*args, **kwargs))
return Wrapper
这对于不需要用户输入的功能来说是可以的;否则,您仍然必须坐在那里连续两次输入完全相同的内容。这很容易解决,但现在您可能已经知道这是怎么回事了:
def doubled(function):
def Wrapper(*args, **kwargs):
result = function(*args, **kwargs)
return (result, result)
return Wrapper
这个版本只接受用户输入一次,但它两次返回相同的引用,这只不过是一种不必要的复杂方式foo = bar = object()
。“啊哈!” 我说,“也许我应该看看这个copy
模块。” 这就是我所做的,只是我不太清楚它是如何工作的......
>>> 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__()
当然,到目前为止,我已经在这个小问题上花费了尽可能多的时间(或更多时间),这意味着我非常好奇。这可以通过返回任意实例副本的方式来完成,而不会变成一个被迫明确处理数十个案例的怪物,每个案例都以自己的特殊方式?