【问题标题】:Python: can a class instance evaluate to any type?Python:类实例可以评估为任何类型吗?
【发布时间】:2012-05-03 01:17:46
【问题描述】:

一个类可以通过它的 __str__ 方法作为一个字符串,或者通过它的 __call__ 方法作为一个函数。它可以充当列表或元组吗?

class A (object):
    def __???__ (self):
        return (1, 2, 3)

>>> a = A()
>>> a * 3
(1, 2, 3, 1, 2, 3, 1, 2, 3)

编辑...

这里有一个更好的例子来帮助阐明上述内容。

class Vector (object):
    def __init__ (self):
        self.vec = (1,2,3)
    def __???__ (self):
        # something like __repr__; non-string
        return self.vec

class Widget (object):
    def __init__ (self):
        self.vector = Vector()

>>> w = Widget()
>>> w.vector
(1, 2, 3) # not a string representation (at least, before being repr'd here)

基本上,我想要 __repr__ 之类的东西,它不返回字符串,而是在我简单地调用指向 Vector 实例的名称时返回一个元组(或列表),但我不想丢失其余的实例中的能力,例如访问其他属性和方法。我也不想使用w.vector.vec 来获取数据。我希望向量像 w 的元组属性一样起作用,同时仍然能够执行 w.vector.whatever() 之类的操作,或者覆盖 __mul__ 以便我可以通过 w.vector * 5 缩放向量。可能吗?

【问题讨论】:

  • 当您调用__str__ 时,该类不会充当字符串,它会创建并返回一个新的字符串对象。我真的不明白你在做什么......

标签: python class tuples


【解决方案1】:

根据您的目标,您可以创建一个继承自 listtuple 等内置类的类:

>>> class A(tuple):
...     def speak(self):
...         print "Bark!"
... 
>>> a = A((1,2,3)) # extra parens needed to distinguish single tuple arg from 3 scalar args
>>> a * 3
(1, 2, 3, 1, 2, 3, 1, 2, 3)
>>> a.speak()
Bark!

鉴于您的 Vector 用例,子类化元组可能会成功。

import math

class Vector(tuple):
    def magnitude(self):
        return math.sqrt( self[0]*self[0]+self[1]*self[1]+self[2]*self[2] )

【讨论】:

  • 我要测试一下,但我认为这就是答案。我基本上想要一个可以使用/执行其他操作的元组,例如添加属性和方法并访问它们,但是如果我只是在任何地方使用 it,我希望它“成为”一个元组。
  • 您的更大目标是什么?你可能想要 Panda3D 什么的。
  • 这很有趣。我们实际上在我的公司使用 Panda。我的目标是能够将向量之类的东西作为某些类实例的类似常量的属性,可以很容易地作为实例属性(iewvector)访问,简单地缩放(例如w.vector*3缩放每个组件),并在自定义方法的许多其他方式(egwvector.inWorld())。我还希望这些属性能够提供有关它们自身的更多信息(例如 w.vector.property)。
  • @GaryFixler:你确定你不想继承像numpy.array() 这样的子类,而不是普通的Python tuplelist
  • 我不确定,因为我没有研究过 numpy.但是,如果我使用 numpy,这意味着更多的研发时间,并且需要将其部署为工具链的一部分,这会稍微降低 ROI。我的需求在这里很简单。
【解决方案2】:

对于您示例中的特定行为(A*3 给出了A 中数据的三个串联副本),您希望实现__mul__() 运算符。

例如,这些是等价的:

>>> a = [1,2,3]
>>> a*3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> a.__mul__(3)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 

