コメントに指摘されているように、おそらくより良いアプローチです。署名が乱雑に見える場合は、そのようtype aliases使用することができます。
from typing import Tuple, Union
MyType = Union[Tuple[int, int], Tuple[int, int, int]]
def example1(i):
# type: (int) -> MyType
...snip...
別のアプローチは、"indefinite length" Tuple typeを使用することです。あなたは基本的にタプルの正確な長さをエンコードすることをあきらめますが、交換では戻り値の型を正規化してその和集合を避けることができます。 (コードがの長さに依存する場合、これはおそらく最善の方法ではありません)。
def example2(i):
# type: (int) -> Tuple[int, ...]
...snip...
しかし、やや抜本的なアプローチは、このような状況を回避するためにコードを再構築することです。
結局のところ、これらの2つの異なるタイプを返す場合、関数の呼び出し元はおそらく長さをチェックする必要があるでしょうか?
この場合、タプルを返すことをあきらめ、その代わりに任意のフィールドを持つNamedTupleまたはカスタムクラスを返します。その後、 "長さ"チェックを "このフィールドをなしに設定する"チェックに変換することができます。
ある意味では、NamedTupleのアプローチは、あなたのタプル/追加されたオーバーヘッドを変換しても構いません。
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
(PEP 557が受け入れられ、言語に統合されると、「カスタムクラス」アプローチは、おそらくよりエレガントになります)。
もう一つの方法は、あなたが期待しているタプルの種類を事前に知っているならば、関数を2つに分割することです。次に、適切な型の関数を呼び出すことができます。
これらは2つの異なるタイプです。おそらく組合は最も論理的です。 – Carcigenicate