2017-09-22 2 views
0

J'ai une fonction qui retourne un 2-tuple mais en option un 3-tuple. Comment puis-je décrire cela avec des annotations de type?Type Python Annotations: Marquer l'élément dans un tuple comme optionnel

Par exemple:

from typing import Tuple 

def example(i): 
    # type: (int) -> Tuple[int, int, <what to put here?>] 
    if i < 10: 
     return (i, i+1, 1) 
    else: 
     return (i, i+1) 

Je peux utiliser l'Union comme ci-dessous, mais il semble tout à fait désordre.

# type: (int) -> Union[Tuple[int, int], Tuple[int, int, int]] 
+1

Ce sont 2 types distincts. L'union est probablement la plus logique. – Carcigenicate

Répondre

2

Comme souligné dans les commentaires, l'union est probablement la meilleure approche. Si la signature semble désordonnée, vous pouvez utiliser type aliases comme ceci:

from typing import Tuple, Union 

MyType = Union[Tuple[int, int], Tuple[int, int, int]] 

def example1(i): 
    # type: (int) -> MyType 
    ...snip... 

Une autre approche serait d'utiliser le "indefinite length" Tuple type. Vous abandonneriez fondamentalement l'encodage de la longueur exacte du tuple mais en échange vous pouvez normaliser le type de retour et éviter cette union. (Si votre code fait compter sur la longueur, ce n'est probablement pas la meilleure approche). Toutefois, une approche un peu plus radicale consisterait à envisager une restructuration de votre code pour éviter ce type de situation.

Après tout, si vous renvoyez ces deux types distincts, l'appelant de votre fonction aura probablement besoin de vérifier la longueur de toute façon, non?

Dans ce cas, une idée est de renoncer à retourner un tuple et de retourner à la place un NamedTuple ou une classe personnalisée, les deux ayant un champ facultatif. Vous pouvez ensuite convertir votre chèque "longueur" en un chèque "est ce champ défini sur Aucun".

Je suppose que, dans un sens, l'approche NamedTuple répond également à votre demande initiale, tant que cela ne vous dérange pas de convertir vos Tuples/le surcoût ajouté.

from typing import NamedTuple, Optional 

MyType2 = NamedTuple('MyType2', (
    ('x', int), 
    ('y', int), 
    ('z', Optional[int]), 
)) 

class MyType3(object): 
    def __init__(self, x, y, z): 
     # type: (int, int, Optional[int]) -> None 
     self.x = x 
     self.y = y 
     self.z = z 

(L'approche « de classe personnalisée » sera probablement plus élégante une fois PEP 557 est accepté et intégré dans la langue).

L'autre approche consiste à diviser votre fonction en deux si vous connaissez à l'avance le type de ligne que vous attendez. Ensuite, vous pouvez simplement appeler la fonction de ce type approprié.

+0

Merci pour la réponse complète. –