Проверка нежелательного изменения типа в Python
Я пришел из программирования статического типа, и мне интересно понять смысл программирования динамического типа, чтобы проверить, могут ли языки динамического типа лучше соответствовать моим потребностям.
Я читал о теории программирования утки. Я также читал, что модульное тестирование (желательно и используется в программировании статического типа) становится необходимостью в динамических языках, где отсутствуют проверки во время компиляции.
Тем не менее, я все еще боюсь пропустить общую картину. В частности, как вы можете проверить на ошибку, когда тип переменной был случайно изменен?
Давайте сделаем очень простой пример в Python:
#! /usr/bin/env python
userid = 3
defaultname = "foo"
username = raw_input("Enter your name: ")
if username == defaultname:
# Bug: here we meant userid...
username = 2
# Here username can be either an int or a string
# depending on the branch taken.
import re
match_string = re.compile("oo")
if (match_string.match(username)):
print "Match!"
Pylint, pychecker и pyflakes не предупреждают об этой проблеме.
Как Pythonic способ справиться с такого рода ошибками?
Должен ли код быть завернут в try/catch?
1 ответ
Это не даст вам проверки во время компиляции, но, как вы предложили использовать try / catch, я предполагаю, что проверки во время выполнения также будут полезны.
Если вы используете классы, вы можете подключить свои собственные проверки типов в __setattr__
метод. Например:
import datetime
# ------------------------------------------------------------------------------
# TypedObject
# ------------------------------------------------------------------------------
class TypedObject(object):
attr_types = {'id' : int,
'start_time' : datetime.time,
'duration' : float}
__slots__ = attr_types.keys()
# --------------------------------------------------------------------------
# __setattr__
# --------------------------------------------------------------------------
def __setattr__(self, name, value):
if name not in self.__slots__:
raise AttributeError(
"'%s' object has no attribute '%s'"
% (self.__class__.__name__, name))
if type(value) is not self.attr_types[name]:
raise TypeError(
"'%s' object attribute '%s' must be of type '%s'"
% (self.__class__.__name__, name,
self.attr_types[name].__name__))
# call __setattr__ on parent class
super(MyTypedObject, self).__setattr__(name, value)
Это приведет к:
>>> my_typed_object = TypedObject()
>>> my_typed_object.id = "XYZ" # ERROR
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 28, in __setattr__
TypeError: 'MyTypedObject' object attribute 'id' must be of type 'int'
>>> my_typed_object.id = 123 # OK
Вы могли бы пойти и сделать TypedObject
выше, более общий, чтобы ваши классы могли наследовать от него.
Другим (возможно, лучшим) решением (указанным здесь) может быть использование черт Entought