<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 L'interpréteur Python, quel sale type
PyConFR 2017, Toulouse
par Serge « sans paille » Guelton
avec la bénédiction de QuarksLab
Round 0
Quel type pour...
Step1:  Round 1
Step2:  Round 2
Step3:  Round 3
Quel type pour
Step4:  K.O.
Step5:  Pour avoir l'air savant
typage nominal
Utilise le nom du type des objets
    pour faire les calculs de type
typage structurel
Utilise les membres des objets
    pour faire des calculs de type
Python
Python utilise le duck typing
Typage structurel à l'exécution
Suis-je un fan de parkour ?
Step6:  Quizz
Quelle différence entre isiterable1 et isiterable2 ?
Quelle différence entre isiterable2 et isiterable3 ?
Approche de haut niveau
Step7:  Peut-on se mocker ?
Step8:  Test de robustesse n°0
Step9:  Test de robustesse n°1
Step10:  __subclasshook__
Step11:  NB ça ne teste que les noms de membre, pas leur type...
Contrat implicite
Step12:  Le gadget de l'inspecteur
Step13:  Un bon moyen pour tester l'arité ?
Step14:  import typeguard
Step15:  Un peu plus loin
Step16:  MyPy
Step17:  Python n'est il pas Dynamique?
Step18:  Le coup fatal
<ASSISTANT_TASK:>
Python Code:
id  # id(obj: Any) -> int
int  # int(obj: SupportsInt) -> int
list.append  # list.append(self: List[T], obj: T) -> None
Explanation: L'interpréteur Python, quel sale type
PyConFR 2017, Toulouse
par Serge « sans paille » Guelton
avec la bénédiction de QuarksLab
Round 0
Quel type pour...
End of explanation
from typing import TypeVar  # PEP 484
T = TypeVar('T')
def add(self: T, other: T) -> T:  # PEP 3107
    return self + other
from typing import List, Tuple
t0: int = add(1, 2)
t1: List[int] = add([1], [2])
t2: Tuple = add((1,), (2,))
Explanation: Round 1
End of explanation
from typing import List
l: List[int] = [1,2,3]
def indexer(i):
    return l[i]
from typing import overload, Iterable
@overload
def indexer(i: int) -> int:
    pass
@overload
def indexer(i: slice) -> Iterable[int]:
    pass
def indexer(i):
    return l[i]
Explanation: Round 2
End of explanation
def bar(x):
    return str(x)
def foo(x):
    return bar if int(x) else None
from typing import Optional, SupportsInt, Any, Callable
def bar(x: Any) -> str:
    return str(x)
def foo(x: SupportsInt) -> Optional[Callable[[Any], str]]:
    return bar if int(x) else None
from typing import Iterable, Tuple, List
x: Iterable[int] = range(3)
y: Iterable[int] = reversed(range(3))
l0: Iterable[Tuple[int, int]] = zip(x, y)
l1: Tuple[Iterable[int], Iterable[int]] = zip(*l0)
from random import randint
n = randint(1, 4)
t0: List[Tuple[int]] = [(1, )] * n
l2: Tuple[(int,) * n] = zip(*t0)
Explanation: Round 3
Quel type pour
End of explanation
l: Any = eval("1 + 2")
%%file pyconfr2017/ko.py
a: int = 1
ko = __import__("pyconfr2017.ko")
Explanation: K.O.
End of explanation
def isiterable0(x):  # nominal
    return isinstance(x, (set, tuple, list, dict, str))
def isiterable1(x):  # structurel
    return hasattr(x, '__iter__')
def isiterable2(x):  # duck type v0
    try:
        x.__iter__()
        return True
    except:
        return False
def isiterable3(x):  # duck type v1
    try:
        iter(x)
        return True
    except:
        return False
Explanation: Pour avoir l'air savant
typage nominal
Utilise le nom du type des objets
    pour faire les calculs de type
typage structurel
Utilise les membres des objets
    pour faire des calculs de type
Python
Python utilise le duck typing
Typage structurel à l'exécution
Suis-je un fan de parkour ?
End of explanation
from collections.abc import Iterable
def isiterable(x):
    return isinstance(x, Iterable)
def check_iterable(l):
    return isiterable0(l), isiterable1(l), isiterable2(l), isiterable3(l), isiterable(l)
l = [1, 2, 3, 5]
check_iterable(l)
Explanation: Quizz
Quelle différence entre isiterable1 et isiterable2 ?
Quelle différence entre isiterable2 et isiterable3 ?
Approche de haut niveau
End of explanation
class EmptySequence(object):
    
    def __iter__(self): yield
    def __len__(self): return 0
    
es = EmptySequence()
check_iterable(es)
Explanation: Peut-on se mocker ?
End of explanation
class Infinity(object):
    def __getitem__(self, _):
        return 0
    
