【问题标题】:*args and other parameters in decorated function in python* args和python中装饰函数中的其他参数
【发布时间】:2023-03-20 05:31:01
【问题描述】:

我有以下脚本可以正常工作。装饰器on_or_off 从函数中获取on_switch 的值,如果其值为True,则执行。

import pandas as pd
import ctypes
import sec4_analysis as analysis

# Main class
######################################################################
class Analysis_ProjectX_Demographic(analysis.Analysis_ProjectX):
    def __init__(self):
        super()
        super().__init__()

    def demographic_analytic_steps(self):
        self.import_parent_ref_data()
        self.import_master_data()
        self.recategorize_var(on_switch=True)
        self.result_in_plaintext(on_switch=True)
        self.result_in_csv(on_switch=True)

    # Decorators
    def on_or_off(func):
        def wrapper(self, on_switch, *args):
            if on_switch:
                func(self, on_switch, *args)
        return wrapper

    # Core class functions
    @on_or_off
    def recategorize_var(self, on_switch=False):
        self.df_master_filtered = self.recat_binary(self.df_master_filtered, 'INDEX_RURAL', 'INDEX_RURAL_CAT', 0, 'URBAN', 1, 'RURAL')
        self.df_master_filtered = self.recat_age(self.df_master_filtered, 'INDEX_AGE', 'INDEX_AGE_CAT')

    @on_or_off
    def result_in_plaintext(self, on_switch=False):
        df_dict = {
            'TxGroup':self.df_master_filtered, 
            }
        for df_key, df in df_dict.items():
            print ('Dataset name: {}'.format(df_key))
            print ('Unique patients, n: {}'.format(df['PHN_ENC'].nunique()))
            self.descriptive_num_var_results(df_key, df, 'INDEX_AGE')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_AGE_CAT')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_RURAL_CAT')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_SEX')

    @on_or_off
    def result_in_csv(self, on_switch=False):
        pass

    # Helper functions
    def recat_binary(self, df, old_var, new_var, old_val1, new_val1, old_val2, new_val2):
        df.loc[df[old_var] == old_val1, new_var] = new_val1 
        df.loc[df[old_var] == old_val2, new_var] = new_val2 
        return df

    def recat_age(self, df, old_var, new_var):
        df.loc[(df[old_var]>=19.00)&(df[old_var]<25.00), new_var] = '19-24'
        df.loc[(df[old_var]>=25.00)&(df[old_var]<30.00), new_var] = '25-29'
        df.loc[(df[old_var]>=30.00)&(df[old_var]<35.00), new_var] = '30-34'
        df.loc[(df[old_var]>=35.00)&(df[old_var]<40.00), new_var] = '35-39'
        df.loc[(df[old_var]>=40.00)&(df[old_var]<45.00), new_var] = '40-44'
        df.loc[(df[old_var]>=45.00)&(df[old_var]<50.00), new_var] = '45-49'
        df.loc[(df[old_var]>=50.00)&(df[old_var]<55.00), new_var] = '50-54'
        df.loc[(df[old_var]>=55.00)&(df[old_var]<60.00), new_var] = '55-59'
        df.loc[(df[old_var]>=60.00)&(df[old_var]<65.00), new_var] = '60-64'
        df.loc[(df[old_var]>=65.00)&(df[old_var]<300.00), new_var] = '65/above'
        return df

x = Analysis_ProjectX_Demographic()
x.demographic_analytic_steps()

但是,除了on_switch 之外,装饰函数应该可以有任意数量的参数。当我在result_in_plaintext.() 中引入更多参数some_text 时。

import pandas as pd
import ctypes
import sec4_analysis as analysis

