Python 从内置对象继承时如何分配给基类对象?
我正在尝试扩展Python内置的list对象以包含元数据。在某些情况下,为了提高效率,我希望能够通过引用来分配基类对象 例如:Python 从内置对象继承时如何分配给基类对象?,python,inheritance,built-in,Python,Inheritance,Built In,我正在尝试扩展Python内置的list对象以包含元数据。在某些情况下,为了提高效率,我希望能够通过引用来分配基类对象 例如: class meta(list): def __init__(self, data=None, metadata=None): if data is not None: super().__init__(data) # performs a copy of data else: su
class meta(list):
def __init__(self, data=None, metadata=None):
if data is not None:
super().__init__(data) # performs a copy of data
else:
super().__init__()
self.metadata = metadata
def foo(self):
new_data = [ i for i in range(10) ]
return meta(new_data, "my meta data")
这正如预期的那样有效。调用foo
返回一个新的meta
对象,其中的值为0-9。但是,由于对基类初始值设定项的调用,在列表理解中创建并分配给new_data
的列表会复制到meta的初始值设定项中。此附加副本是不必要的,因为它可以简单地将新_数据的引用分配给继承的列表对象,因为在退出foo
后,不可能存在对它的其他引用
我想描述的是这样的:
class meta(list):
def __init__(self, data=None, metadata=None):
if data is not None:
super().__init__(data) # performs a copy of data
else:
super().__init__()
self.metadata = metadata
def foo(self):
result = meta(None, "my meta data") # an efficient initialization
new_data = [ i for i in range(10) ]
super(list, result) = new_data # just assign the reference instead of copying
return result
但我知道这在语法上是不正确的。然而,它确实描述了我试图实现的目标。其目的是,新的meta
对象通过将引用分配给基础列表对象来引用new_data
列表对象
我知道我可以使用列表成员对象而不是从列表继承,但这会导致其他效率低下,因为现在所有的列表属性都必须在meta
类中定义,并且会被包装在另一层函数调用中
所以…我的问题是:
- 有没有办法做到这一点
- 我可以作为子类中的独立对象访问底层对象吗
- 它可以干净地实现而不产生比我试图消除的更多的开销吗
- 是否有一些晦涩难懂的
方法不是该语言的一个未记录的“特性”\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
list
的实例。也就是说,meta
的新实例不包含对另一个list
实例的引用;它是list实例,只是带有一个\uuuu class\uuuu
属性,该属性指向meta
,而不是list
如果不想复制参数,首先不要制作列表参数
class meta(list):
def __init__(self, data=None, metadata=None):
if data is not None:
super().__init__(data) # performs a copy of data
else:
super().__init__()
self.metadata = metadata
def foo(self):
new_data = range(10)
return meta(new_data, "my meta data")
list.\uuuu init\uuuuuu
不是一个execking列表;它只需要一个iterable,对其元素的引用可以添加到刚构建的列表中
您可能无论如何都要覆盖\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,因为列表中已经包含了决定是否有一个可传递给<
class meta(list):
def __new__(cls, *args, metadata=None, **kwargs):
new_list = super().__new__(cls, *args, **kwargs)
new_list.metadata = metadata
return new_list
def foo(self):
return meta(range(10), metadata="my meta data")
(最后,foo
应该是一个静态方法或类方法,因为它没有使用调用它的meta
实例。)尽管@chepner没有直接回答我的问题,但我得到了他们的一些鼓励,并提出了以下解决方案
class meta_add_iterable:
def __init__(self, *data):
self.data = data # copies only the references to the tuple of arguments passed in
self.current = -1
def __iter__(self):
return self
def __next__(self):
self.current += 1
if self.current < len(self.data[0]):
return sum([ i[self.current] for i in self.data ])
raise StopIteration
class meta(list):
def __init__(self, data, metadata):
super().__init__(data)
self.metadata = metadata
def __add__(self, other):
return meta(meta_add_iterable(self, other), self.metadata)
a = meta([1, 2, 3, 4, 5], "meta data")
b = meta([6, 7, 8, 9, 0], "more data")
a + b
[7, 9, 11, 13, 5]
考虑有两个meta
对象,我们希望逐个元素将底层list
对象添加到一起
最直截了当的答案与我原来的帖子相似。我将把错误检查留给读者来实现
class meta(list):
def __init__(self, data, metadata):
super().__init__(data)
self.metadata = metadata
def __add__(self, other):
return meta([self[i] + other[i] for i in range(len(self))], self.__metadata)
a = meta([1, 2, 3, 4, 5], "meta data")
b = meta([6, 7, 8, 9, 0], "more data")
a + b
[7, 9, 11, 13, 5]
注意:元数据只是用来完成示例的,我知道我遗漏了确保b列表不短于a列表的检查。然而,该行动如期进行。也很容易看到列表理解创建的列表
稍后在调用list时被完全复制到meta.\uuuu init\uuuu
中。\uuu init\uuuuu
通过super()。\uuu init\uuuuuu(…)
调用。这第二份是我想要避免的
多亏@chepner识别了列表。_init__
使用iterable,我想出了以下解决方案
class meta_add_iterable:
def __init__(self, *data):
self.data = data # copies only the references to the tuple of arguments passed in
self.current = -1
def __iter__(self):
return self
def __next__(self):
self.current += 1
if self.current < len(self.data[0]):
return sum([ i[self.current] for i in self.data ])
raise StopIteration
class meta(list):
def __init__(self, data, metadata):
super().__init__(data)
self.metadata = metadata
def __add__(self, other):
return meta(meta_add_iterable(self, other), self.metadata)
a = meta([1, 2, 3, 4, 5], "meta data")
b = meta([6, 7, 8, 9, 0], "more data")
a + b
[7, 9, 11, 13, 5]
class meta\u add\u iterable:
定义初始化(自,*数据):
self.data=data#只复制对传入参数元组的引用
自身电流=-1
定义(自我):
回归自我
定义下一个(自我):
自身电流+=1
如果自电流
在上述实现中,在meta.\uuuu add\uuu
方法中没有通过列表理解创建的临时列表。相反,我们只需将两个meta
对象(self
和other
)传递给迭代器对象。这里唯一要做的复制是将引用复制到原始元对象,以便迭代器可以引用它们。然后对meta.\uuuu init\uuuu
的调用传递迭代器,而不是已经创建的列表。list.\uuuuu init\uuuuu
方法只是从该迭代器创建列表,这意味着每个引用的元对象仅被访问一次以检索其数据,并且结果仅在列表中写入一次。此实现中完全省略了次副本,因为添加操作实际上被推迟到在列表中调用迭代器\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
class meta(list):
def __new__(cls, *args, metadata=None, **kwargs):
new_list = super().__new__(cls, *args, **kwargs)
new_list.metadata = metadata
return new_list
def foo(self):
return meta(range(10), metadata="my meta data")
最好的部分是,我们不需要检查是否从列表对象或迭代器初始化
我知道现在有很多事情会出错。我省略了所有的错误检查,因此读者可以看到这个过程
我不确定使用@chepner建议的\uuuu new\uuuu
方法实现它是否会更好。就我个人而言,我看不出有什么好处。也许@chepner