Можно ли заставить поле класса данных вызывать свой default_factory, когда предоставленный аргумент равен None? - PullRequest
1 голос
/ 25 апреля 2019

У меня есть класс данных с изменяемым полем (список).Я надеюсь, что в этом поле никогда не будет None, даже если в вызове __init__ явно указано значение None.В обычном классе это было бы тривиально реализовать:

class A:
    def __init__(self, l: Optional[List[int]] = None):
        if l is None:
            l = []
        self.l = l

Есть ли способ достичь того же результата только с помощью функции dataclasses.field , т.е. без явной реализации метода __init__(что было бы обременительно, если у класса много атрибутов)?Могу ли я заставить dataclasses.field вызывать его default_factory, если в качестве аргумента init указано None?

Ответы [ 2 ]

3 голосов
/ 25 апреля 2019

Я не думаю, что можно напрямую вызвать default_factory для явно предоставленных значений None. Но вы можете использовать метод __post_init__, чтобы явно проверить None и указать значение по умолчанию, особенно если вам нужно проверить много атрибутов.

Вы можете использовать функцию fields, чтобы автоматически сканировать ваш класс данных 'для значений None и вызывать default_factory для этих атрибутов, если это было предоставлено:

from dataclasses import dataclass, field, fields, MISSING
from typing import List

@dataclass
class A:
    l: List[int] = field(default_factory=list)

    def __post_init__(self):
        for f in fields(self):
            value = getattr(self, f.name)   
            if value is None and not f.default_factory is MISSING:
                setattr(self, f.name, f.default_factory())

s = A([1,2])
print(s.l)  # [1,2]

t = A(None)
print(t.l)  # []
1 голос
/ 25 апреля 2019

Вы можете достичь желаемого результата с помощью метода __post_init__, который установит self.l в пустой список, даже если это None:

@dataclass
class A:
    l: Optional[List[int]]

    def __post_init__(self):
        self.l = self.l or []


a = A(None)
print(a.l)  # []
...