this または this のように見えますが、関連するスレッドですが、まだ理解できていません:)
namedtuple
のサブクラスを作成し、さまざまな方法でオブジェクトを構築できるようにさまざまな初期化子を提供しようとしています。例えば:
>>> from collections import namedtuple
>>> class C(namedtuple("C", "x, y")) :
... __slots__ = ()
... def __init__(self, obj) : # Initialize a C instance by copying values from obj
... self.x = obj.a
... self.y = obj.b
... def __init__(self, x, y) : # Initialize a C instance from the parameters
... self.x = x
... self.y = y
ただし、それは機能しません。
>>> c = C(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in __init__
AttributeError: can't set attribute
いろいろ調べてから(たとえば、 this threadを参照)、初期化子の代わりにコンストラクターを使用しようとしました。
>>> from collections import namedtuple
>>> class C(namedtuple("C", "x, y")) :
... __slots__ = ()
... def __new__(cls, obj) :
... self = super(C, cls).__new__(cls, obj.a, obj.b)
... def __new__(cls, x, y) :
... self = super(C, cls).__new__(cls, x, y)
オブジェクトを構築しているように見えましたが、その属性を読み取ることができません:
>>> c = C(1,2)
>>> c.x, c.y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'x'
私はここでどこが間違っていますか?複数のコンストラクターまたは初期化子を持つサブクラスを作成するにはどうすればよいですか?
名前付きタプルは不変なので、___init__
_初期化子でそれらを操作することはできません。唯一のオプションは___new__
_メソッドをオーバーライドすることです:
_class C(namedtuple('C', 'x, y')):
__slots__ = ()
def __new__(cls, obj):
return super(C, cls).__new__(cls, obj.x, obj.y)
_
___new__
_は新しいインスタンスのファクトリメソッドであるため、新しく作成されたインスタンスをreturnする必要があることに注意してください。 ___new__
_メソッドでreturn
を使用しない場合、デフォルトの戻り値はNone
であり、エラーが発生します。
x
およびy
属性を持つオブジェクトを使用したデモ:
_>>> class C(namedtuple('C', 'x, y')):
... __slots__ = ()
... def __new__(cls, obj):
... return super(C, cls).__new__(cls, obj.x, obj.y)
...
>>> O.x, O.y
(10, 20)
>>> C(O)
C(x=10, y=20)
_
Pythonはメソッドのオーバーロードをサポートしていません。通常、オプションのキーワード引数または追加のクラスメソッドをファクトリメソッドとして使用します。
たとえば、 datetime
module には、標準のコンストラクタに適合しないオブジェクトを作成できるようにするためのファクトリメソッドがいくつかあります。 datetime.datetime.fromtimestamp()
は、単一の数値から_datetime.datetime
_インスタンスを作成します datetime.datetime.fromordinal()
;ただし、番号はさまざまな方法で解釈されます。
可変引数をサポートする場合は、次を実行します。
_class C(namedtuple('C', 'x, y')):
__slots__ = ()
def __new__(cls, x, y=None):
if y is None:
# assume attributes
x, y = x.x, x.y
return super(C, cls).__new__(cls, x, y)
_
ここで、y
はオプションの引数で、呼び出し元から提供されない場合のデフォルトはNone
です。
_>>> C(3, 5):
C(x=3, y=5)
>>> C(O)
C(x=10, y=20)
_
クラスメソッドを使用する代替方法は次のとおりです。
_class C(namedtuple('C', 'x, y')):
@classmethod
def from_attributes(cls, obj):
return cls(obj.x, obj.y)
_
現在、2つのファクトリーメソッドがあります。 1つのデフォルトと1つの名前:
_>>> C(3, 5):
C(x=3, y=5)
>>> C.from_attributes(O)
C(x=10, y=20)
_
_replace
メソッド
from collections import namedtuple
C = namedtuple('C', 'x, y')
c = C(x=10, y=20)
# c.x = 30 won't work
c = c._replace(x=30)
2つのことがあります。1つは、私が知る限り、ここでnamedtupleからあまり多くを得ていないことです。したがって、通常のクラスに切り替える必要があります。また、あなたはオーバーロードすることはできません
第二に、あなたの問題に役立つかもしれない他の可能性:
工場設計パターン -コンストラクターにさまざまなパラメーターを配置する代わりに、さまざまな種類のパラメーターを取り、オブジェクトの外部で適切な引数を使用してコンストラクターを呼び出すクラスを用意します。 recordtype -変更可能な名前付きタプル。デフォルトを許可しますが、元の方法でサブクラスを記述することもできます。 bunch -名前付きタプルではありませんが、いくぶん任意のオブジェクトを作成できます。
名前付きタプルの属性を変更する回避策があります。
import collections
def updateTuple(NamedTuple,nameOfNamedTuple):
## Convert namedtuple to an ordered dictionary, which can be updated
NamedTuple_asdict = NamedTuple._asdict()
## Make changes to the required named attributes
NamedTuple_asdict['path']= 'www.google.com'
## reconstruct the namedtuple using the updated ordered dictionary
updated_NamedTuple = collections.namedtuple(nameOfNamedTuple, NamedTuple_asdict.keys())(**NamedTuple_asdict)
return updated_NamedTuple
Tuple = collections.namedtuple("Tuple", "path")
NamedTuple = Tuple(path='www.yahoo.com')
NamedTuple = updateTuple(NamedTuple, "Tuple")