【问题标题】:Change representation of Python object更改 Python 对象的表示
【发布时间】:2015-10-31 09:56:14
【问题描述】:

在 Python 中,数据类型(如 int、float)既表示一个值,也有一些内置的属性/函数/等:

In [1]: a = 1.2

In [2]: a
Out[2]: 1.2

In [3]: a.is_integer()
Out[3]: False

是否可以在 Python 中重现此行为,例如定义一个类:

class Scalar:
    def __init__(self, value)
        self.value = value

    # other code ....

s = Scalar(1.2)

我可以让s 返回 1.2(而不是输入s.value),然后执行a = s -> a = 1.2 之类的操作?我最接近这种行为的方法是添加如下内容:

def __getitem__(self, key=None):
    return self.value

并使用a = s[()],但这看起来不太好。

【问题讨论】:

  • Python property callable 的可能重复项
  • 特别是查看带有WeirdInteger 类的sn-p。
  • 这不是一个通用的解决方案,但您可以通过简单地继承 float(或 int,或您想模仿的任何其他标量类型)使您的示例中的 Scalar 类按照您想要的方式工作)。 class Scalar(float): pass; s = Scalar(1.2)
  • 子类化一个类型可能有效,我必须看看它是否适用于我的(更复杂的..)问题,但我会试一试!

标签: python object


【解决方案1】:

我可以让 s 返回 1.2(而不是输入 s.value)

在控制台中?然后实现__repr__方法。

a = s -> a = 1.2

为避免必须使用a = s.value,您可以实现__call__ 并调用对象:

>>> class Scalar:
...     def __init__(self, value):
...         self.value = value
...     def __repr__(self):
...         return str(self.value)
...     def __call__(self):
...         return self.value
... 
>>> s = Scalar(1.2)
>>> s
1.2
>>> a = s()
>>> a
1.2

查看有关data model on emulating numeric types 的文档。

例如:

class Scalar:
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return str(self.value)
    def __call__(self):
        return self.value
    def __add__(self, other):
        return Scalar(self.value + other.value)
    def __lt__(self, other):
        return self.value < other.value
    def ___le__(self, other):
        return self.value <= other.value
    def __eq__(self, other):
        return self.value == other.value
    def __ne__(self, other):
        return self.value != other.value
    def __gt__(self, other):
        return self.value > other.value
    def __ge__(self, other):
        return self.value >= other.value

可以这样使用:

>>> s1 = Scalar(1.2)
>>> s2 = Scalar(2.1)
>>> s1 + s2
3.3
>>> s1 < s2
True
>>> s1 > s2
False
>>> s1 != s2
True
>>> s1 <= s2
True
>>> s1 >= s2
False

还有__int____float__ 魔术方法,您可以像这样实现和使用它们(这在语义上更正确):

>>> a = int(s)
>>> a = float(s)

【讨论】:

  • 好吧,__call__ 去掉了一组括号,所以这是一个改进;-) 如果我找不到其他解决方案并且上面的建议(使用 class Scalar(float))不要'行不通,这可能是一个可以接受的解决方案
  • __repr__ 如果您尝试返回除字符串以外的任何内容:TypeError: __repr__ returned non-string (type float),将会抱怨。这也不会影响问题中描述的赋值语句 (a = s)。
【解决方案2】:

据我所知,这对于您的 a = s 示例是不可能的。您必须更改赋值运算符= 的行为。赋值运算符实际上并没有对右边的对象做任何事情,它只是复制一个对它的引用(至少在对象的情况下)。

通常,可以使用operator overloading 更改自定义类的内置运算符的行为,但 Python 不提供这种类型的赋值选项 (=),因为它与加法 (+) 甚至相等 (==) 等运算符。

【讨论】:

  • 当这个答案与here的所有答案基本相同时,为什么会被否决?
  • @Two-BitAlchemist - 当基本子类化使之成为可能时,它会说“那是不可能的”。
  • @TigerhawkT3 有点...在一般情况下这不可能,如果这是 only i> 你想要的行为。
  • 这个答案是正确的。它只回答了部分问题,但由于 = 不能被覆盖,所以 OP 无法获得他们所追求的完整行为。
猜你喜欢
  • 2019-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
相关资源
最近更新 更多