如何在Python中将自定义类变成一个集合

3

我来自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。如果我继承“list”,那么我的类会成为一个带有属性.data、.text和函数.clob的“list”类吗?还要注意,我不想要包含我的对象的“list”,我希望我的对象是一个列表,这样我可以从索引中解除引用:a[1].clob()或a(1).clob()(??或类似的内容)。或者,我想将整个数组传递给self:a.clob()使我可以访问列表。我可能对术语有点混淆。
此致敬礼

但是,我不想让我的“class-list”接受任何类,只想接受myNewClass。简单的答案是“不要这样做”。实际上几乎没有好的理由这样做。虽然在MATLAB中这种做法很常见,但在Python中强烈反对。 - TheBlackCat
2个回答

3

在使用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中的方式之外;但我不喜欢它。我可以删除验证部分,并拥有一个常规的“可列出”类,是吗?最好的问候 - userJohn
如果您想要一个常规的“可列出”类,只需使用内置的 list。这只是添加了类型“安全性”,我认为这就是您想要的。 - Alyssa Haroldsen
感谢您的评论。您是正确的,但我决定不喜欢语言中的机械化方式。我采用了您的建议并从“list”继承了我的类定义: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]。此外,我的调试器没有显示任何属性。提前致以最好的问候和感谢。 - userJohn
1
为什么你不喜欢语言中的机械化?你需要一个额外的功能吗?是什么使内置列表如此不受欢迎?改变语言的一个相当基本的部分几乎总是做事情的错误方式,而且你只会惹恼其他人需要查看你的代码。 - Alyssa Haroldsen

1
所有这些在Python中的功能都使用“特殊方法名称”,如语言参考第3.3节所述。第3.3.6节描述了如何模拟容器类型,通常就是您在此处要求的内容。您需要定义和实现方法__getitem____setitem____delitem__,也许还包括__iter____reversed____contains__。Python非常适合此类操作,方法非常灵活。

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