私はPythonで値オブジェクトを定義する良い方法について興味があります。 Wikipedia:value objectは、同一性がアイデンティティに基づいていない単純なエンティティを表す小さなオブジェクトです。つまり、2つの値オブジェクトが同じ値を持ち、必ずしも同じオブジェクトである必要はありません。 Pythonでは、本質的に、__eq__
と__hash__
のメソッドと、不変性を再定義することを意味します。PythonでPyCharmに優しい値オブジェクトを定義する方法は?
標準namedtuple
はPyCharmのような現代的なPython IDEではうまく動作しないという例外を除いてほぼ完璧なソリューションのようです。私は、IDEがnamedtuple
として定義されたクラスについての有用な洞察を実際に提供しないことを意味します。それは可能ですが、このようなトリックを使用して、このようなクラスにドキュメンテーション文字列を添付します
class Point2D(namedtuple("Point2D", "x y")):
"""Class for immutable value objects"""
pass
単にコンストラクタ引数の説明を入れて、自分の型を指定する場所がありません。 PyCharmは、Point2D
"コンストラクタ"の引数を推測するのに十分なほどスマートですが、それは盲目的です。
このコードでプッシュされ、いくつかの種類の情報を持っているが、それは非常に便利ではありません:PyCharmは、新しいオブジェクトを構築する際に種類が表示されますが、それpoint.xとpoint.yがフロートしている把握しています
class Point2D(namedtuple("Point2D", "x y")):
"""Class for immutable value objects"""
def __new__(cls, x, y):
"""
:param x: X coordinate
:type x: float
:param y: Y coordinate
:type y: float
:rtype: Point2D
"""
return super(Point2D, cls).__new__(cls, x, y)
point = Point2D(1.0, 2.0)
彼らの誤用を検出するのに役立ちません。また、私は、「魔法」の方法を定期的に再定義するという考えを嫌っています。に簡単に
- 同じように通常のPythonクラスとして定義することは容易またはnamedtuple
- 値のセマンティクス(平等、ハッシュ、不変性)を提供
- :
だから私はなります何かを探しています
:IDE とうまく再生されます方法で文書
理想的なソリューションは、このようになります。
class Point2D(ValueObject):
"""Class for immutable value objects"""
def __init__(self, x, y):
"""
:param x: X coordinate
:type x: float
:param y: Y coordinate
:type y: float
"""
super(Point2D, self).__init__(cls, x, y)
か、その:
class Point2D(object):
"""Class for immutable value objects"""
__metaclass__ = ValueObject
def __init__(self, x, y):
"""
:param x: X coordinate
:type x: float
:param y: Y coordinate
:type y: float
"""
pass
私はこのような成功せず、何かを見つけることを試みました。私は自分でそれを実装する前に助けを求めることが賢明であると思った。
更新日: user4815162342の助けを借りて、私は何かを考え出すことができました。コードは次のとおりです。
class ValueObject(object):
__slots__ =()
def __repr__(self):
attrs = ' '.join('%s=%r' % (slot, getattr(self, slot)) for slot in self.__slots__)
return '<%s %s>' % (type(self).__name__, attrs)
def _vals(self):
return tuple(getattr(self, slot) for slot in self.__slots__)
def __eq__(self, other):
if not isinstance(other, ValueObject):
return NotImplemented
return self.__slots__ == other.__slots__ and self._vals() == other._vals()
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self._vals())
def __getstate__(self):
"""
Required to pickle classes with __slots__
Must be consistent with __setstate__
"""
return self._vals()
def __setstate__(self, state):
"""
Required to unpickle classes with __slots__
Must be consistent with __getstate__
"""
for slot, value in zip(self.__slots__, state):
setattr(self, slot, value)
これは理想的な解決策とはほど遠いものです。 __slots__
で、CTOR引数で、ドキュメンテーション文字列内とCTOR本体内:
class X(ValueObject):
__slots__ = "a", "b", "c"
def __init__(self, a, b, c):
"""
:param a:
:type a: int
:param b:
:type b: str
:param c:
:type c: unicode
"""
self.a = a
self.b = b
self.c = c
それはすべての属性を一覧表示するには、4回の合計です:クラスの宣言は次のようになります。これまでのところ私はそれをあまり厄介なものにする方法を知らない。
'namedtuple'はタプルインターフェース(索引付け、アンパック)と属性アクセスの両方を提供することを主な目的としています。これは、 'os.stat'や' time.gmtime'のようなタプルを返す関数の後方互換性のために考案されました。単純な値の型に最適な選択ではない可能性があります。 – user4815162342
タイプについて:* PyCharmは、Point2Dの "コンストラクタ"の引数を推測するのに十分なほどスマートですが、タイプワイズです。*静的に型指定された言語を使用する必要がありますか? Pythonでは、IDEがタイプについて盲目的であるほど大したものであってはなりません。 – user4815162342
さて、 'namedtuple'は私にとって正しい仕事です。それは間違いなく単なる価値オブジェクトですが、私はそれで生きることができます。 静的型付けされた言語を使用することについては、できればと思います。しかし、私はPythonプロジェクトを手にして、開発をより快適にする方法を模索しています。 PyCharmはすでにdocstringを使って変数の型を推論するのにとても良い仕事をしています。 –