В качестве предисловия ваш код
class Foo:
def __init__(self, a=1, b=2.0, c=(3, 4, 5)):
self.a = int(a)
self.b = float(b)
self.c = list(c)
, как уже упоминалось в нескольких комментариях, хорош, как есть.Код читается гораздо больше, чем написано, и, кроме того, что нужно быть осторожным, чтобы избежать опечаток в именах при первом определении этого, цель совершенно ясна.(Хотя см. Конец ответа относительно значения по умолчанию c
.)
Если вы используете Python 3.7, вы можете использовать класс данных, чтобы уменьшить количество ссылок на каждую ссылкупеременная.
from dataclasses import dataclass, field
from typing import List
@dataclass
class Foo:
a: int = 1
b: float = 2.0
c: List[int] = field(default_factory=lambda: [3,4,5])
Это не мешает вам нарушать подсказки типов (Foo("1")
с радостью установит a = "1"
вместо a = 1
или вызовет ошибку), но обычно это ответственностьвызывающая сторона должна предоставить аргументы правильного типа.) Если вы действительно хотите применить это во время выполнения, вы можете добавить __post_init__
метод:
def __post_init__(self):
self.a = int(self.a)
self.b = float(self.b)
self.c = list(self.c)
Но если вы сделаете это, вы также можетевернитесь к исходному методу __init__
, закодированному вручную.
Кроме того, стандартная идиома для изменяемых аргументов по умолчанию:
def __init__(self, a=1, b=2.0, c=None):
...
if c is None:
c = [3, 4, 5]
У вашего подхода есть две проблемы:
- Требуется, чтобы
list
запускался для каждого экземпляра, а не позволял жесткий код компилятора [3,4,5]
. Если вы указали аргументы типа для__init__
, ваше значение по умолчанию не совпадает сУхоженный тип.Вам нужно написать что-то вроде
def init (a: int = 1, b: float = 2.0, c: Union [List [Int], Tuple [Int, Int,Int]] = (3,4,5))
Значение по умолчанию None
автоматически вызывает «продвижение» типа к соответствующему необязательному типу.Следующие значения эквивалентны:
def __init__(a: int = 1, b: float = 2.0, c : List[Int] = None):
def __init__(a: int = 1, b: float = 2.0, c : Optional[List[Int]] = None):