【问题标题】:Python class returning valuePython类返回值
【发布时间】:2012-09-06 21:34:20
【问题描述】:

我正在尝试创建一个返回值而不是自身的类。

我将向您展示一个与列表进行比较的示例:

>>> 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 是假的?这就是问题。

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

【问题讨论】:

  • 如果你想让构造函数MyClass()返回一个列表,你应该使用一个函数,而不是一个类。你的意思是当你打印它时你想让它显示为一个列表吗?
  • 如果你想拥有一个具有列表属性的类,那么这就是子类化的目的。为什么不想从list 继承?
  • 另外,构造没有返回“信息”,信息是对象打印时的样子。 mc 是类 MyClass 的一个实例。
  • 也许您想重新实现 __repr____str__ 方法,以便您的类实例在交互模式下评估时类似于列表?
  • 在不深入细节的情况下,类与函数不同,并且本身不返回值。

标签: python class return


【解决方案1】:

对我来说有效的提议是 __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 ₁₅ ₅₅ ₄₉ ₀

【讨论】:

    【解决方案2】:

    使用__new__ 从类返回值。

    正如其他人建议的那样,__repr____str__ 甚至 __init__(不知何故)可以为您提供您想要的,但 __new__ 将是一个语义上更好的解决方案,因为您希望返回实际对象而不仅仅是它的字符串表示。

    阅读此答案以获得对__str____repr__ 的更多见解 https://stackoverflow.com/a/19331543/4985585

    class MyClass():
        def __new__(cls):
            return list() #or anything you want
    
    >>> MyClass()
    []   #Returns a true list not a repr or string
    

    【讨论】:

    • 为什么它是一个更好的解决方案?
    • 因为您并不总是需要返回对象的字符串表示形式。在这种情况下,使用__str____repr__ 将是错误的。当然,您可以使用任何东西来返回任何东西,但 __str____repr__ 不是为此而设计的
    • 它会一直创建新的list() 对象吗?
    【解决方案3】:

    如果您想要一种将您的类变成某种列表的方法,而无需子类化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__

    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())
    

    【讨论】:

    • 那是我不想做的事情。我不想使用 mc1.getValue() == mc2.getValue()。我想比较没有 getValue 的 mc1 == mc2。但曾经说过假
    • 好的,这就是答案。谢谢!
    【解决方案4】:
    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']
    

    【讨论】:

      【解决方案5】:

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

      在 Python 中,一切都是对象:

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

      它们都是“值”,因为它们是事物而不是指代事物的名称。 (变量是引用值的名称。)值与 Python 中的对象没有什么不同。

      当您调用一个类对象(如MyClass()list())时,它会返回该类的一个实例。 (list 确实是一个类型而不是一个类,但我在这里简化了一点。)

      当您打印一个对象(即获取一个对象的字符串表示)时,会调用该对象的__str__ or __repr__ magic method 并打印返回值。

      例如:

      >>> 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
      

      如果你想改变这个,使用one of the comparison magic methods

      例如,你可以拥有一个等于一切的对象:

      >>> 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. 看看this guide to magic method use in 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])
        

      【讨论】:

      • 感谢您的回答(也感谢大家)。由于排名,我编辑了第一个问题。我添加了一个例子来说明它发生了什么。
      • 链接到rafekettler.com/magicmethods.html 指向一个过期/被劫持的域 :( 很遗憾看到这些天有这么多有大量文档的网站正在消失。
      • @n3storm 通过Github issue跟踪问题找到了魔法方法指南的另一个来源。
      • rafekettler.com 魔法方法指南仍存档在 Wayback Machine / Internet Archive here,也来自 GitHub
      【解决方案6】:

      你描述的是一个函数,而不是一个类。

      def Myclass():
          return []
      

      【讨论】:

      • 但如果我使用 def 我不能使用 setitemgetitem 等。
      • 你需要它们做什么?如果您使用列表,您也没有这些。
      • 对不起!我不明白你的问题,因为我的英语很差。如果我在这里问是否因为在西班牙语中没有好的和快速的论坛可以问。见第一个答案。我编辑了它
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多