1

I write a library in Python and I want to code to be a self explained, but I find it difficult to be with duck typing.

Let's assume that I have a class that accept a parameter A. That parameter has to implemet fly, eat and dance methods. How would another programmer or even myself will know easliy what behavior that A parameter must implements without reading the entire class's code or helper functions' code?

In these days I define an interface above each class that contains the expacated bahvior - For a self explained code.

Any thoughts? Better soultions?

Programmer
  • 119
  • 1
  • 8

1 Answers1

2

Your example sounds like an abstract class. You could define an abstract class, and add a type annotation for that parameter or explicitly check its type:

from abc import ABC, abstractmethod

class MyABC(ABC):
    @abstractmethod
    def fly(self):
        pass

    @abstractmethod
    def eat(self):
        pass

    @abstractmethod
    def dance(self):
        pass

And for your method:

def test(param: MyABC):
    if not isinstance(param, MyABC):
        raise Exception("param must inherit MyABC.")

This works because when passing param to test method, it must inherit MyABC - and in order to inherit MyABC, the class must define the three methods fly, eat, dance - otherwise, a TypeError would be raised when trying to instantiate it.

Edit:

If you want the subclasses not to directly inherit but still "count as" a MyABC subclass, you can use __subclasshook__:

from abc import ABC, abstractmethod

class MyABC(ABC):
    @abstractmethod
    def fly(self):
        pass

    @abstractmethod
    def eat(self):
        pass

    @abstractmethod
    def dance(self):
        pass

    @classmethod
    def __subclasshook__(cls, C):
        if any("fly" in B.__dict__ for B in C.__mro__):
            # add checks for dance and eat...
            return True
        return NotImplemented

Now every class that implements the fly method (or inherits a class that implements it) will return True to the following condition: isinstance(CLASS, MyABC)

From Fluent Python:

The subclasshook adds some duck typing DNA to the whole goose typing proposition. You can have formal interface definitions with ABCs, you can make isinstance checks everywhere, and still have a completely unrelated class play along just because it implements a certain method (or because it does whatever it takes to convince a subclasshook to vouch for it). Of course, this only works for ABCs that do pro‐ vide a subclasshook.

AdamGold
  • 4,941
  • 4
  • 29
  • 47
  • This is exactly what I meant when I wrote "interface". The problem is that it seems to be not pythonic.. but I can not find other way of writing a readble duck typing code in Python – Programmer Aug 20 '19 at 12:09
  • 1
    I can not see a reason why this is not Pythonic. – AdamGold Aug 20 '19 at 12:44
  • Ok. What about enforcing some object to have a setter and a getter that looks like the following: object.attribute and object.attribute = value. My abstract class must declare it, but what way is preferred? As a global class's member? As abstract properties? As an abstract dataclass? – Programmer Aug 20 '19 at 13:23
  • You mean an abstract property. That's a subject for a separate SO question. Check [here](https://stackoverflow.com/questions/2736255/abstract-attributes-in-python) and [here](https://stackoverflow.com/questions/23831510/abstract-attribute-not-property). – AdamGold Aug 21 '19 at 14:14
  • 1
    You enforce the type to be a MyABC instance. What if it has all the mentioned behavior but it's not an instance of that class? That why I wrote earlier that it is against Duck Typing. I think that instead of an abstract class, a behavior mechanism needs to be added to Python, and that will make Python a truley duck-typing language. – Programmer Sep 22 '19 at 12:44
  • This is already implemented in Python. It's called `subclasshook`, you can read about it [here](https://docs.python.org/3/library/abc.html#abc.ABCMeta.__subclasshook__). – AdamGold Sep 22 '19 at 18:07
  • From *Fluent Python*: "The __subclasshook__ adds some duck typing DNA to the whole goose typing proposition. You can have formal interface definitions with ABCs, you can make isinstance checks everywhere, and still have a completely unrelated class play along just because it implements a certain method (or because it does whatever it takes to convince a __subclasshook__ to vouch for it). Of course, this only works for ABCs that do pro‐ vide a __subclasshook__." – AdamGold Sep 22 '19 at 18:08