5 ms·
Well, I like to put that another way -- I think Python is all about protocols (in the Python sense of the word protocol). I think that is what most people mean
by dbcurtis 10y ago
Well, I like to put that another way -- I think Python is all about protocols (in the Python sense of the word protocol). I think that is what most people mean when they say Python is all about duck typing, and it communicates the concept more precisely.
The concept of 'type' is overloaded with too many meanings these days. It started out as a what-storage-to-allocate and which-instruction-to-generate (int v float) concept (FORTRAN I, variables starting with I..N are ints, others real). Deep class hierarchies muddied the waters by overlaying the idea of whether or not a class implements a particular property or method, and how to locate the property or method that you want.
Python shows us that types and protocols/interfaces are two very different thing. In Python, asking 'isinstance()' is usually a bad idea unless you are doing something very low level, low level as in next stop is a C extension. The missing predicate in Python is 'hasprotocol()'. Abstract base classes can be used to accomplish that: isinstance(foo, SomeABC), but I think the intent could be more transparent with different syntax.
- clusmore 10y agoYeah I agree with you completely, I think we just use different terminology to describe the same thing. It sounds like you use "type" to mean "concrete type", i.e. the thing it actually is, and not the thing it acts like, and then "protocol/interface" to describe the behaviour, the thing we can use it as. As somebody who mostly uses statically-typed languages, I use "type" to mean "the thing my static type checker knows this as", which could be a concrete type or simply an interface, and then obviously I use the term "concrete type" when I need to be more explicit. I like the idea of a hasprotocol or supportsprotocol predicate, certainly over usage of isinstance, since one of the beauties of duck typing is that it works without requiring the type hierarchy. The tricky part will be in allowing you to define your own protocols, like "has these attributes/methods". An example would be the difference (or lack thereof) between classes and namedtuples.
- benhoyt 10y agoInterestingly, I think that's what isinstance() actually does when it's called on abstract base classes like collections.abc.Iterable -- it looks to see whether the type supports __iter__ and whatnot. See the abc module and it's implementation here: * https://docs.python.org/3.4/library/collections.abc.html https://docs.python.org/3.4/library/collections.abc.html * https://hg.python.org/cpython/file/3.4/Lib/_collections_abc.py https://hg.python.org/cpython/file/3.4/Lib/_collections_abc....
- clusmore 10y agoPasting the relevant snippet from your link: def __subclasshook__(cls, C): if cls is Iterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented Wow, hadn't seen this before. That's exactly what I mean. If I can define my own, e.g. Addable, which does a similar check for the presence of __add__ (and __radd__) and MyPy uses the subclasshook, then that'd be perfect.
- dbcurtis 10y agoGet _Fluent_Python_ by Ramalho and read chapter 11.
- dllthomas 10y ago> Python shows us that types and protocols/interfaces are two very different thing. In Python, asking 'isinstance()' is usually a bad idea Interesting perspective. This would seem to be pretty well described by parametric polymorphism with constraints (Haskell-style polymorphism with typeclasses). In that context, too, we are often well served staying as generic as possible, and asking at runtime about the type of something is a bit of a code smell (and only possible where you have a Typeable constraint available).
- clusmore 10y agoYes. Haskell's type deduction is exactly what I was thinking of as I read the article. You write a function using what you need and it deducts the requirements based on usage, giving you the most general type. I think this is actually very close to compile-time duck-typing. Actually I think if you took the class declarations out of Haskell and removed the instance lines (but left the subsequent implementations), and had the compiler deduce typeclasses for you, you'd get something that felt very much like compile-time duck-typing.
- int_19h 10y agoIf you want an even closer example, it would be OCaml with its structurally typed object system with inferred types. For example: # let f obj x y = (obj#m x)#n y;; val f : < m : 'a -> < n : 'b -> 'c; .. >; .. > -> 'a -> 'b -> 'c = <fun> Here I defined a function taking 3 arguments, called method m on obj, passing x as argument, then called method n on the result of that, passing y as argument. Note the inferred type signature for this: the first argument is of type <m : 'a -> <n : 'b -> 'c; ..>; ..> - i.e. any object that has a method named m (and possibly some other unspecified members - that's what ".." means), with said method m having a signature that allows us to pass some 'a, and returning another object of type <n : 'b -> 'c; ..> - i.e. something with a method named n that accepts 'b and returns 'c. 'a and 'b' are then used as types of x and y, respectively, and 'c is the the result of f. So effectively, this is full-fledged duck typing in the vein of Python objects, but captured on type system level.
- 10y ago
- brettcannon 10y agoThere's an open issue discussing the idea of an explicit protocol support somehow in Python: https://github.com/python/typing/issues/11 https://github.com/python/typing/issues/11 .