私はリストの記述子を作成しました。それをテストした後Pythonは複数のインスタンスに値を追加しています
は、私は1つのインスタンスのリストに値を追加するたびに、それは同様に別のインスタンスに追加されているようです。
ユニットテストでは、リストに追加されたままであり、すべてのテストでリセットされることはありません。
私の記述メインクラス:
class Field(object):
def __init__(self, type_, name, value=None, required=False):
self.type = type_
self.name = "_" + name
self.required = required
self._value = value
def __get__(self, instance, owner):
return getattr(instance, self.name, self.value)
def __set__(self, instance, value):
raise NotImplementedError
def __delete__(self, instance):
raise AttributeError("Can't delete attribute")
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = value if value else self.type()
記述子リストクラス:
class ListField(Field):
def __init__(self, name, value_type):
super(ListField, self).__init__(list, name, value=[])
self.value_type = value_type
def __set__(self, instance, value):
if not isinstance(value, list):
raise TypeError("{} must be a list".format(self.name))
setattr(instance, self.name, value)
def __iter__(self):
for item in self.value:
yield item
def __len__(self):
return len(self.value)
def __getitem__(self, item):
return self.value[item]
def append(self, value):
if not isinstance(value, self.value_type):
raise TypeError("Value is list {} must be of type {}".format(self.name, self.value_type))
self.value.append(value)
ユニットテスト:
# Class I created solely for testing purposes
class ListTestClass(object):
l = ListField("l", int)
class TestListFieldClass(unittest.TestCase):
def setUp(self):
self.listobject = ListTestClass()
def test_add(self):
# The first number is added to the list
self.listobject.l.append(2)
def test_multiple_instances(self):
# This test works just fine
l1 = ListField("l1", int)
l2 = ListField("l2", int)
l1.append(1)
l2.append(2)
self.assertEqual(l1[0], 1)
self.assertEqual(l2[0], 2)
def test_add_multiple(self):
# This test works just fine
l1 = ListField("l1", int)
l1.append(1)
l1.append(2)
self.assertEqual(l1[0], 1)
self.assertEqual(l1[1], 2)
def test_add_error(self):
# This test works just fine
with self.assertRaises(TypeError):
l1 = ListField("l1", int)
l1.append("1")
def test_overwrite_list(self):
# This test works just fine
l1 = ListField("l1", int)
l1 = []
l1.append(1)
def test_overwrite_error(self):
# This test works just fine
l1 = ListTestClass()
l1.l.append(1)
with self.assertRaises(TypeError):
l1.l = "foo"
def test_multiple_model_instances(self):
# I create 2 more instances of ListTestClass
l1 = ListTestClass()
l2 = ListTestClass()
l1.l.append(1)
l2.l.append(2)
self.assertEqual(l1.l[0], 1)
self.assertEqual(l2.l[0], 2)
最後のテストは
Failure
Traceback (most recent call last):
File "/home/user/project/tests/test_fields.py", line 211, in test_multiple_model_instances
self.assertEqual(l1.l[0], 1)
AssertionError: 2 != 1
を失敗しました
私はl1.1
とl2.l
の値を見てみると、彼らは両方の[2, 1, 2]
私はここで何をしないのですを含むリストを持っていますか?
メモリアドレスを調べたところ、リストはすべて同じオブジェクトを指しているようです。
class ListFieldTest(object):
lf1 = ListField("lf1", int)
class TestClass(object):
def __init__(self):
l1 = ListFieldTest()
l2 = ListFieldTest()
l1.lf1.append(1)
l2.lf1.append(2)
print(l1.lf1)
print(l2.lf1)
print(hex(id(l1)))
print(hex(id(l2)))
print(hex(id(l1.lf1)))
print(hex(id(l2.lf1)))
これは、クラス属性であるので、それはクラスのすべてのインスタンスで共有され
[1, 2]
[1, 2]
0x7f987da018d0 --> Address for l1
0x7f987da01910 --> Address for l2
0x7f987d9c4bd8 --> Address for l1.lf1
0x7f987d9c4bd8 --> Address for l2.lf1
を追加する必要はありません(リストのような)参照型のためしかし
なぜ時々 'self.value'と時には' self._value'ですか? –
@JohnZwinck self._valueは、valueプロパティの値を格納するためにのみ使用されます。 _valueはgetterとsetterの値 –
でのみ使用されています。記述子プロトコルを覚えている限り、記述子ベースの属性をクラス変数として割り当てることになっています。そうでなければ、正しく動作しません。http://すべてがさえ、オブジェクトであり、ボンネットの下にそれがポインタを介して操作ですので、Pythonでnbviewer.jupyter.org/urls/gist.github.com/ChrisBeaumont/5758381/raw/descriptor_writeup.ipynb – volcano