【问题标题】:How to set base class per instance of derived class?如何为派生类的每个实例设置基类?
【发布时间】:2021-10-08 03:28:55
【问题描述】:

我遇到过很多次问题,解决方案通常是循环列表。例如:

my_list = CircularList([1,2,3,4])
my_list[0] # 1
my_list[4] # 1

为了实现这样的结构,我这样做了:

class CircularList(list):
    def __getitem__(self, index: int):
        return list.__getitem__(self, index % len(self))

在实现该类之后,我想创建一个可以“Circularize”实现__getitem____len___ 的任何可迭代对象的单个类,同时仍保留该对象的所有属性和方法. 比如:

circ_iter = Circular(MyIter(1,2,3,4))   # Object keeps MyIters's attributes
circ_tuple = Ciruclar((1,2,3,4))  # Still has attributes of a tuple

我遇到的问题是我找不到根据参数类型为每个实例动态设置基类的方法。

我该怎么做呢?

【问题讨论】:

  • 纯粹出于好奇——与collections.deque 相比,什么用例需要这个?
  • @TeejayBruno 我正在寻找支持这种代码的东西:deq = deque([1,2,3,4])print(deq[4])`deque 在这种情况下会引发错误。

标签: python python-3.x list inheritance iterable


【解决方案1】:

您可以通过混合类使用多重继承来做到这一点,但您必须确保两件事:

  1. 在基类列表中之前Circularize 没有出现其他覆盖__getitem__ 的类
  2. 您自己的类不会覆盖__getitem__

(从技术上讲,您不能以阻止Circularize.__getitem__ 按预期工作的方式覆盖__getitem__。但这涉及到继承如何与可组合性冲突的问题,并且实际上不在此答案的范围内.)

class Circularize:
    def __getitem__(self, index):
        return super().__getitem__(index % len(self))


_circular_types = {}
def Circular(v: collections.abc.Sequence):
    t = type(v)
    tname = t.__name__
    if tname not in _circular_types:
        _circular_types[tname] = type(f'Circular{tname.upper()}', (Circularize, t), {})

    return _circular_types[tname](v)
    

circ_list = Circular([1,2,3])  # Creates an instance of CircularList
circ_tuple = Circular((1,2,3))  # Creates an instance of CircularTuple

我省略了CircularSet,因为集合本身不可索引(即set 不是Sequence 的子类)。如果您想重复迭代集合中的元素,请使用 itertools.cycle({1,2,3})(产生 1、2、3、1、2、3、1、2、...)。

【讨论】:

  • 但这并不能真正解决问题。 OP 的目的是拥有一个“通用”Circular 类,可用于制作任何类型的“圆形”可迭代对象,例如list, tuple, set.
  • 但是如果我导入一个添加了十个新的可迭代对象的库怎么办。我正在寻找一种解决方案,即使只有两行,我也不必为每个类声明一个新类。
  • 是的,我正在努力修复它,但我不确定这是一个好方法。 (我可以使用Circularize 根据传递给Circular 的参数类型动态创建一个新类,并保留一个缓存,这样我就不会一遍又一遍地重新创建同一个类。)跨度>
  • 已更新;它至少更接近您最初的要求。
  • @flakes 我没有不喜欢你的回答;在可能的情况下,组合绝对比继承更可取。你对__getattribute__ 的定义让我感到困扰,但我永远无法完全确定是什么。 (我没有机会对其进行太多测试。)我认为可以修复它以使该方法正常工作。 (我认为让新值仍然被视为原始类型的实例很重要,但使用 abc.register 之类的东西相对容易修复。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
  • 2011-02-20
  • 2014-04-27
  • 2013-02-12
  • 2023-03-19
  • 1970-01-01
  • 2013-10-15
相关资源
最近更新 更多