1

背景: 頻繁に使用されるデータベース接続を開く関数があるとします。基本的には次のようなものですが、追加の機能があります。

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)

また、場合によっては、次のように 2 つの接続を開きたいことがあります。

read_connection = myspecialconnect()
write_connection = myspecialconnect()

なんという苦痛 - 私はパスワードを 2 回入力しなければなりません。もちろん、これを回避するためにこの 1 つの例を変更する方法はたくさんあります。この1つの機能。しかし、この特殊なケースにより、より一般的なアプリケーションについて考えるようになりました。myspecialconnect(multi=True)myspecialconnect(copies=9)

質問: 任意の関数からこの機能 (必要なものの複数のコピーを返す) を取得できるようにしたい場合はどうすればよいですか? うーん、これは難しいかもしれません。

まず、うまくいかないことを確認するために、これを試しました:

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

ユーザー入力を必要としない関数の場合は問題ありません。そうしないと、そこに座ってまったく同じことを 2 回続けて入力する必要があります。これは簡単に修正できますが、ここまでで、これがどこに向かっているのかを確認できるかもしれません。

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

このバージョンは、ユーザー入力を 1 回だけ受け取りますが、同じ参照を 2 回返すため、必要以上に複雑な方法になっています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__()

もちろん、これまでに、この小さな副次的な問題に正当化できる限り (またはそれ以上) の時間を費やしてきました。つまり、非常に興味があります。これは、何十ものケースをそれぞれ独自の特別な方法で明示的に処理することを余儀なくされたモンスターに変わることなく、任意のインスタンスのコピーを返す方法で行うことができますか?

4

2 に答える 2

2

あなたが望むことをするための一般的な方法はありません。最初の関数呼び出しを再生したいだけなら簡単です。最初の試行でうまくいきます。残念ながら、ユーザー入力を再生する必要があるため、状況が複雑になります。

まず、コピーは必要ありません。データベース接続をどのようにコピーしますか? 複製しなければならないネットワーク接続の反対側に状態があり、新しいポートを選択する必要があり、同じ状態とプロパティを持つという意味で実際にはコピーにはなりません。 . 古い接続と同じパラメーターで新しい接続を開きたいとします。

第 2 に、デコレータがどの入力を再生するかを知る方法がありません。同じ引数で関数を 2 回呼び出すのは簡単です。関数を 2 回呼び出して、最初の呼び出しから 2 番目の呼び出しへのユーザーの入力を再生するのは面倒ですが、可能です。ただし、デコレーターが最初の呼び出しから 2 番目の呼び出しまでのすべての入力を完全に再生しようとすると、データベースの TCP 応答も再生することになります。データベースと通信して接続をセットアップする代わりに、2 番目の呼び出しはデコレータと通信し、機能しない接続オブジェクトを返します。

double を試みる代わりに、myspecialconnectユーザー入力を読み取る必要のない関数を作成し、それを 2 倍にします。パスワードを 1 回読み取り、それを doubled 関数に渡します。

于 2013-07-19T18:59:34.757 に答える
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 (ひどい名前..) を作成し、それを拡張することで、より良くすることができます。

于 2013-07-19T18:29:01.527 に答える