Marko Rauhamaa wrote: > I seem to remember an idea floated on the Scheme mailing list of using > assertions for such a purpose: > > def myfunction(arg1, arg2): > assert isinstance(arg1, str) and isinstance(arg2, int) > return True > > The advantage is that the assertions can be as complex as you'd like: > > def weekday(day): > assert isinstance(day, int) and 0 <= day <= 6 > ... > > def str_product(x, y): > assert isinstance(x, int) and isinstance(y, str) or \ > isinstance(x, str) and isinstance(y, int) > ... > > Also, they have always been present in the language and assertion > semantics is fully compatible with static analysis.
Not really. Well, I suppose technically they could be, if the type-checker included a full Python interpreter. Requiring the type-checker to parse and understand arbitrarily complex assertions would require the type-checker to be as complex as Python itself: def f(something): assert (__import__("somemodule") is some_function(spam, eggs, *ham, **cheese).attr.x[y](z) or any(some_expression and another_expression for a, b, c, d in my_module.map(something, fe, fi, fo, fum) if some_condition(a) or b == c[d]) and are_you_confused_yet() if foo else bar or eval(expr, ns) < 23 or open('config').read(100)[23:27] == 'okay') Fortunately, type systems are generally not fully Turing complete and are usually significantly more restricted. PEP 484 doesn't mandate an upper limit to how clever the type-checker must be, it only sets a common syntax which type-checkers are expected to support. That is significant less complex than a full Python parser, and should be lightweight enough that IDEs and editors can use type-hints for providing text completion and hints. (This means that type-checkers are permitted to parse assertions, but they aren't required to.) Assertions also have the problem that they execute arbitrarily complex code at runtime. Type annotations also execute code at runtime, but they're not expected to be arbitrarily complex: mostly name lookups. Lastly, this use of assertions clashes with "best practice" for assertions. Since assertions may be disabled, you should not use them for testing user-supplied arguments. So that means you have to write: def func(arg): assert isinstance(arg, int) # satisfy the type checker if isinstance(arg, int): # support times when assert is disabled ... which is not only ugly, but every call requires *two* isinstance checks. It also means that when asserts are enabled you get a different exception for bad data than when they are disabled. This doesn't apply to annotations: def func(arg:int): # since this is a public function, not private, we cannot assume the # caller will run the type-checker if isinstance(arg, int): ... In this case, the overhead from the "arg:int" annotation is trivial: a single name lookup and binding when the function is created, not when it is called. Sufficiently clever type-checkers may use assertions to infer types, but requiring this is a non-starter. -- Steven -- https://mail.python.org/mailman/listinfo/python-list