首页 > 解决方案 > 如何使用 __new__ 将多个参数传递给一个类?

问题描述

我试图理解 __new__ 并且我对 OOP python 还很陌生。我有这个代码...

import csv
from csv import DictReader
import logging
import typing as T


class MaxLength(str):
    def __new__(cls, field: str):

        # how do i pass this dynamically in the PCW obj
        maximum = 4

        if len(field) > maximum:
            raise ValueError('invalid length of fields at: ' + field)
        return super().__new__(cls, field)


class PCW(T.NamedTuple):
    length_checker: MaxLength

    @classmethod
    def from_row(cls, row: dict):

        return cls(**{key: type_(row[key]) for key, type_ in cls._field_types.items()})


def validate_csv(reader: DictReader) -> bool:
    for row in reader:
        try:
            PCW.from_row(row)
        except Exception as e:
            logging.error('type: {} msg: {}'.format(type(e), e))
            return False
    return True


input_file = validate_csv(csv.DictReader(open("test.csv")))

这可行,但我希望能够maximum作为参数传入,以便这会改变。IE:

class PCW(T.NamedTuple):
    length_checker: MaxLength(maximum=4)
    ...


input_file = validate_csv(csv.DictReader(open("test.csv")))

我想我已经掉进了兔子洞。这是可能的还是我忽略/误解了什么?

标签: pythonpython-3.xcsvoop

解决方案


一种方法是使用object.__init_subclass__()Python 3.6 中添加的类方法。使用它需要子类化你的MaxLength子类。

这就是我的意思:

import csv
from csv import DictReader
import logging
import typing as T


class MaxLength(str):
    maximum = 8

    @classmethod
    def __init_subclass__(cls, **kwargs):
        maximum = kwargs.pop('maximum', cls.maximum)
        super().__init_subclass__(**kwargs)
        cls.maximum = maximum

    def __new__(cls, field: str):
        if len(field) > cls.maximum:
            raise ValueError('invalid length of fields at: ' + field)
        return super().__new__(cls, field)


class PCW(T.NamedTuple):
#    class PCWMaxLength(MaxLength):
    class PCWMaxLength(MaxLength, maximum=4): # Override default maximum.
        pass

    length_checker: PCWMaxLength

    @classmethod
    def from_row(cls, row: dict):
        return cls(**{key: type_(row[key]) for key, type_ in cls._field_types.items()})

    # Display value assigned to nested class' constant.
    print(f'PCWMaxLength.maximum: {PCWMaxLength.maximum}') # -> PCWMaxLength.maximum: 4


def validate_csv(reader: DictReader) -> bool:
    for row in reader:
        try:
            PCW.from_row(row)
        except Exception as e:
            logging.error('type: {} msg: {}'.format(type(e), e))
            return False
    return True

否则,我认为您将需要进行一些实际的元类编程……</p>


推荐阅读