infnty = Infinity()
check_iterable(infnty)
Explanation: Test de robustesse n°0
End of explanation
class Hole(object):
    def __iter__(self, _):
        pass
    
h = Hole()
check_iterable(h)
Explanation: Test de robustesse n°1
End of explanation
import abc  # PEP 3119
class Appendable(abc.ABC):
    
    @classmethod
    def __subclasshook__(cls, C):
        return any('append' in B.__dict__ for B in C.mro())
    
class DevNull(object):
    
    def append(self, value):
        pass
    
    def __len__(self):
        return 0
    
issubclass(DevNull, Appendable)
class TraitsFactory(object):
    def __getitem__(self, method_names):
        if not isinstance(method_names, tuple):
            method_names = method_names,
            
        class SlotCheck(abc.ABC):
    
            @classmethod
            def __subclasshook__(cls, C):
                return all(any(method_name in B.__dict__ for B in C.mro())
                           for method_name in method_names)
        return SlotCheck
Members = TraitsFactory()
issubclass(DevNull, Members['append', '__len__'])
issubclass(DevNull, Members['append', 'clear'])
Explanation: __subclasshook__
End of explanation
class Twice(list):
    def append(self, value, times):
        for _ in range(times):
            super(Twice, self).append(value)
tw = Twice()
tw.append("ore", 2)
len(tw)
isinstance(tw, Members['append', '__len__'])
tw.append("aison")  # gentlemna contract again
Explanation: NB ça ne teste que les noms de membre, pas leur type...
Contrat implicite
End of explanation
import inspect
inspect.signature(Twice.append).parameters
Explanation: Le gadget de l'inspecteur
End of explanation
inspect.signature(list.append)
from typing import Callable
isinstance(list.append, Callable)
from typing import List, TypeVar; T = TypeVar('T')
isinstance(list.append, Callable[[List[T], T], None])
Explanation: Un bon moyen pour tester l'arité ?
End of explanation
from typeguard import typechecked
def aff(x: int) -> int:
    return x * 2 + 1
aff(2)
aff("2")
taff = typechecked(aff)
taff(2)
taff("2")
taff(2.)
from numbers import Number  # PEP 3141
@typechecked
def taff(x: Number) -> Number:
    return x * 2 + 1
taff(1), taff(1.), taff(1j)
print("** without type checking **")
%timeit aff(2)
print("** with type checking **")
%timeit taff(2)
Explanation: import typeguard
End of explanation
@typechecked
def index(x: Members["__getitem__"]) -> None:
    x[1]
index([1,2])
@typechecked
def pouce(x: Members['__getitem__']) -> None:
    return x[0]
pouce([0])
from typing import List, TypeVar; T = TypeVar('T')
@typechecked
def majeur(x: List[T]) -> T:
    return x[2]
majeur([1,2,3])
majeur([1, "1", 1])
@typechecked
def step(x : List[T]) -> List[T]:
    return x + [x[-2] + x[-1]]
step([1, 2])
from functools import reduce
reduce(lambda x, _: step(x), range(10), [0, 1])
from typing import Tuple
@typechecked
def step(x : Tuple) -> Tuple:
    return x + (x[-2] + x[-1],)
step((1,2))
@typechecked
def step(x : Tuple) -> Tuple:
    return x + (x[-2] + x[-1],)
step((1,2))
Explanation: Un peu plus loin
End of explanation
from mypy.api import run as mypy_runner
def mypy(*args):
    print( mypy_runner(args)[0])
%%file pyconfr2017/mypy0.py
from typing import Tuple
def step(x : Tuple) -> Tuple:
    return x + (x[-2] + x[-1],)
step([1, 2])
mypy("pyconfr2017/mypy0.py")
%%file pyconfr2017/mypy1.py
from typing import Tuple
def step(x : Tuple) -> Tuple:
    return x + (x[-2] + x[-1],)
step((1, 2))
mypy("pyconfr2017/mypy1.py")
%%file pyconfr2017/mypy2.py
from typing import Tuple, Any
def step(x : Tuple[int, ...]) -> Tuple[int, ...]:
    return x + (x[-2] + x[-1],)
step((1, 2))
mypy("pyconfr2017/mypy2.py")
Explanation: MyPy
End of explanation
float_mode = True
scalar = float if float_mode else int
@typechecked
def div(n: scalar):
    return 2 / n
div(scalar(3))
%%file pyconfr2017/mypy3.py
float_mode = True
scalar_type = float if float_mode else int
    
def div(n: scalar_type):
    return 2 / n
div(scalar_type(3))
mypy("pyconfr2017/mypy3.py")
Explanation: Python n'est il pas Dynamique?
End of explanation
import numpy
help(numpy.sum)
Explanation: Le coup fatal
End of explanation
<END_TASK>