【问题标题】:How do I make a custom class a collection in Python如何在 Python 中将自定义类设为集合
【发布时间】:2015-10-10 07:26:06
【问题描述】:

我来自 Matlab 背景。在 matlab 中,我可以创建一个类定义,然后创建一个对象数组。我可以轻松地使用索引取消引用每个对象。此外,当我从对象数组(没有索引)调用方法时,我可以访问数组中的所有对象。例如,假设 myNewClass 具有属性 .data 和 .text,它还具有方法 .clob。我可以:

% init
a(1) = myNewClass;
a(2) = myNewClass;

a(1).data = [0;0;0];
a(2).data = [1;1;1];

所以现在,如果我调用 a.clob(不是 a(1).clob 或 a(2).clob),我可以执行类似的操作

% this is a function inside the methods definition of my class definition
function clob(self)
   % self here is my object array, "a", from above
   for i=1:length(self)
       % deref a single object
       self(i).goClobYourself;
   end
end

我如何在 Python 中做这样的事情?请注意,我希望我的课程是一个索引集合,有点像一个列表。但是,我不希望我的“班级列表”接受任何班级,只接受 myNewClass。如果我从“列表”继承,我的类是否只是一个具有属性 .data、.text 和函数 .clob 的“列表”类?另请注意,我不想要包含我的对象的“列表”,我希望我的对象是列表,以便我可以从索引中取消它们:a[1].clob() 或 a(1).clob( ) (?? 或类似的东西)。或者,我想将整个数组传递给 self:a.clob() 让我可以访问列表。我的术语可能有点模糊。

最好的问候

【问题讨论】:

  • “但是,我不希望我的“班级列表”接受任何班级,只接受 myNewClass。”简单的答案是“不要这样做”。实际上从来没有充分的理由这样做。它在 MATLAB 中可能很常见,但在 Python 中却很不受欢迎。

标签: python arrays matlab list class


【解决方案1】:

在使用 Python 编程时,执行类型检查并不常见。你确定你需要你的列表只接受一种类型(及其子类型),还是你会相信程序员会阅读你的文档而不是把不应该存在的东西放进去?

如果是这样,这是一个继承自 collections.MutableSequence 的示例泛型类,它可能会做你想做的事:

from collections import MutableSequence
class VerifierList(MutableSequence):
    _list = None
    def __init__(self, allowedClasses, *args, **kwargs):
        super(VerifierList, self).__init__()
        self._list = list(*args, **kwargs)
        self.allowedClasses = tuple(allowedClasses)
    def __repr__(self):
        return repr(self._list)
    def __str__(self):
        return str(self._list)
    def __len__(self):
        return len(self._list)
    def __getitem__(self, index):
        return self._list[index]
    def __setitem__(self, index, value):
        if not isinstance(value, self.allowedClasses):
            raise TypeError('Value of type %s not allowed!' % value.__class__.__name__)
        self._list[index] = value
    def __delitem__(self, index):
        del self._list[index]
    def insert(self, index, value):
        if not isinstance(value, self.allowedClasses):
            raise TypeError('Value of type %s not allowed!' % value.__class__.__name__)
        self._list.insert(index, value)

如下使用:

>>> class A(object): pass

>>> class B(object): pass

>>> l = VerifierList((A,))
>>> l.append(A())
>>> print(l)
>>> [<__main__.A object at 0x000000000311F278>]
>>> l.append(B())

Traceback (most recent call last):
  File "<pyshell#228>", line 1, in <module>
    l.append(B())
  File "C:\Python27\lib\_abcoll.py", line 661, in append
    self.insert(len(self), value)
  File "<pyshell#204>", line 23, in insert
    raise TypeError('Value of type %s not allowed!' % value.__class__.__name__)
TypeError: Value of type B not allowed!

【讨论】:

  • 感谢您提供的信息。我试图理解这一点。对于集合部分,对象存储在 _list 中并从对象引用(名称)提供/管理,“[”和“]”只是被此定义覆盖的运算符,对吗?没什么私人的(对你来说),但我不喜欢 VerifierList((A,)),主要是因为我不自然地理解它——除了类类型加载到 .allowedClass 中的方式;但我不喜欢它。我可以删除验证部分,并有一个常规的“可列出”类,对吗?最好的问候
  • 如果你想要一个常规的“可列表”类,只需使用内置的list。这只是添加类型“安全”,我认为这是你想要的。
  • 感谢 cmets。你是对的,但我决定我不喜欢它在语言中的机械化方式。我会接受你的建议并从“列表”继承我的班级定义是class myTest(list): def __init__(self): list.__init__(self) self.data = None self.test = None 但我不明白结果。当a=myTest a.data=[1,2,3,4] a.text = 'hello bob'。我假设这是元素 a[0]。但是当我a.append(myTest()) 时,那个元素实际上是 a[0]。此外,我的调试器没有显示任何属性。提前致以最诚挚的问候和感谢。
  • 你为什么不喜欢它在语言中的机械化方式?您需要额外的功能吗?是什么让内置列表如此不受欢迎?更改语言的一个非常基本的部分几乎总是错误的做事方式,而且您只会激怒其他必须查看您的代码的人。
【解决方案2】:

Python 中的所有此类功能都使用“语言参考”第 3.3 节中所述的“特殊方法名称”。第 3.3.6 节描述了如何模拟容器类型,这通常是您在这里所要求的。您需要定义和实现方法__getitem____setitem____delitem__,也许还需要__iter____reversed____contains__。 Python 在这方面做得很好,而且方法非常灵活。

【讨论】:

    猜你喜欢
    • 2016-07-05
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    相关资源
    最近更新 更多