1

I am new to python (3.6.2 is the version I am using).

I am currently porting (trying to port) a DSL implementation from Scala to python for some projet in which python is imposed.

So I am looking for a way to efficiently write immutable class hierarchies to represent ADTs in a way that supports type-checking with mypy.

I first came across macropy which replicates scala case classes and pattern matching in python but is only python 2.7.x compatible (and would not work with mypy anyway).

I did some more research and came by typing.NamedTuple and abc.ABC. So now I am trying to find a way to combine the benefits of typing.NamedTuple with abc.ABC to be able to add mixins to namedtuples.

I would like to be able to write this sort of code:

from typing import *
from abc import ABC, abstractmethod

class M(ABC):
    @abstractmethod
    def m1(self, it: Iterable[str]) -> str:
        pass

class NT(NamedTuple):
    attr1: str
    attr2: Union[bool, float]

class C1(NT,M):
    def m(self, it: Iterable[str]) -> str:
        return attr1.join(it)

class C2(NT,M):
    pass
c1 = C1('foo',12)
c1.m([str(i) for in in range(10)]) # would work
c2 = C2('bar',12.0)
c2.m([str(i) for in in range(10)]) # would fail because abstractmethod not implemented

The code above runs typechecks with mypy but fails to fail on the C2.m call (the method call just returns None).

So I searched further and came by this recipe for collections.namedtuple + Mix-In : abc.namedtuple

I tried to adapt the recipe from collections.namedtuple to typing.NamedTuple but cannot wrap my head around the fairly complex and fragile python machinery involved in the recipe. Is there any obvious way to make this work ?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
remi
  • 566
  • 3
  • 13
  • `C2(...)` should not really work; the ABC should prevent an instance from being created. Except that the namedtuple `__new__` implementation masks the ABC `__new__` method so the normal check isn't applied. – Martijn Pieters Jul 29 '17 at 16:17
  • Do you *have* to use an ABC? You could just put the method on the NamedTuple directly. – Martijn Pieters Jul 29 '17 at 16:18
  • actually I would like to use ABC to implement something equivalent to a scala trait, ie a abstract class providing an abstract method (that must be implemented in derived classes), and at the same time providing concrete methods that rely on this abstract method. This would save me a lot of code duplication. I know I could just use standard classes and raise exceptions at runtime for unimplemented methods, but since mypy is able to warn you when you forget to implement abstract methods this would be ideal for me. – remi Jul 29 '17 at 17:19
  • Testing that an ABC's abstract methods are implemented is outside the scope for mypy. This comes down to a basic incompatibility between named tuples and ABCs, really. – Martijn Pieters Jul 29 '17 at 17:20
  • actually mypy generates errors "Cannot instantiate abstract class 'Foo' with abstract attribute 'foo" whereas running the program does not produce the error at runtime (I created a class Foo which inherits both from a NamedTuple subclass and an ABC subclass with an @abstractmethod) – remi Jul 29 '17 at 17:39
  • Ah, wasn't aware that mypy correctly detects that case then. – Martijn Pieters Jul 29 '17 at 17:45

0 Answers0