我正在構建一個以ints串列為基礎的類,__getitem__然后它的方法是一個計算合理的函式,輸出一個可能很大的串列。這是代碼:
Class A(list):
def __init__(self, n):
self.li = [i for i in range(0, n)]
super().__init__(self.li)
self._ind = 0
def __getitem__(self, item):
assert (type(item) is int and item >= 0) or type(item) is slice
if type(item) is slice:
start, stop, step = item.start, item.stop, item.step
if stop is None:
stop = len(self)
if step is not None:
for i in range(start, stop, step):
yield self[i]
else:
for i in range(start, stop):
yield self[i]
if item == 0 or item == 1:
return []
out = []
while item != 1:
if super().__getitem__(item):
p = super().__getitem__(item)
else:
out.append(item)
return out
if p not in out:
out.append(p)
item //= p
return out
我的代碼目前無法正常作業,因為它總是回傳一個生成器,這會擾亂對類實體的迭代。但是在切片時,我不希望它完成所有計算并存盤它,因為這會使其消耗更多記憶體。我想做的一個例子:
from math import prod
test = A(10**7)
out = 0
for i in test[10**6:10**7]:
out = prod(i)
如何使切片有效地作業?
uj5u.com熱心網友回復:
與其回傳生成器,不如回傳一個視圖。這是一個概念上表示相關元素序列的物件。我們可以通過存盤對原始 A 實體的參考以及對實體進行編碼的范圍來做到這一點。當我們對視圖進行索引時,我們可以詢問涉及哪些原始索引(或多個索引)的范圍。
假設我們建立了一般結構:
class A(list):
def __init__(self, n):
super().__init__(self.li)
self[:] = [i for i in range(0, n)]
def _at(self, idx):
# custom logic here to return the correct value for self[idx]
def __getitem__(self, idx):
if isinstance(idx, int):
return self._at(idx)
elif isinstance(idx, slice):
# The `indices` method of a slice object converts to
# start, stop, step values which we can use to construct a range.
return A_view(self, range(*idx.indices(len(self))))
else:
raise TypeError # this is not an appropriate use for `assert`
那么我們的視圖可能如下所示:
class A_view:
def __init__(self, original, indices):
self._original, self._indices = original, indices
def __getitem__(self, idx):
if isinstance(idx, int):
return self._original[self._indices[idx]]
elif isinstance(idx, slice):
return A_view(self._original, self._indices[idx])
else:
raise TypeError
def __len__(self):
return len(self._indices)
這個想法是,如果我們收到一個整數索引,我們通過range物件將它轉換為原始的索引A,并回呼它__getitem__(這次是一個整數)。如果我們收到另一個slice,我們使用它將我們的范圍分割成一個子范圍,并制作另一個視圖。
請注意,您的 A 類應該已經是可迭代的,因為繼承自list. 要使視圖可迭代(并免費獲得in運算子、正向和反向迭代.index以及.count方法),您可以從collections.abc.Sequence. 你只需要一個__getitem__和__len__- 兩者都易于實作,如上所述 - 基類將完成其余的作業(同時也向isinstance你的類宣傳這些屬性)。
uj5u.com熱心網友回復:
我不完全確定你在問什么。這對您的用例有用嗎?專案將延遲生成而不存盤(除非呼叫者存盤它們)。
class LazyCollection:
def __getitem__(self, key):
if isinstance(key, int):
return self.get_single_item(key)
elif isinstance(key, slice):
def my_generator():
for index in slice_to_range(key):
yield self.get_single_item(index)
return my_generator()
def get_single_item(self, index):
# (Example! Your logic here.)
return index * 10
def slice_to_range(my_slice):
'''
More options for implementing this:
https://stackoverflow.com/questions/13855288/turn-slice-into-range
'''
start = my_slice.start if my_slice.start is not None else 0
stop = my_slice.stop
step = my_slice.step if my_slice.step is not None else 1
return range(start, stop, step)
coll = LazyCollection()
# Get a single item
print(coll[9999])
# Get a slice
for x in coll[2:10]:
print(x)
輸出:
99990
20
30
40
50
60
70
80
90
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/420042.html
標籤:
