Python类返回值

38
我想创建一个返回值而不是self的类。
我会给你展示一个与列表进行比较的例子:
>>> l = list()
>>> print(l)
[]
>>> class MyClass:
>>>     pass

>>> mc = MyClass()
>>> print mc
<__main__.MyClass instance at 0x02892508>

我需要让MyClass返回一个列表,就像list()一样,而不是实例信息。我知道可以创建一个列表的子类,但是否有一种不用创建子类的方法呢?

我想模仿一个列表(或其他对象):

>>> l1 = list()
>>> l2 = list()
>>> l1
[]
>>> l2
[]
>>> l1 == l2
True
>>> class MyClass():
def __repr__(self):
    return '[]'


>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1
[]
>>> m2
[]
>>> m1 == m2
False

为什么m1 == m2的结果是False?这是问题所在。

如果我没有回复你们所有人,我很抱歉。我正在尝试你们给我的所有解决方案。我不能使用def,因为我需要使用像setitem、getitem等函数。


1
真正想做什么?为什么要模拟一个列表?使用实际的列表有什么问题吗? - Karl Knechtel
6个回答

55

我认为你对正在发生的事情非常困惑。

在Python中,一切都是对象:

  • [](一个列表)是一个对象
  • 'abcde'(一个字符串)是一个对象
  • 1(一个整数)是一个对象
  • MyClass()(一个实例)是一个对象
  • MyClass(一个类)也是一个对象
  • list(一种类型——很像一个类)也是一个对象

它们都是“值”,因为它们是一种东西,而不是指向一种东西的名称。 (变量是指向值的名称。)在Python中,值不是与对象不同的东西。

当你调用一个类对象(比如 MyClass()list()),它会返回该类的一个实例。(list 实际上是一种类型而不是一个类,但我这里进行了简化。)

当你 print 一个对象(即获取一个对象的字符串表示),它会调用该对象的 __str____repr__ 魔法方法 并打印返回的值。

例如:

>>> class MyClass(object):
...     def __str__(self):
...             return "MyClass([])"
...     def __repr__(self):
...             return "I am an instance of MyClass at address "+hex(id(self))
... 
>>> m = MyClass()
>>> print m
MyClass([])
>>> m
I am an instance of MyClass at address 0x108ed5a10
>>> 
所以你所要求的,“我需要MyClass返回一个列表,就像list()一样,而不是实例信息”,没有任何意义。list() 返回一个列表实例。MyClass() 返回一个MyClass实例。如果你想要一个列表实例,只需获取一个列表实例即可。如果问题是关于在print或控制台上查看这些对象的外观,那么创建一个__str____repr__方法来表示它们的外观.

更新新问题的等式

再次提醒,__str____repr__ 只用于打印,不会以任何其他方式影响对象。仅因为两个对象具有相同的__repr__值,并不意味着它们相等!

MyClass() != MyClass() 因为你的类没有定义如何相等,所以它倒回到默认行为(object类型),即对象只等于它们自己:

>>> m = MyClass()
>>> m1 = m
>>> m2 = m
>>> m1 == m2
True
>>> m3 = MyClass()
>>> m1 == m3
False

如果您想进行更改,请使用比较魔术方法之一

例如,您可以拥有一个等于所有东西的对象:

>>> class MyClass(object):
...     def __eq__(self, other):
...             return True
... 
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1 == m2
True
>>> m1 == m1
True
>>> m1 == 1
True
>>> m1 == None
True
>>> m1 == []
True

我认为你应该做两件事情:

  1. 查看这篇关于Python中魔术方法使用的指南
  2. 解释为什么不应该继承 list 如果你想要一个非常类似于列表的对象。如果继承不合适,你可以委托给一个包装了列表实例的对象:

    class MyClass(object):
        def __init__(self):
            self._list = []
        def __getattr__(self, name):
            return getattr(self._list, name)
    
        # __repr__ and __str__ methods are automatically created
        # for every class, so if we want to delegate these we must
        # do so explicitly
        def __repr__(self):
            return "MyClass(%s)" % repr(self._list)
        def __str__(self):
            return "MyClass(%s)" % str(self._list)
    

    现在这将像一个列表一样工作,但不是一个列表(即,没有继承list)。

    >>> c = MyClass()
    >>> c.append(1)
    >>> c
    MyClass([1])
    

1
链接到http://www.rafekettler.com/magicmethods.html的网站已过期/被劫持:(很遗憾看到现在有这么多具有优秀文档的网站正在消失。 - n3storm
1
@n3storm 通过跟踪Github issue解决问题,找到了魔术方法指南的另一个来源。 - Francis Avila
rafekettler.com 的魔术方法指南仍然存档在 Wayback Machine / Internet Archive 上这里,同时也可以在 GitHub 上找到源代码。 - Andrew Richards

47

如果你想把你的类转换成一种列表,而不需要继承list,那么只需创建一个返回列表的方法:

def MyClass():
    def __init__(self):
        self.value1 = 1
        self.value2 = 2

    def get_list(self):
        return [self.value1, self.value2...]


>>>print MyClass().get_list()
[1, 2...]

如果你的意思是 print MyClass() 会打印一个列表,那么只需重载 __repr__

如果你指的是 print MyClass() 會印出一個列表,只需要覆寫 __repr__ 即可:

class MyClass():        
    def __init__(self):
        self.value1 = 1
        self.value2 = 2

    def __repr__(self):
        return repr([self.value1, self.value2])

修改: 我明白你的意思是如何使对象比较。 为此,您需要覆盖__cmp__方法。

class MyClass():
    def __cmp__(self, other):
        return cmp(self.get_list(), other.get_list())

1
那就是我不想做的事情。我不想使用mc1.getValue() == mc2.getValue()。我想比较mc1 == mc2,而不需要getValue。但结果总是False。 - Harry Hache

19

使用__new__从类中返回值。

正如其他人建议的那样,__repr____str__甚至__init__(某种程度上)可以给你想要的东西,但是对于你的目的来说,__new__将是一个语义上更好的解决方案,因为你希望返回实际的对象而不仅仅是它的字符串表示。

阅读此答案以了解更多关于__str____repr__的见解 https://dev59.com/H2Ik5IYBdhLWcg3wYtNC#19331543

class MyClass():
    def __new__(cls):
        return list() #or anything you want

>>> MyClass()
[]   #Returns a true list not a repr or string

为什么这是更好的解决方案? - desa
因为你并不总是需要返回一个对象的字符串表示。在这种情况下,使用 __str____repr__ 是错误的。当然,你可以使用任何东西来返回任何内容,但 __str____repr__ 不是为此而设计的。 - Kashif Siddiqui
它会一直创建新的 list() 对象吗? - alper

11
class MyClass():
    def __init__(self, a, b):
        self.value1 = a
        self.value2 = b

    def __call__(self):
        return [self.value1, self.value2]

测试:

>>> x = MyClass('foo','bar')
>>> x()
['foo', 'bar']

4
您正在描述一个函数,而不是一个类。
def Myclass():
    return []

0
返回翻译文本:对于我来说,可行的方案是在创建小数列表的类上使用__call__
import itertools
    
class SmallNumbers:
    def __init__(self, how_much):
        self.how_much = int(how_much)
        self.work_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
        self.generated_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
        start = 10
        end = 100
        for cmb in range(2, len(str(self.how_much)) + 1):
            self.ListOfCombinations(is_upper_then=start, is_under_then=end, combinations=cmb)
            start *= 10
            end *= 10

    def __call__(self, number, *args, **kwargs):
        return self.generated_list[number]

    def ListOfCombinations(self, is_upper_then, is_under_then, combinations):
        multi_work_list = eval(str('self.work_list,') * combinations)
        nbr = 0
        for subset in itertools.product(*multi_work_list):
            if is_upper_then <= nbr < is_under_then:
                self.generated_list.append(''.join(subset))
                if self.how_much == nbr:
                    break
            nbr += 1

并运行它:

if __name__ == '__main__':
        sm = SmallNumbers(56)
        print(sm.generated_list)
        print(sm.generated_list[34], sm.generated_list[27], sm.generated_list[10])
        print('The Best', sm(15), sm(55), sm(49), sm(0))

结果

['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉', '₁₀', '₁₁', '₁₂', '₁₃', '₁₄', '₁₅', '₁₆', '₁₇', '₁₈', '₁₉', '₂₀', '₂₁', '₂₂', '₂₃', '₂₄', '₂₅', '₂₆', '₂₇', '₂₈', '₂₉', '₃₀', '₃₁', '₃₂', '₃₃', '₃₄', '₃₅', '₃₆', '₃₇', '₃₈', '₃₉', '₄₀', '₄₁', '₄₂', '₄₃', '₄₄', '₄₅', '₄₆', '₄₇', '₄₈', '₄₉', '₅₀', '₅₁', '₅₂', '₅₃', '₅₄', '₅₅', '₅₆']
₃₄ ₂₇ ₁₀
The Best ₁₅ ₅₅ ₄₉ ₀

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接