使用Python装饰器分解共享数据验证

使用Python装饰器分解共享数据验证,python,python-decorators,Python,Python Decorators,我在一个项目类中具有以下两个功能: def stage_changes(self, change_set_name): change_set_id = self._get_change_set_id(change_set_name) # Perform validation on change set ID self._stage_changes_internal(change_set_id) def commit_changes(self, change_set_na

我在一个项目类中具有以下两个功能:

def stage_changes(self, change_set_name):
    change_set_id = self._get_change_set_id(change_set_name)
    # Perform validation on change set ID
    self._stage_changes_internal(change_set_id)

def commit_changes(self, change_set_name):
    change_set_id = self._get_change_set_id(change_set_name)
    # Perform validation on change set ID (same validation as first function)
    # Perform some other computation using change set ID
    self._commit_changes_internal(change_set_id, ...)
我希望从这些函数中考虑前两个共享行,即

change_set_id = self._get_change_set_id(change_set_name)
# Perform validation on change set ID
我的问题是:

  • 在这里使用decorator真的有意义吗?或者在我应该只调用一个简单的helper函数的地方,我是不是太有创意了
  • 如果使用装潢师确实有意义,我将如何着手构建它?这样做似乎很麻烦,因为我需要在公共尾声中计算的值来在每个函数中执行额外的计算(即,共享逻辑不仅仅产生副作用,它还返回一个值)

  • 正如您提到的,您可以使用辅助函数应用DRY原理。 我认为更多的是关于个人品味,在这里使用助手或装饰功能。 但作为一名装饰师,它可能看起来像这样:

    from functools import wraps
    
    def validateData(fn):
        @wraps(fn)
        def wrapper(*args, **kw):
            cls = args[0]
            change_set_name = args[1]
    
            if change_set_name in ('bar', 'foobar'):
                kw['change_set_id'] = 1
            else:
                kw['change_set_id'] = None
    
            return fn(*args, **kw)
        return wrapper
    
    
    class Foo():
        @validateData
        def stage_changes(self, change_set_name, change_set_id=None):
            print('change_set_id in stage_changes:', change_set_id)
            # Perform validation on change set ID
            #self._stage_changes_internal(change_set_id)
    
        @validateData
        def commit_changes(self, change_set_name, change_set_id=None):
            #change_set_id = self._get_change_set_id(change_set_name)
            print('change_set_id in commit_changes:', change_set_id)
            # Perform validation on change set ID (same validation as first function)
            # Perform some other computation using change set ID
            #self._commit_changes_internal(change_set_id, ...)
    
    f = Foo()
    f.stage_changes('bar')
    f.stage_changes('banana')
    
    印刷品:

    change_set_id in stage_changes: 1
    change_set_id in stage_changes: None
    

    正如您提到的,您可以使用辅助函数应用DRY原理。 我认为更多的是关于个人品味,在这里使用助手或装饰功能。 但作为一名装饰师,它可能看起来像这样:

    from functools import wraps
    
    def validateData(fn):
        @wraps(fn)
        def wrapper(*args, **kw):
            cls = args[0]
            change_set_name = args[1]
    
            if change_set_name in ('bar', 'foobar'):
                kw['change_set_id'] = 1
            else:
                kw['change_set_id'] = None
    
            return fn(*args, **kw)
        return wrapper
    
    
    class Foo():
        @validateData
        def stage_changes(self, change_set_name, change_set_id=None):
            print('change_set_id in stage_changes:', change_set_id)
            # Perform validation on change set ID
            #self._stage_changes_internal(change_set_id)
    
        @validateData
        def commit_changes(self, change_set_name, change_set_id=None):
            #change_set_id = self._get_change_set_id(change_set_name)
            print('change_set_id in commit_changes:', change_set_id)
            # Perform validation on change set ID (same validation as first function)
            # Perform some other computation using change set ID
            #self._commit_changes_internal(change_set_id, ...)
    
    f = Foo()
    f.stage_changes('bar')
    f.stage_changes('banana')
    
    印刷品:

    change_set_id in stage_changes: 1
    change_set_id in stage_changes: None