2017-09-07 4 views
1

私はしかし、カスタム動作とisinstance()を呼び出すときに、intから継承exemple posintクラスを持っているしたいと思います:isinstanceのカスタム動作を使って新しいタイプを正しく作成する方法は?

>>> isinstance(1, int), isinstance(1, posint) 
(True, True) 
>>> isinstance(-1, int), isinstance(-1, posint) 
(True, False) 

私が最初に試さ:

class posint(int): 

    def __instancecheck__(self, obj): 
     try: 
      obj >= 0 
      return True 
     except: 
      return False 

しかし__instancecheck__をする必要がメタクラスで宣言した。

は、だから私は、この重く、醜いもので終わる:

class NewType(type): 

    def __instancecheck__(self, obj): 
     try: 
      obj >= 0 
      return True 
     except: 
      return False 

class posint(metaclass=NewType): 
    pass 

それは動作しますが、それは良い解決策になることができない...は、継承をサポートしていない、他の検査では動作しません。 ..

その後、私はもっと良いものを実装するために管理:

class CheckedType(type): 

    def __instancecheck__(cls, obj): 
     if not all(isinstance(obj, base) for base in cls.mro()[1:-1]): 
      return False 
     return cls.__instancecheck__(obj) 

class posint(int, metaclass=CheckedType): 

    @classmethod 
    def __instancecheck__(cls, obj): 
     if obj >= 0: 
      return True 
     return False 

をしかし、これは__instancecheck__の乱用です。 私はabcまたはtypingモジュールから何かを使用することができると考えていた...

アイデア?

+0

このクラスは、実際には 'int'のサブクラスである必要はありません。 – user2357112

+0

'int'のすべてのメソッドを継承したいのであれば、... –

+0

これが問題です。 'int'から継承するメソッドは、このクラスの具体的なインスタンスを作成する場合にのみ重要です。そうするつもりなら、あなたのクラスは責任を混同してはいけません。一方では、あなたのクラスは 'isinstance(5、posint)'を使って、正のintnessをチェックする方法として動作するはずです。一方、あなたのクラスの具体的なインスタンスは、 'posint(5)-posint(6)'を禁止する通常の正の 'int'とは異なる振る舞いをするでしょう、あるいはそれらが同じように振る舞うならば、 。 – user2357112

答えて

1

Aこの時、私はこのレシピを使用しているいくつかの実験法の後:

class TypedMeta(type): 
    """Metaclass used for custom types.""" 

    def __instancecheck__(cls, obj): 
     return cls._test(obj) 

    @staticmethod 
    def _init(self, x): 
     if not self._test(x): 
      raise ValueError(f"bad value for '{self.__class__.__name__}' object") 

    def __init__(cls, name, bases, clsdict): 
     if not clsdict.get('_test'): 
      raise TypeError(f"cannot instaciate '{name}' class without '_test' method") 
     setattr(cls, '__init__', TypedMeta._init) 


class posint(int, metaclass=TypedMeta): 
    """Strictly positive 'int'.""" 

    @classmethod 
    def _test(cls, val): 
     return val > 0 

そうでも誰かがこの型のオブジェクトをインスタンス化する、またはそれに他をキャストしたい場合、それが実行されます最初に_testメソッド。

関連する問題