2017-09-01 4 views
3

BaseChildの2つのクラスがファクトリメソッドBaseにあるとします。ファクトリメソッドは、Baseの子クラスによって上書きされるかもしれない別のクラスメソッドを呼び出します。子クラスのインスタンスを返すベースクラスのファクトリメソッドのヒント:

class Base(object): 
    @classmethod 
    def create(cls, *args: Tuple) -> 'Base': 
     value = cls._prepare(*args) 
     return cls(value) 

    @classmethod 
    def _prepare(cls, *args: Tuple) -> Any: 
     return args[0] if args else None 

    def __init__(self, value: Any) -> None: 
     self.value = value 


class Child(Base): 
    @classmethod 
    def _prepare(cls, *args: Tuple) -> Any: 
     return args[1] if len(args) > 1 else None 

    def method_not_present_on_base(self) -> None: 
     pass 

静的型チェッカーは、Base.create()Baseのインスタンスを返し、次の例では、静的解析を通過するようにChild.create()は、Childのインスタンスを返したことを推測することができるようにBase.createに注釈を付ける方法はありますか?

base = Base.create(1) 
child = Child.create(2, 3) 
child.method_not_present_on_base() 

は、上記の例では、静的な型チェックは当然method_not_present_on_baseBaseクラスに存在しない、十分であることを訴えることになります。


私は、ジェネリッククラスにBaseを回すと、子クラスは、すなわちPythonのにCRTPをもたらし、型引数として自分自身を指定することについて考えました。

T = TypeVar('T') 

class Base(Generic[T]): 
    @classmethod 
    def create(cls, *args: Tuple) -> T: ... 

class Child(Base['Child']): ... 

しかし、これはCRTPは、C++およびすべてから来るとむしろunpythonic感じ...

答えて

2

それが実際に可能である:我々はこれを使用しているので、これは少し紛らわしいですが、機能は(TypeVar with Generic Selfと呼ばれていますこの場合はクラスメソッド)。私はあなたがリンクしている "CRTP"テクニックとほぼ同じように動作すると信じています(私はC++の専門家ではありませんので、確かに言うことはできません)。我々は唯一の必要があるので、私たちは、クラス自体は汎用的にする必要はありません

  1. :という

    from typing import TypeVar, Type, Tuple 
    
    T = TypeVar('T', bound='Base') 
    
    class Base: 
        @classmethod 
        def create(cls: Type[T], *args: Tuple[Any]) -> T: ... 
    
    class Child(Base): 
        @classmethod 
        def create(cls, *args: Tuple[Any]) -> 'Child': ... 
    

    注:

    いずれにせよ、あなたはそうのようなあなたのベースと子のクラスを宣言します

  2. TypeVarのバインドを 'Base'に設定することは、厳密にはオプションですが、おそらく良い考えです。この方法では、基本クラス/サブクラスの呼び出し元は、少なくとも基本クラスで定義されたメソッドを呼び出すことができますあなたがしてもあなたが扱っているサブクラスを正確には知らない。
  3. 子の定義については、clsの注釈を省略することができます。
+0

ありがとうございます!残念ながら、PyCharmは 'cls'のプライベートメソッドを別のオブジェクトのプライベートメンバにアクセスするように扱いますが、mypyはこれを期待通りに扱います。 – PoByBolek

+0

これは本当にクールです!あなたの答えに感謝します。 – bjd2385

関連する問題