简体   繁体   English

使用相同类型的所有元素对 Python 列表进行子类化

[英]Subclass Python list with all elements of the same type

I'm looking for a way to make a subclass of list where all elements are of the same type.我正在寻找一种方法来创建list的子类,其中所有元素的类型都相同。 I don't need a fully generic implementation, as described in this answer .我不需要完全通用的实现, 如本答案中所述

What I'd like is something roughly equivalent to the following code (using typing ):我想要的是大致相当于以下代码的东西(使用typing ):

class NumberParty(list[int]):
    def __str__(self) -> str:
        "🎉".join([str(x) for x in self])

    def total(self) -> int:
        return sum(self)

The reason I want this class instead of using List[int] annotations is that I use the __str__ method described above in multiple places and want to eliminate the copied lines of code.我想要这个类而不是使用List[int]注释的原因是我在多个地方使用了__str__描述的__str__方法并希望消除复制的代码行。


As a bonus question, would it be wise to overload __init__ in something similar to the following code?作为一个额外的问题,在类似于以下代码的内容中重载__init__是否明智?

__init__(self, *numbers: int):
    self = numbers
__init__(self, nums: Iterable[int]):
    self = list(nums)

The first way would be for directly creating a new NumberParty instance while the second would create one from an existing list or set of integers.第一种方法是直接创建一个新的NumberParty实例,而第二种方法是从现有列表或整数集创建一个。

Unless I'm misunderstanding your question, just doing:除非我误解了您的问题,否则只需执行以下操作:

from typing import List

class NumberParty(List[int]):
    def __str__(self) -> str:
        return "🎉".join([str(x) for x in self])

    def total(self) -> int:
        return sum(self)

...should just work. ...应该只是工作。

Note that inheriting from List[int] is essentially the same as inheriting from list -- the only difference is that type checkers will understand what your custom class is supposed to contain and verify you're using methods like append(...) in a type safe way.请注意,从List[int]继承本质上与从list继承相同 - 唯一的区别是类型检查器将了解您的自定义类应该包含的内容并验证您正在使用append(...)的方法一种类型安全的方式。

However, there is no difference at runtime, and you can still freely ignore your type checker and append strs or whatever, just like how you Python lets you append strs to regular lists that are annotated to be of type List[int].但是,在运行时没有区别,您仍然可以自由地忽略类型检查器并附加 strs 或其他任何内容,就像 Python 允许您将 strs 附加到注释为 List[int] 类型的常规列表一样。

And since this class is a subtype of List[int], code snippets like the below should type check:由于这个类是 List[int] 的子类型,像下面这样的代码片段应该进行类型检查:

def expect_list(x: List[int]) -> None: pass

def expect_number_party(x: NumberParty) -> None: pass

n = NumberParty()

# Both type checks
expect_list(n)
expect_number_party(n)

Regarding your question about overriding __init__ -- you'll need to call the super constructor if you decide to take that route to ensure the class is set up properly.关于覆盖__init__的问题 - 如果您决定采用该路线以确保正确设置类,则需要调用超级构造函数。

Idea主意

I don't know.我不知道。 If I understood what you asked or not如果我理解你的要求

What I got from your question is: You want an Array As Marcos said in comments.我从你的问题中得到的是:你想要一个数组,正如马科斯在评论中所说。

And also adding a whole NumPy library to your dependencies for just an array is overkill.并且将整个 NumPy 库添加到您的依赖项中只是一个数组是矫枉过正的。

What you need is to make a list-like object which uses a list for storing things and and a public API and several 'magic functions' for making it work like a list (with the filters you want).您需要的是制作一个类似列表的对象,它使用一个列表来存储事物,以及一个公共 API 和几个“魔术函数”,使其像列表一样工作(带有您想要的过滤器)。

Code代码

from typing import Iterable, optional


class NumberParty:
    def __init__(self, iterable: optional[Iterable] = ()):
        self._inner = [].extend(iterable)


    def __getitem__(self, item):
        return self._inner[item]


    def __setitem__(self, key, value):
        if not isinstance(value, int):
            raise ValueError("NumberParty only accepts integers")
        self._inner[key] = value


    def __len__(self):
        return len(self._inner)


    def __iter__(self):
        return iter(self._inner)


    def append(self, i: int) -> None:
        if not isinstance(i, int):
            raise ValueError("NumberParty only accepts integers")
        self._inner.append(i)


    def insert(self, index: int, i: int) -> None:
        if not isinstance(i, int):
            raise ValueError("NumberParty only accepts integers")

        self.inner[index] = i


    def extend(self, __iterable: Iterable[int]) -> None:
        # Itering through it to check every value
        for i in __iterable:
            if not isinstance(i, int):
                raise ValueError("NumberParty only accepts integers")
            self.append(i)

Please be careful that this NumberParty is not complete Operations like: + - / % * += -= /= %= *= are not implemented but are implemented in original list (plus several public functions which are not implemented here)请注意此NumberParty不完整 操作如: + - / % * += -= /= %= *=未实现,但在原始列表中实现(加上一些未在此处实现的公共功能)

Tip for completing this NumberParty object完成此NumberParty对象的提示

This Class can be a wrapper around the list object.这个类可以是list对象的包装器。 Waiting for you to complete it ;)等你完成;)

In case you just want type-checkers to show a warning Michael0x2a answer works.如果您只希望类型检查器显示警告Michael0x2a 答案有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM