繁体   English   中英

Python用类和访问类实例修饰函数

[英]Python decorate function with class and access class instance

我有一个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__() - 方法被调用两次。 此外,在__call__ -method之前__call__ performTCPConnection函数。 我现在想要的是, performTCPConnection函数将RemoteConnection类的实例返回到performTCPConnection函数中的变量。

如果我做了类似以下的事情:

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世界,就像实施战略模式一样。

不幸的是,到目前为止,我没有找到解释行为的良好解释。 这也是一个很好的设计方法吗?

我肯定会说这不是好设计。 这是一种在不使用继承机制的情况下有效获取继承的聪明方法,但它是非标准的,不直观的,不必要的,因为有更多直接的方法来完成所有这些。

@zmo的答案显示了如何正确设置派生类。 但我甚至不这样做:考虑将连接器对象与类本身分开,并设置类签名,如下所示:

class RemoteConnection(object):
    def __init__(self, connector):
        self.connection = connector

然后,您只需使用对正确连接器的引用来实例化它:

conn = RemoteConnection(TCPConnector(user, password))

这种方式RemoteConnection封装了与协议无关的功能,而与协议相关的部分是独立的功能或对象(如果您愿意,可以从公共类派生)。 如果在连接的生命周期中需要连接器,则保存连接器对象,以便稍后调用它。 如果没有,那么TCPConnection可以只返回您现在拥有的results值。

如果我关注你写的内容,我相信你过度设计了这个。 基本上,使用装饰器的策略将严格等同于:

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

我发现错误,我忘了在call ()-method中返回装饰函数的结果。

这解决了这个问题:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM