python-3.x 如何在不修改继承方法的情况下进行修饰?

jgovgodb  于 2023-03-04  发布在  Python
关注(0)|答案(2)|浏览(150)

我已经看到并尝试了How would one decorate an inherited method in the child class?给出的答案,但无济于事。
样本数据:

import pandas as pd

df = pd.DataFrame([('Tom', 'M'), ('Sarah', 'X')], columns=['PersonName', 'PersonSex'])

我正在使用pandera库来进行DataFrame数据质量和验证。我有一个类BaseClass,它定义了一些我将在许多模式中使用的函数,例如:

class BaseClass:
    def check_valid_sex(col):
        return col.isin(['M', 'F'])

我在我的schema类中继承了这个类,我将在其中应用检查。这里,首先,是一个不使用这个类并在SchemaModel中显式编写检查的示例。

import pandera as pa
from pandera.typing import Series

class PersonClass(pa.SchemaModel):
    PersonName: Series[str]
    PersonSex: Series[str]

    @pa.check('PersonSex')
    def check_valid_sex(cls, col):
        return col.isin(['M', 'F'])

PersonClass.validate(df)

我想做的是在其他SchemaModel类中重用check_valid_sex函数,其中有一个PersonSex列,类似于:

import pandera as pa
from pandera.typing import Series

class PersonClass(pa.SchemaModel, BaseClass):
    PersonName: Series[str]
    PersonSex: Series[str]

    # apply the pa.check function to the BaseClass function to inherit the logic
    validate_sex = classmethod(pa.check(BaseClass.check_valid_sex, 'PersonSex'))

PersonClass.validate(df)

这应该会返回一个有效的验证,但是没有起作用,因为我不相信这个函数被正确注册了。我怎样才能修饰父类而不覆盖它呢?简单地用修饰器参数来修饰。

yquaqz18

yquaqz181#

这里的decorator实际上是一个decorator构造函数,它会对调用它的对象进行装饰,因此需要遵循相同的模式,用字段名构造check,然后使用它手动 Package 基类函数:

validate_sex = pa.check('PersonSex')(BaseClass.check_valid_sex)
             # ^^^^^^^^^^^^^^^^^^^^^ constructs decorator
             #                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ calls on function

不太清楚为什么基类(不是classmethod)接受cls,而子类试图 Package 成classmethod,如果只是子类应该是classmethod,你可以这样做:

validate_sex = classmethod(pa.check('PersonSex')(BaseClass.check_valid_sex))

来 Package 它,但是如果基类方法实际上是classmethod,它会变得更难看;你必须打开它,例如,你要用BaseClass.check_valid_sex.__func__替换BaseClass.check_valid_sex(将函数绑定到类,然后只提取未绑定的函数),或者在Python 3.10+中,您可以通过执行BaseClass.__dict__['check_valid_sex'].__wrapped__来避免创建绑定类方法(它查找原始的classmethod,绕过描述符协议,并直接提取它 Package 的函数)。您需要这样做,以便获得干净的原始函数,而不是永久地绑定到父类(即使在子类上调用clscls仍将是BaseClass)。

mwg9r5ms

mwg9r5ms2#

有一个接口可以向pandera的check-engine注册自定义的check-function,它可以实现重用:

import pandera as pa
from pandera.typing import Series
from pandera import extensions
import pandas as pd

@extensions.register_check_method()
def valid_sex(pandas_obj):
    return pandas_obj.isin(['M', 'F'])

class PersonClass(pa.SchemaModel):
    PersonName: Series[str]
    PersonSex: Series[str] = pa.Field(valid_sex=())

df = pd.DataFrame(
    [('Tom', 'M'), ('Sarah', 'X')],
    columns=['PersonName', 'PersonSex']
)

PersonClass.validate(df)

图纸

Traceback (most recent call last):
...
pandera.errors.SchemaError: <Schema Column(name=PersonSex, type=DataType(str))> failed element-wise validator 0:
<Check valid_sex>
failure cases:
   index failure_case
0      1            X

相关问题