Спасибо, что прочитали мой код!
Действительно, нетрудно создать общий исполнитель аннотации в Python. Вот мой прием:
'''Very simple enforcer of type annotations.
This toy super-decorator can decorate all functions in a given module that have
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.
This module also has a test function func() which should fail and logging facility
log which defaults to print.
Since this is a test module, I cut corners by only checking *keyword* arguments.
'''
import sys
log = print
def func(x:'int' = 0) -> 'str':
'''An example function that fails type checking.'''
return x
# For simplicity, I only do keyword args.
def check_type(*args):
param, value, assert_type = args
log('Checking {0} = {1} of {2}.'.format(*args))
if not isinstance(value, assert_type):
raise AssertionError(
'Check failed - parameter {0} = {1} not {2}.'
.format(*args))
return value
def decorate_func(func):
def newf(*args, **kwargs):
for k, v in kwargs.items():
check_type(k, v, ann[k])
return check_type('<return_value>', func(*args, **kwargs), ann['return'])
ann = {k: eval(v) for k, v in func.__annotations__.items()}
newf.__doc__ = func.__doc__
newf.__type_checked = True
return newf
def decorate_module(module = '__main__'):
'''Enforces type from annotation for all functions in module.'''
d = sys.modules[module].__dict__
for k, f in d.items():
if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
log('Decorated {0!r}.'.format(f.__name__))
d[k] = decorate_func(f)
if __name__ == '__main__':
decorate_module()
# This will raise AssertionError.
func(x = 5)
Учитывая эту простоту, на первый взгляд странно, что эта вещь не является основным. Однако, я считаю, есть веские причины, почему это не так полезно, как может показаться.Как правило, проверка типов помогает, потому что, если вы добавляете целое число и словарь, скорее всего, вы совершили какую-то очевидную ошибку (и если вы имели в виду что-то разумное, все равно лучше быть явным, чем неявным).
Но в реальной жизни вы часто смешивают количества одного и того же типа компьютера, как видно компилятором, но явно отличается человеческого типа, например, следующий фрагмент содержит очевидную ошибку:
height = 1.75 # Bob's height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What's that supposed to mean???
Любой человек должен немедленно увидеть ошибку в приведенной выше строке при условии, что он знает «тип человека» переменных height
и length
, хотя он выглядит на компьютере как совершенно законный умножение int
и float
.
Есть еще что можно сказать о возможных решениях этой проблемы, но применение «типов компьютеров», по-видимому, является полурешением, поэтому, по крайней мере, по моему мнению, это хуже, чем никакого решения вообще. Это та же самая причина, почему Systems Hungarian - ужасная идея, а Apps Hungarian - отличный вариант. Есть еще в самом информативном post of Joel Spolsky.
Теперь, если кто-то должны были осуществить какое-то библиотеки третьих стороной вещей, которая бы автоматически присваиваемое реальные данные его человеческого типа, а затем позаботилась, чтобы преобразовать этот тип как width * height -> area
и обеспечивать эту проверку с функцией аннотациями, Я думаю, что это будет тип проверки людей, которые действительно могут использовать!
И вот что я только что написал об опасностях сильной типизации: http://stackoverflow.com/questions/1251791/what-are-the-limits-of-type-checking-and-type-systems/1276675#1276675 –
Что если боб должен был нарисовать один квадратный метр своей спальни красной краской для каждого модуля, который он импортирует? –
Тогда вы должны использовать явный тип приведения, чтобы наказать Боба. Каждая система сильной типизации, будь то статическая или динамическая, имеет положения для типоразмеров: например. '' string '+ 5' запрещен, но '' string' + str (5) 'отлично. –