gpt4 book ai didi

python - 通用函数/对象加倍装饰器在 Python 中是否可行?

转载 作者:行者123 更新时间:2023-12-01 05:40:10 26 4
gpt4 key购买 nike

背景:假设我们有一个打开常用数据库连接的函数,其本质上类似于以下内容,但具有附加功能:

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__()

当然,到目前为止,我已经在这个小问题上花费了尽可能多的时间(或更多),这意味着我非常好奇。是否可以通过返回任意实例的副本的方式来完成此操作,而不会变成被迫显式处理数十个案例的怪物,每个案例都以自己的特殊方式?

最佳答案

没有通用的方法可以做你想做的事。如果您只想重播第一个函数调用,那会很简单 - 您的第一次尝试就会成功。不幸的是,重放用户输入的要求使事情变得复杂。

首先,您不需要副本。如何复制数据库连接?网络连接的另一端有您必须复制的状态,并且您必须选择新端口,并且从具有相同状态和属性的意义上来说,它最终不会真正成为副本。您想要使用与旧连接相同的参数打开一个新连接。

其次,装饰器无法知道要重播哪些输入。使用相同的参数调用一个函数两次很容易。调用一个函数两次,将用户的输入从第一次调用重播到第二次调用,虽然很困惑,但也是可能的。但是,如果装饰器尝试将第一次调用的所有输入重播到第二次调用,那么它最终也会重播数据库的 TCP 响应。第二次调用不会与数据库通信并建立连接,而是与装饰器通信并返回一个不起作用的连接对象。

不要尝试加倍 myspecialconnect,而是创建一个不需要读取用户输入的函数并将其加倍。读取密码一次,然后将其传递到双倍函数中。

关于python - 通用函数/对象加倍装饰器在 Python 中是否可行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17751480/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com