我应该装饰一个函数吗?

时间:2015-08-16 19:15:50

标签: python

尝试确定我是否应该尝试使用装饰器或其他一些Pythonic方法来减少我的许多函数正在执行的代码。我希望这些函数能够在每个函数的开头调用可能的另一个函数,或以某种方式“装饰”每个函数的开头。我之前从未使用过装饰器,并且正在努力以pythonic方式实现这种装饰思想,以减少每个函数的共同代码集。

我有很多函数会在函数开始时执行相同的一组步骤。但是,公共代码存在一些结构问题,使得这个“装饰者”的想法变得困难:

  • 这些函数都在父类的子类中。

  • 函数之间的通用命令引用变量名称 特定于函数的函数(但函数的子集 名称)。

  • 常用命令需要返回调用者而不执行任何操作 如果满足某个条件,则更多的子功能。 (“if jobj:”示例代码中的块)

对于变量/属性示例,子函数get_nas_server(self)将在公共代码集中使用“nas_server”变量变量。从函数名中减去get_会显示要在公共代码集中使用的变量名的基础。从“get_nas_server”函数名称派生的示例变量名称和对象属性:

nas_server
nas_server.json
self.nas_server(属性)

以下是其中一个功能的公共代码:

        ####################################################################
        def get_nas_server(self):
        ####################################################################
            """\nGets COMMAND nas_server and places data into self.nas_server"""

           try:
               self.nas_server
               return self.nas_server
           except AttributeError:
               pass
           self.get_file_cmd('nas_server')
           jobj = self.fresh_json('nas_server.json')
           if jobj :
               self.nas_server = jobj
               return self.nas_server
           self.get_file_cmd('get_nas_server')

函数中上面代码下面的所有内容都是特定于功能目的,不适合在此讨论。基本上我试图在我的函数中重复使用上面的所有代码,但代码必须根据函数名称更改变量和属性。

感谢您阅读,如果您有这么远,感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

似乎你可以在父类中定义为辅助方法:

class Parent(object):
    def _get_something(name):
        try:
            return getattr(self, name)
        except AttributeError:
            pass
       self.get_file_cmd(name)
       jobj = self.fresh_json(name+'.json')
       if jobj :
           setattr(self, name, jobj)
           return jobj
       self.get_file_cmd('get_'+name)

正如此代码段所示,您可以使用getattr()setattr()hasattr()函数按名称引用对象属性。

答案 1 :(得分:1)

如果初始簿记内容对于该类太具体,您可以在课堂内使用装饰器。每次你需要在类方法中进行初始检查时,你可以使用我在下面添加的auto_nas装饰器来装饰它。我假设,这个包装器的范围仅针对这个类。否则,您可以将其移到课堂之外以获得一般性,但如果您打算这样做,请记得更改(self=None)

class YourMainClass():
    # This is your main class inside which all the methods are defined.

    def auto_nas(func):
        # This wrapper function will be called instead of your class methods.
        def wrap(self):
            # All your bookkeeping stuff goes here.
            try:
               self.nas_server
               return self.nas_server
            except AttributeError:
               pass
            self.get_file_cmd('nas_server')
            jobj = self.fresh_json('nas_server.json')
            if jobj :
               self.nas_server = jobj
               return self.nas_server
            self.get_file_cmd('get_nas_server')
            # Things went well - we shall call the actual method.
            return func(self)
        return wrap

    @auto_nas
    def get_nas_server(self):
        # This is one of your methods that require bookkeeping
        pass

另外,请注意包装函数中的self。它由Python自动作为参数传递,因此您可以从该装饰器内部访问所有特定于实例的属性。再一次,如果您的装饰者必须针对您班级的每个实例执行特定工作,这是合适的。如果不是这样,你可以简单地将所有代码放在一个函数中,并在每次需要时调用它。

答案 2 :(得分:0)

非常感谢Augurar指出正确的方向。我最终在父类中创建了一个存根方法。只需要用适当的技术调用该方法来“扩展”父方法。然后使用super()从子类调用该stub方法这个技术必须有一个合适的名称?方法覆盖?方法扩展?

这是父类方法,主要是因为Augurar建议:

###########################################################################
def get_stub(self,fcmd):
###########################################################################
    try:
        return getattr(self, fcmd)
    except AttributeError:
        pass
    jobj = self.fresh_json(fcmd + '.json')
    if jobj :
        setattr(self, fcmd, jobj)
        return jobj
    if not self.get_file_cmd(fcmd):
        self.log.error("{} not found".format(fcmd))
        return False

以下是子方法使用此父方法的方式:

####################################################################
def get_nas_server(self):
####################################################################
  super().get_stub('nas_server')
  #bunch of child method specific code below here