首页 > 解决方案 > 如何将带参数的函数包装到带参数的包装器中?

问题描述

更新V2:好的,我在空闲时间写了一些代码并提出了这个想法。它有效,但我不知道为什么。这些代码之间有什么区别使其真正起作用?

类基础:

def __init__(self):
    self.prevention = [
        'targetDeceleration',
        'collisionPrevention',
        ]
    self.correct = []
    self.incorrect = []

def mapping(self, signal: list, data: list or np.ndarray, idx_list: list, filename: str, support: list = None):
    def outer_wrapper(func):
        def inner_wrapper(*args):
            for idx, sig in enumerate(signal):
                print(sig)
                if support:
                    print(support[idx])
                for idx_triplet in idx_list:
                    eth_idx, spi_idx, _ = idx_triplet
                    is_correct = func(sig, eth_idx, spi_idx, support)
                    if is_correct:
                        print('Correct')
                        self.correct.append(sig)
                    else:
                        print('Incorrect')
                        self.incorrect.append(sig)
                    print(filename)
        return inner_wrapper
    return outer_wrapper 

@abstractmethod
def mapping_check(self):
    pass

AEB 类(基础):

def __init__(self):
    super().__init__()

def mapping_check(self):
    data = np.full((4,), 5)
    idx_list = [
        [1, 1, 1]
    ]
    fname = 'FILENAME'
    
    @Base.mapping(
        self,
        signal=self.prevention,
        data=data,
        idx_list=idx_list,
        filename=fname,
        support=['idTarget', 'syncId']
    )
    def prevention_mapping(self, sig: list, eth_idx: int, spi_idx: int) -> bool:
        return eth_idx == spi_idx
    
    prevention_mapping()

更新:

@Functionality.mapping_functionality
    def id_target_object_fcm_mapping(eth_signal, spi_idx, eth_idx) -> bool:
        # FCF_VD_KEYS from A to E
        idx_A = FCF_VD_KEYS.index('A')
        idx_E = FCF_VD_KEYS.index('E')
        fcf_vd_keys = FCF_VD_KEYS[idx_A: idx_E + 1]
        # Check ETH and SPI mapping
        for key in fcf_vd_keys:
            # Check SPI mapping
            PDD_469_1_1 = FCF_VD_IDS['FCV'][spi_idx] == FCF_VD_IDS[key][spi_idx]
            PDD_469_1_2 = FCF_VD_ALERTS[key][spi_idx] == 43605
            PDD_469_1 = PDD_469_1_1 and PDD_469_1_2
            if PDD_469_1:
                # Check for appropriate idTargetObjectFCMCam values
                PDD_469_2 = eth_signal[eth_idx] == FCF_VD_IDS[key][spi_idx]
                if PDD_469_2:
                    return True

        # Check for default value
        IS_DEFAULT = eth_signal[eth_idx] == 0
        if IS_DEFAULT:
            return True
        # Otherwise return incorrect mapping
        return False


    def mapping_functionality(self):
    def inner_wrapper(function, eth_signal, pickle_data, idx_list, file_name, support_signal=None):
        print('inner wrapper')
        for idx, sig in enumerate(eth_signal):
            # Get ETH signal to be mapped
            eth_signal = Functionality.get_eth_signal(sig, pickle_data)
            # Load support signal
            if support_signal:
                support_signal = Functionality.get_eth_signal(support_signal[idx], pickle_data)
            for spi_idx, eth_idx, _ in idx_list:
                # Boolean storing info whether ETH was mapped correctly to the SPI signal
                # Update output
                is_mapping_correct = function(eth_signal, spi_idx, eth_idx, support_signal)
                if is_mapping_correct:
                    if self.result[sig] != self.incorrect:
                        self.result[sig] = self.correct
                else:
                    self.result[sig] = self.incorrect
                    if sig not in self.corrupted_files[file_name]:
                        self.corrupted_files[file_name][sig] = []
                    self.corrupted_files[file_name][sig].append([spi_idx, eth_idx])
    return inner_wrapper

不幸的是,在尝试运行代码后:

id_target_object_fcm_mapping(self.id_target_object_fcm_sig, pickle_data, idx_list, file_name)

我收到错误,mapping_functionality() 错过了 file_name 参数。我该如何解决?

所以基本上我想包装这个功能:

