4 ms·
PEP484 and the current state of typings in Python: - Imports everywhere. Even basic types (list, dict, set) have to be imported - Basic types don't share the
by scrollaway 8y ago
PEP484 and the current state of typings in Python:
- Imports everywhere. Even basic types (list, dict, set) have to be imported
- Basic types don't share the same casing as the actual types they represent (Set vs set, Dict vs dict, List vs list)
- Awful support for enums.
- Syntax is generally ugly. Typescript got everything right; it's intuitive, clear, and scales pretty well even for complex types. I'd be happy if they just copied typescript syntax.
- Types have a runtime impact.
- throwawaymath 8y ago> - Types have a runtime impact. Do you mind expanding on this, and what could be done differently?
- wrmsr 8y agotype annotations are actual objects instantiated at runtime, usually only done at module import for non-local annotations but done each function invocation for locals. this is nice for extensibility as it makes interacting with and extending the type system as easy as writing any other normal python but in older versions of python it was extraordinarily slow, particularly with generics (as they were previously implemented by creating new actual typeobjects each time they had arguments applied (to be usable as baseclasses) - this has been corrected in 3.7 with the addition of __mro_entries__). 3.8 is however making annotations evaluated on demand not eagerly pretty much removing all runtime performance impact.
- marmaduke 8y agoIn what sense does x: float = 1.0 instantiate?
- blattimwind 8y agoList[Tuple[Tuple[str, int], Dict[str, str]]] creates a bunch of objects; if you're having a closure these are necessarily created each time the closure is invoked, by evaluating the entire "List[Tuple[Tuple[str, int], Dict[str, str]]]" expression.
- marmaduke 8y agoWhy can’t you close over that type instantied outside the closure? Complicated closures are often more idiomatically as classes where the aggregate type would be a class member.
- blattimwind 8y agoThere are two cases to consider. One is where the closure is called multiple times. This is the "by necessity" case, because the enclosed definition is executable and Python must make believe that this definition is re-executed every time the function is called. If you are just calling the enclosed function then of course this does not happen. Compare: def mytype(): print("!") return dict() def closure(): def enclosed(x: mytype()): pass return enclosed print("Calling the closure") for i in range(10): closure() print("Calling the enclosed") f = closure() for i in range(10): f(0) Note that using closures is almost always faster in Python than classes, because accesses to enclosed variables are done through offsets instead of attribute lookup (this gap has been somewhat closed, but is still significant in some cases; arguably almost all of these cases indicate that you are using either the wrong language, or the wrong implementation). So adding overhead to closures can be a somewhat valid reason to avoid using these annotations.
- throwawaymath 8y agoThank you, I've been eyeing typing in Python and appreciate your explanation.
- sleavey 8y agoAgree. One way to fix it would be to allow you to define the typing in a completely separate file. Right now you can define some of it in a separate file but not all of it. I keep the horrendous typing syntax out of my code by not using it.
- Too 8y agoTyping in a separate file defeats almost all the benefits of typing. Being able to read the code without also having to open a second source, the documentation. It's almost as bad as going back to stoneage c++ with header/source split up in separate files. Reading and writing types should be fast, agile, easy and effortless. Only way to acheive that is having it as close the usage as possible
- sametmax 8y ago+1, also Union must be imported and can't be simply spelled |. Althought now annotations don't have a runtime cost anymore since the y are lazily evaluated.