更一般地说,如果你想实现一个序列类型,你必须实现所有的operations defined for sequence types。你必须定义 -

  • A[3] 是什么意思(__getitem__()__setitem__()
  • A[1:10] 是什么意思 (__getslice__())
  • for item in A: 是什么意思 (__iter__())

等等。

这是lists 上定义的方法的完整列表:

>>> pprint.pprint(dict(list.__dict__))
{'__add__': <slot wrapper '__add__' of 'list' objects>,
 '__contains__': <slot wrapper '__contains__' of 'list' objects>,
 '__delitem__': <slot wrapper '__delitem__' of 'list' objects>,
 '__delslice__': <slot wrapper '__delslice__' of 'list' objects>,
 '__doc__': "list() -> new empty list\nlist(iterable) -> new list initialized from iterable's items",
 '__eq__': <slot wrapper '__eq__' of 'list' objects>,
 '__ge__': <slot wrapper '__ge__' of 'list' objects>,
 '__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>,
 '__getitem__': <method '__getitem__' of 'list' objects>,
 '__getslice__': <slot wrapper '__getslice__' of 'list' objects>,
 '__gt__': <slot wrapper '__gt__' of 'list' objects>,
 '__hash__': None,
 '__iadd__': <slot wrapper '__iadd__' of 'list' objects>,
 '__imul__': <slot wrapper '__imul__' of 'list' objects>,
 '__init__': <slot wrapper '__init__' of 'list' objects>,
 '__iter__': <slot wrapper '__iter__' of 'list' objects>,
 '__le__': <slot wrapper '__le__' of 'list' objects>,
 '__len__': <slot wrapper '__len__' of 'list' objects>,
 '__lt__': <slot wrapper '__lt__' of 'list' objects>,
 '__mul__': <slot wrapper '__mul__' of 'list' objects>,
 '__ne__': <slot wrapper '__ne__' of 'list' objects>,
 '__new__': <built-in method __new__ of type object at 0x1E1DACA8>,
 '__repr__': <slot wrapper '__repr__' of 'list' objects>,
 '__reversed__': <method '__reversed__' of 'list' objects>,
 '__rmul__': <slot wrapper '__rmul__' of 'list' objects>,
 '__setitem__': <slot wrapper '__setitem__' of 'list' objects>,
 '__setslice__': <slot wrapper '__setslice__' of 'list' objects>,
 '__sizeof__': <method '__sizeof__' of 'list' objects>,
 'append': <method 'append' of 'list' objects>,
 'count': <method 'count' of 'list' objects>,
 'extend': <method 'extend' of 'list' objects>,
 'index': <method 'index' of 'list' objects>,
 'insert': <method 'insert' of 'list' objects>,
 'pop': <method 'pop' of 'list' objects>,
 'remove': <method 'remove' of 'list' objects>,
 'reverse': <method 'reverse' of 'list' objects>,
 'sort': <method 'sort' of 'list' objects>}

【讨论】:

  • 我知道 __mul__ 运算符,并将为此需要实现它。但是,在我的示例中,我只是想证明它确实返回了一个元组,而不是元组的字符串表示形式。它可以简单地使用类来充当类型,同时仍保留其他功能,例如调用我感兴趣的方法。也许我可以以某种方式子类化元组?
  • @GaryFixler:如果您希望能够将对象转换为元组,则需要使对象“可迭代”。 (还记得TypeError: 'A' object is not iterable 错误吗?这就是它所说的。)实现__iter__() 应该足以做到这一点。然后tuple(A),扩展为tuple(A.__iter__()),应该做你想做的事。同样,A 上的循环将起作用,列表推导将起作用,等等。
  • @Li-aungYip 请注意,您不需要将 __setitem__ 实现为序列协议的一部分(除非您明确希望它是可变的,在这种情况下您要实现 __delitem__ , insert 和其他人),并且 __{get,set,del}slice__ 已被弃用一段时间,有利于将 slice 对象传递给 __{get,set,del}item__。一个类实现完整序列协议的最好和最简单的方法是从collections.Sequence(或者,collections.abc.Sequence 3.3)继承。 (当然,除非从现有的序列类型继承是有意义的)。
  • @lvc:谢谢。我忘了提到 sequence 类型实际上只需要是可迭代的。 get*set* 只需要随机访问元素。还有关于collections.Sequence 的好信息,谢谢。
【解决方案3】:

当您调用 str 时,该类不充当字符串。它创建并返回一个新的字符串对象。基本上当你在一个对象上调用str(something) 时,这就是真正发生的事情:

a = str(someObject)

a = someObject.__str__()

所以str函数基本上可以认为是这样做的:

def str(variable):
    return variable.__str__()

当您调用list()tuple()set() 等时也是如此。如果我认为您的问题是正确的:

tuple()list()set() 都调用类的 __iter__() 方法,所以你要做的是:

class MyClass(object):
    ...
    def __iter__(self):
        ...
        return myIterable

【讨论】:

  • 我知道它正在创建和返回一个字符串,但对我来说,这符合充当字符串的类的定义。我不知道它会如何工作。 __iter__ 是迄今为止我得到的最接近的答案,但它仍然需要额外的工作,比如调用 iter 。也许我还没有在脑海中充分定义问题。
  • @GaryFixler:你不必打电话给__iter__()。使用A 的实例,任何需要可迭代类型的地方都会隐式调用__iter__()。例如循环for item in A:for item in A.__iter__(): 的语法糖。因此,如果您定义__iter__(),就足以将A 的实例转换为列表,或者像列表一样使用它们(尽管如果您想实现随机访问,则必须实现__setitem__()__getitem__()也是。)
  • @GaryFixler:不需要额外的工作。 list(myObject) 隐式调用 myObject.__iter__(),任何需要迭代器的表达式也是如此。
  • @JoelCornett:手比眼睛快!
  • @GaryFixler:你为什么不继承元组?
猜你喜欢
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 2022-05-26
  • 2023-01-09
  • 2021-04-10
相关资源
最近更新 更多