@Functionality.mapping_functionality(
        self=self,
        eth_signal=self.id_target_object_fcm_sig,
        pickle_data=pickle_data,
        idx_list=idx_list,
        file_name=file_name,
    )
    def id_target_object_fcm_mapping(eth_signal, spi_idx, eth_idx, *args) -> bool:
        # FCF_VD_KEYS from A to E
        idx_A = FCF_VD_KEYS.index('A')
        idx_E = FCF_VD_KEYS.index('E')
        fcf_vd_keys = FCF_VD_KEYS[idx_A: idx_E + 1]

        # Check ETH and SPI mapping
        for key in fcf_vd_keys:
            # Check SPI mapping
            PDD_469_1_1 = FCF_VD_IDS['FCV'][spi_idx] == FCF_VD_IDS[key][spi_idx]
            PDD_469_1_2 = FCF_VD_ALERTS[key][spi_idx] == 43605
            PDD_469_1 = PDD_469_1_1 and PDD_469_1_2
            if PDD_469_1:
                # Check for appropriate idTargetObjectFCMCam values
                PDD_469_2 = eth_signal[eth_idx] == FCF_VD_IDS[key][spi_idx]
                if PDD_469_2:
                    return True

        # Check for default value
        IS_DEFAULT = eth_signal[eth_idx] == 0
        if IS_DEFAULT:
            return True
        # Otherwise return incorrect mapping
        return False

进入一个将遍历索引并根据包装函数的布尔值更新电子表格的函数:

    def mapping_functionality(self, eth_signal, pickle_data, idx_list, file_name, support_signal=None):
    for idx, sig in enumerate(eth_signal):
        # Get ETH signal to be mapped
        eth_signal = Functionality.get_eth_signal(sig, pickle_data)

        # Load support signal
        if support_signal:
            support_signal = Functionality.get_eth_signal(support_signal[idx], pickle_data)

        def outer_wrapper(function):
            # Iterate over signal indices
            for spi_idx, eth_idx, _ in idx_list:
                # Boolean storing info whether ETH was mapped correctly to the SPI signal
                @wraps(function)
                def inner_wrapper():
                    is_mapping_correct = function(eth_signal, spi_idx, eth_idx, support_signal)
                    # Update output
                    if is_mapping_correct:
                        if self.result[sig] != self.incorrect:
                            self.result[sig] = self.correct
                    else:
                        self.result[sig] = self.incorrect
                        if sig not in self.corrupted_files[file_name]:
                            self.corrupted_files[file_name][sig] = []
                        self.corrupted_files[file_name][sig].append([spi_idx, eth_idx])
                    return inner_wrapper
        return outer_wrapper

不幸的是,在尝试调用该函数后:

id_target_object_fcm_mapping()

我收到以下错误:

TypeError: 'NoneType' object is not callable

我该如何解决这个问题?

标签: pythonpython-3.xpipelinewrapper

解决方案


由于您没有提供有关类对象以及您正在尝试做什么的信息,因此很难理解您的代码行为是否与修复预期的一样。

通常,最好简化问题并将其作为 SO 上的可重现示例提供。

假设您的潜在问题是标题所暗示的,

如何将带参数的函数包装到带参数的包装器中?

这是通过装饰器传递参数的一般结构如下。希望这可以帮助 -

def decorator_function(n):
    def outer_wrapper(f):
        def inner_wrapper(*args, **kwargs):
            out = f(*args, **kwargs)**n
            return out
        return inner_wrapper
    return outer_wrapper

@decorator_function(4)        #<- Decorator with argument
def function(x, m):
    return x/m

print(function(10,3))
print((10/3)**4)
123.45679012345681
123.45679012345681

原始函数x将其除以m。包装器接受n并将其作为原始函数输出的幂,因此,(x/m)^n


编辑:只是添加创建嵌套装饰器函数的 lambda 函数方法,因为我个人觉得它们更具可读性(很奇怪吧?)

decorator = lambda n:lambda f:lambda *args, **kwargs: f(*args, **kwargs)**n

@decorator(4)
def function(x, m):
    return x/m

function(10,3)
123.45679012345681

你可以很容易地看到这里发生了什么 -

   lambda n:lambda f:lambda *args, **kwargs: f(*args, **kwargs)**n
#  |                 |                       |________________|  | |
#  |                 |                        original function  | |
#  |                 |___________________________________________| |
#  |                  wrapper takes in f and returns inner lambda  |
#  |_______________________________________________________________|
#       outer function takes n parameter and returns wrapper


推荐阅读