Итак, мой вопрос: есть ли более «питонический» подход к этому?
Да: четко задокументируйте, какой API ожидается от объекта Q
(в данном случае: он должен иметь атрибут x
int) и называть его днем.
Дело в том, что независимо от того, «проверяете» ли вы тип аргумента или нет, ошибка произойдет во время выполнения, так что практическая проверка типов POV или нет не будет иметь большого значения - но это предотвратит передачу«совместимый» объект без уважительной причины.
Кроме того, поскольку Tee.x
является общедоступным, его можно установить на что угодно в любой точке кода, и этот на самом деле гораздо более важен, так как может сломаться при совершенно не связаннойместами, что делает ошибку намного более трудной для отслеживания и устранения, поэтому, если вы действительно настаиваете на том, чтобы быть оборонительным (что может или не имеет смысла в зависимости от контекста), это то, на чем вы должны сосредоточиться.
class Tee(object):
def __init__(self):
self.x = 0
@property
def x(self):
return self._x
@x.setter
def x(self, value):
# this will raise if value cannot be
# used to build an int
self._x = int(value)
def copy(self, Q : '__main__.Tee'):
# we don't care what `Q` is as long
# as it has an `x` attribute that can
# be used for our purpose
self.x = Q.x
def __str__(self):
return str(self.x)
Это 1 / предотвратит невозможность использования Tee.x
и 2 / остановит точную точку, где передается недопустимое значение, что делает ошибку очевидной и легко исправляемой путем проверки трассировки.
Обратите внимание, что здесь важно сказать, что проверка типов полностью и определенно бесполезна, но (по крайней мере, в Python) вы должны использовать ее только тогда и там, где это действительно имеет смысл для контекста.Я знаю, что это может показаться странным, когда вы купили идею о том, что «статическая типизация хороша, потому что она предотвращает ошибки» (уже здесь, сделали это ...), но на самом деле ошибки типа довольно редки (по сравнению с логическими ошибками) и чаще всего быстропятнистый.Правда о статической типизации заключается в том, что здесь не для того, чтобы помочь разработчику написать лучший код, а чтобы помочь компилятору оптимизировать код - что является ценной целью, но совершенно другой.