子类化int会导致意外行为

时间:2016-01-15 13:47:29

标签: python

我正在尝试使用int类的子类来附加一个额外的标签(“标题”)。如果我访问单个对象,所有都可以工作,但如果我在列表中收集多个,它们都具有相同的属性,而我希望它们具有我在创建对象时指定的属性。

我还尝试使用方法而不是属性来进一步获得结果。

我正在使用Python 3.4.3。

import unittest

class LabeledInt(int):
    def __new__(cls, *args, **kwargs):
        cls._headline = args[1]
        return super(LabeledInt, cls).__new__(cls, args[0])

    @property
    def headline(self):
        return self._headline

class SomeNumbers:
    def __init__(self, arg):
        self.arg = arg

    @property
    def something(self):
        return LabeledInt(self.arg, "Something")

    @property
    def something_squared(self):
        return LabeledInt(self.arg ** 2, "Squared")

    @property
    def something_exponential(self):
        return LabeledInt(self.arg ** self.arg, "Exp.")

    def all_numbers(self):
        array = [
            LabeledInt(self.arg, "Something"),
            LabeledInt(self.arg ** 2, "Squared"),
            LabeledInt(self.arg ** self.arg, "Exp.")
        ]
        return array

S = SomeNumbers(2)


class Test(unittest.TestCase):
    def test_something(self):
        self.assertEqual(2, S.something)
        self.assertEqual("Something", S.something.headline)

    def test_something_squard(self):
        self.assertEqual(4, S.something_squared)
        self.assertEqual("Squared", S.something_squared.headline)

    def test_exp(self):
        self.assertEqual(4, S.something_exponential)
        self.assertEqual("Exp.", S.something_exponential.headline)

    def test_all_numbers_1(self):
        self.assertEqual(2, S.all_numbers()[0])

    def test_all_numbers_2(self):
        self.assertEqual("Something", S.all_numbers()[0].headline)

    def test_all_numbers_3(self):
        self.assertEqual(4, S.all_numbers()[1])

    def test_all_numbers_4(self):
        self.assertEqual("Squared", S.all_numbers()[1].headline)

    def test_all_numbers_5(self):
        self.assertEqual(4, S.all_numbers()[2])

    def test_all_numbers_6(self):
        self.assertEqual("Exp.", S.all_numbers()[2].headline)

for n in S.all_numbers():
    print(n.headline)
>>>
Exp.
Exp.
Exp.

测试“test_all_numbers_2”和“... 4”失败。

为什么会这样?围绕它的最佳方法是什么?非常感谢。

1 个答案:

答案 0 :(得分:1)

class LabeledInt(int):
    def __new__(cls, *args, **kwargs):
        cls._headline = args[1]
#       ^^^
        return super(LabeledInt, cls).__new__(cls, args[0])

您正在设置的属性,而不是实例的属性。试试这个:

class LabeledInt(int):
    def __new__(cls, *args, **kwargs):
        self = super(LabeledInt, cls).__new__(cls, args[0])
        self._headline = args[1]
#       ^^^^
        return self

PS:如果您既没有使用它们,也没有传递它们,请不要使用*args**kwargs。此外,Python 3的super()不再需要参数。考虑使用此代码:

class LabeledInt(int):
    def __new__(cls, value, headline):
        self = super().__new__(cls, value)
        self._headline = headline
        return self