背景 假设我们有一个函数可以打开一个经常使用的数据库连接,这个函数基本上类似于以下内容,但有额外的功能和口哨:
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)
一样添加一个参数来返回两个连接而不是一个,或{{1}如果你想变得疯狂,用相应的代码来实现这一功能。然而,这个特殊情况促使我想知道更普遍的应用。
问题:如果我想从任意函数中获得此功能(返回我们想要的任何内容的多个副本)该怎么办?嗯 - 这可能很棘手。
首先,为了确认它不起作用,我尝试了这个:
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
当然,到目前为止,我已经花了相当多的时间来证明(或更多)这个小问题,这意味着我非常好奇。这可以通过返回任意实例的副本的方式完成,而不会变成一个被迫明确处理几十个案例的怪物,每个案例都以他们自己的特殊方式进行吗?
答案 0 :(得分:2)
没有一般方法可以做你想要的。如果你只想重播第一个函数调用就很简单 - 你的第一次尝试就行了。不幸的是,重放用户输入的要求使事情变得复杂。
首先,您不需要副本。你会如何复制数据库连接?在网络连接的另一端有状态,你必须复制,你必须选择新的端口,并且它不会真正成为一个副本,具有相同的状态和属性。您希望使用与旧参数相同的参数打开新连接。
其次,装饰者无法知道要重放的输入。使用相同的参数调用函数很容易。调用一个函数两次,将用户输入从第一次调用重放到第二次调用,是很麻烦但可能。但是,如果装饰器试图将第一次调用中的所有输入重放到第二次调用中,那么它最终也会重放数据库的TCP响应。第二次调用将与装饰器通信并返回不起作用的连接对象,而不是与数据库通信并建立连接。
不要试图加倍myspecialconnect
,而是创建一个不需要读取用户输入并将其加倍的函数。读取密码一次,然后将其传递给双重功能。
答案 1 :(得分:0)
编辑:
如果我理解你的问题以及一个例子,这是一个通用的解决方案。
generator = None
def getObject(askOnce = None, createFunction = None, *args):
global generator
if generator is None:
askOnceValue = askOnce()
generator = getGenerator(askOnceValue, createFunction, *args)
return generator.next()
def getGenerator(askOnceValue, createFunction, *args):
while(True):
yield createFunction(askOnceValue, *args)
def myInputFunction():
return "Some dynamic value"
def myCreateFunction(myInput, arg1, arg2):
return list([myInput, arg1, arg2])
myObj1 = getObject(myInputFunction, myCreateFunction, "hello", 1234)
print(myObj1)
myObj2 = getObject()
print(myObj2)
通过创建一个类CopyableObject(可怕的名称..)然后扩展它可以使这更好。