83299


## 概要

Pythonで関数にTypeHintをつける場合に引数の型を元にした型を返り値にするにはどうすればよいのでしょうか

## 詳細

詳細はサンプルコードを見て頂きたいのですが、親クラスAがあり、子クラスB、Cがあります。（実際には子クラスは複数ある）  
関数Xは引数としてBを渡すとBのインスタンス、Cを渡すとCのインスタンスを返す実装になります。  
その際に関数XにTypeHintをうまくつけるにはどのようにすればよいのでしょうか？

引数、返り値共にAを指定すると意味合い的には合ってはいるものの、Bを渡した際にCが返ってきても意味合い的には間違っていない事になってしまいます。

他の言語ではTなどと書かれる部分と認識しておりますが、どのように書くのが正しいのかわからないため質問させていただきました。

## サンプルコード

[code]

    from abc import ABC
    from typing import Type
    class Drink(ABC):
        pass
    class Cola(Drink):
        pass
    class Tea(Drink):
        pass
    def create_drink(drink: Type[Drink]) -> Drink: # ここのTypeHintを改善したい
        return drink()
    
    # VS Codeなどで見た際にCola型と認識してくれない
    created_drink = create_drink(Cola)
    
[/code]


CC BY-SA 4.0
2021-10-28T00:36:52.547
83287
2021-10-28T17:04:02.683
2021-10-28T17:04:02.683
13022
13022
question
python python3
Pythonで関数にTypeHintをつける場合に引数の型を元にした型を返り値にするにはどうすればよいのでしょうか


クラスの継承との関係であれば、以下のようなコードがPythonだと可能のようです。

[code]

    class Drink():
        @classmethod
        def create_drink(self):
            return self
            
        def printDrinkType():
            print("Drink")
        
    class Cola(Drink):
        def printDrinkType():
            print("Cola")
    
    
    drink = Drink.create_drink()
    drink.printDrinkType() # Drink
    
    cola = Cola.create_drink()
    cola.printDrinkType() # Cola
    
[/code]


CC BY-SA 4.0
2021-10-28T02:15:14.840
83292
2021-10-28T02:15:14.840
40856
83287
answer


typing の TypeVarで他の言語で言うところのTみたいなのが定義できます。

[code]

    from typing import TypeVar, Type
    
    T = TypeVar("T", bound=Drink)
    def create_drink(drink: Type[T]) -> T:
        return drink()
    
    created_drink = create_drink(Cola)
    
[/code]

気になったので補足なのですが、Pythonの型ヒントはあくまでヒントなので実行時になにか影響するわけではないです。  
なのでコメントに「#created_drinkの型はDrinkであり、Colaではない」とありますが、Typeヒントがあろうとなかろうと間違っていようとColaのオブジェクトが返ってきます。

[code]

    #元のコード
    def create_drink(drink: Type[Drink]) -> Drink: 
        return drink()
    
    created_drink = create_drink(Cola)
    print(type(created_drink))  # 出力は→ <class '__main__.Cola'>
    
[/code]

VSCodeなどのIDEを使うと、TypeHintの定義を見てイイ感じに補完機能が効いたり、警告だしたりしてくれますね。  
[![Colaで補完](https://i.stack.imgur.com/hRuhz.png)](https://i.stack.imgur.com/hRuhz.png)

[![Teaで補完](https://i.stack.imgur.com/0ysQR.png)](https://i.stack.imgur.com/0ysQR.png)


CC BY-SA 4.0
2021-10-28T05:01:06.097
83299
2021-10-28T05:01:06.097
28626
83287
answer