我有一个Python类,它将执行到服务器的远程连接。因为有几个协议(TCP / IP,HTTP)来访问相同的数据,这些数据可以根据情况使用(性能问题,...),我想使用该类作为封装的不同函数的装饰器实施。
我的班级看起来像这样:
class RemoteConnection(object):
def __init__(self, function):
self.function = function
self.results = None
def __call__(self, *args):
self.function(self, *args)
def setResults(*args):
self.results = args
@RemoteConnection
def performTCPConnection(instance, username, password):
#...perform connection
instance.setResults(results) #set the results of the connection (a query)
return instance
@RemoteConnection
def performHTTPConnection(instance, username, password):
#...perform connection
#and so on
if __name__ == '__main__':
performTCPConnection("admin", "admin") #OR
#performHTTPConnection("admin, "admin")
稍后应使用argparse
或其他内容将参数(超过用户名和密码,仅作为示例)提供给程序。
如果我像这样调用程序,由于装饰器,__init__()
- 方法被调用两次。此外,调用performTCPConnection
- 函数并调用__call__
- 方法之前。我现在想要的是,performTCPConnection
- 函数将RemoteConnection类的实例返回到main函数中的变量。
如果我执行以下操作:
foo = perfprmTCPConnection("admin","admin")
print foo
没有打印到StdOut。
如果我尝试访问performTCPConnection函数中的实例,那样:
@RemoteConnection
def performTCPConnection(instance, username, password):
#...perform connection
instance.setResults(results) #set the results of the connection (a query)
print instance
return instance
像<__main__.ServerConnection object at 0x7f4803516fd0>
这样的东西被写入StdOut。
我的想法有点像Java世界,就像实施战略模式一样。
不幸的是,直到现在我还没有找到解释行为的好解释。这也是一种很好的设计方法吗?
答案 0 :(得分:2)
我肯定会说这不是好设计。它是一种在不使用继承机制的情况下有效获取继承的聪明方法,但它是非标准的,不直观的,不必要的,因为有更多直接的方法来完成所有这些。
@zmo的答案显示了如何正确设置派生类。但我甚至不会这样做:考虑将连接器对象与类本身分开,并设置类签名,如下所示:
class RemoteConnection(object):
def __init__(self, connector):
self.connection = connector
然后,您只需使用对正确连接器的引用来实例化它:
conn = RemoteConnection(TCPConnector(user, password))
这种方式RemoteConnection
封装了与协议无关的函数,协议相关的部分是独立的函数或对象(如果你愿意,可以从公共类派生)。如果在连接的整个生命周期中需要连接器,则需要保存连接器对象,以便以后可以调用它。如果没有,则TCPConnection
可以返回您现在拥有的results
值。
答案 1 :(得分:1)
如果我按照你写的内容,我相信你过度设计了这个。基本上,使用装饰器的策略将严格等同于:
def performTCPConnection(username, password):
instance = RemoteConnection()
#...perform connection
instance.setResults(results) #set the results of the connection (a query)
return instance
但是读了你想要的东西,你还没有。因为如果我理解了您的模式中RemoteConnection
类的目的,那么在您调用.function()
方法时推迟连接。
所以你真正想要的是:
def prepareTCPConnection(username, password):
rc = RemoteConnection()
def connection_handler():
# perform the connection, and setup results
rc.setResults(results)
rc.function = connection_handler
return rc
你必须适当地适应RemoteConnection
。
在这里,你要做的是利用内部函数(和闭包)来定义一个在程序流程中稍后方便的点调用的函数。
但说实话,您可以使用简单的子类化以更简单的方式实现相同的目标:
class PerformConnection():
def __init__(self, username, password):
self.username = username
self.password = password
def perform(self):
raise NotImplementedError
class PerformConnectionTCP(PerformConnection):
def perform(self):
# do what you got to do here...
return results
然后在你的主要你可以做:
if __name__ == "__main__":
instance = PerformConnectionTCP('admin', 'admin')
instance.perform()
答案 2 :(得分:0)
我发现了错误,我忘了在调用() - 方法中返回修饰函数的结果。
这解决了这个问题:
class RemoteConnection(object):
def __init__(self, function):
self.function = function
self.results = None
def __call__(self, *args):
return self.function(self, *args) #here was the problem!
def setResults(*args):
self.results = args