# Main class
######################################################################
class Analysis_ProjectX_Demographic(analysis.Analysis_ProjectX):
    def __init__(self):
        super()
        super().__init__()

    def demographic_analytic_steps(self):
        self.import_parent_ref_data()
        self.import_master_data()
        self.recategorize_var(on_switch=True)
        self.result_in_plaintext(some_text='This is done', on_switch=True)
        self.result_in_csv(on_switch=True)

    # Decorators
    def on_or_off(func):
        def wrapper(self, on_switch, *args):
            if on_switch:
                func(self, on_switch, *args)
        return wrapper

    # Core class functions
    @on_or_off
    def recategorize_var(self, on_switch=False):
        self.df_master_filtered = self.recat_binary(self.df_master_filtered, 'INDEX_RURAL', 'INDEX_RURAL_CAT', 0, 'URBAN', 1, 'RURAL')
        self.df_master_filtered = self.recat_age(self.df_master_filtered, 'INDEX_AGE', 'INDEX_AGE_CAT')

    @on_or_off
    def result_in_plaintext(self, some_text, on_switch=False):
        df_dict = {
            'TxGroup':self.df_master_filtered, 
            }
        for df_key, df in df_dict.items():
            print ('Dataset name: {}'.format(df_key))
            print ('Unique patients, n: {}'.format(df['PHN_ENC'].nunique()))
            self.descriptive_num_var_results(df_key, df, 'INDEX_AGE')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_AGE_CAT')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_RURAL_CAT')
            self.descriptive_cat_var_results(df_key, df, 'INDEX_SEX')

        print(some_text)

    @on_or_off
    def result_in_csv(self, on_switch=False):
        pass

    # Helper functions
    def recat_binary(self, df, old_var, new_var, old_val1, new_val1, old_val2, new_val2):
        df.loc[df[old_var] == old_val1, new_var] = new_val1 
        df.loc[df[old_var] == old_val2, new_var] = new_val2 
        return df

    def recat_age(self, df, old_var, new_var):
        df.loc[(df[old_var]>=19.00)&(df[old_var]<25.00), new_var] = '19-24'
        df.loc[(df[old_var]>=25.00)&(df[old_var]<30.00), new_var] = '25-29'
        df.loc[(df[old_var]>=30.00)&(df[old_var]<35.00), new_var] = '30-34'
        df.loc[(df[old_var]>=35.00)&(df[old_var]<40.00), new_var] = '35-39'
        df.loc[(df[old_var]>=40.00)&(df[old_var]<45.00), new_var] = '40-44'
        df.loc[(df[old_var]>=45.00)&(df[old_var]<50.00), new_var] = '45-49'
        df.loc[(df[old_var]>=50.00)&(df[old_var]<55.00), new_var] = '50-54'
        df.loc[(df[old_var]>=55.00)&(df[old_var]<60.00), new_var] = '55-59'
        df.loc[(df[old_var]>=60.00)&(df[old_var]<65.00), new_var] = '60-64'
        df.loc[(df[old_var]>=65.00)&(df[old_var]<300.00), new_var] = '65/above'
        return df

x = Analysis_ProjectX_Demographic()
x.demographic_analytic_steps()

它给出了这个错误:

line 16, in demographic_analytic_steps
self.result_in_plaintext(some_text='This is done', on_switch=True)
TypeError: wrapper() got an unexpected keyword argument 'some_text'

【问题讨论】:

    标签: python-3.x parameters parameter-passing decorator


    【解决方案1】:

    您在wrapper 函数中使用的*args 参数仅支持作为位置参数传入的附加参数。它不支持任意关键字参数。如果要匹配关键字参数,则需要使用**kwargs(代替*args 或作为*args 的补充)。否则,您需要更改调用函数的方式,将 some_text 作为位置参数而不是关键字参数传递。

    注意位置参数的顺序很重要!您需要将 *args 放在参数列表中,而不是其他位置参数,这意味着 on_switch 需要是第一个参数,而不是第二个参数,如果您按位置传递它们。这是支持关键字参数的原因之一,因为它们的顺序无关紧要。您甚至可以通过将它们放在函数声明中的 *args 参数之后(或者如果您根本不需要 *args 则单独放在 * 之后来制作 仅限关键字 参数)。如果您想要尽可能广泛的支持,我建议:

    # Decorators
    def on_or_off(func):
        def wrapper(self, *args, on_switch, **kwargs):  # on_switch is keyword only now!
            if on_switch:
                func(self, *args, on_switch=on_switch, **kwargs) # note you may want to return here
        return wrapper
    

    【讨论】:

      【解决方案2】:
      class MyClass:
          def on_or_off(func):
                  def wrapper(self,*args, **kwargs):
                      if kwargs['on_switch']:
                          func(**kwargs)
                  return wrapper
          @on_or_off
          def test(on_switch = False,some_text="This is done"):
                print(f' "Test" Function executed with on_switch = {on_switch} and some_text {some_text}')
      
      obj = MyClass()
      obj.test(on_switch = True, some_text="Abhijeet")
      

      【讨论】:

        猜你喜欢
        • 2023-03-17
        • 2018-04-05
        • 2013-09-18
        • 2012-12-09
        • 2014-07-21
        • 1970-01-01
        • 1970-01-01
        • 2018-08-28
        • 2013-06-03
        相关资源
        最近更新 更多