Из-за отсутствия лучших слов я пошел с этим названием.
Я хочу иметь возможность сделать что-то вроде этого:
>>> from random import randint
>>> fruits = [
... "Orange",
... "Banana",
... f"{randint(2,5)} Cherries",
... ]
>>> fruits[2]
'3 Cherries'
>>> fruits[2]
'5 Cherries'
>>> fruits[2]
'2 Cherries'
Но вместо этого буквенное выражение внутри строки вычисляется один раз при создании списка и дает один и тот же результат каждый раз, когда я к нему обращаюсь.
Мне было интересно, есть ли более простой/умный способ приблизиться к этому, чем написание какой-то сложной обработки крайних случаев (в конце концов, мы программисты; кому не нравится писать хороший код и быть элегантным и причудливым?). Я говорю об обработке краевого случая, потому что только 6 из моих 49 строк требуют такого "особого" поведения.
Пока я пытался сделать лямбда-функцию из вызова randint, но это не помогло; тот же результат. Может быть, это случай для ленивой оценки, но мне нужно небольшое руководство о том, как (или нужно ли?) Использовать его со списком.
Если вы хотите, чтобы некоторые из ваших элементов были буквальными, а некоторые вызывались, вы можете создать свою собственную версию list
:
from random import randint
class LazyList(list):
'Like a list, but invokes callables'
def __getitem__(self, key):
item = super().__getitem__(key)
if callable(item):
item = item()
return item
fruits = LazyList([
"Orange",
"Banana",
lambda: f"{randint(2,5)} Cherries",
])
print(fruits[2])
print(fruits[2])
Вы на правильном пути, желая лямбда:
from random import randint
fruits = [
lambda: "Orange",
lambda: "Banana",
lambda: f"{randint(2, 5)} Cherries",
]
print(fruits[2]())
print(fruits[2]())
print(fruits[2]())
Есть способы исключить ()
но это, вероятно, не стоит.
Отказ от ответственности: я автор библиотеки
Вы можете использовать seqtools для ленивого отображения, оно поддерживает итерации и нарезки:
>>> fruits = seqtools.smap(lambda x: x if isinstance(x, str) else x(),
... fruits)
>>> fruits[0]
'Orange'
>>> fruits[-1]
'3 Cherries'
Если вы не хотите переоценивать элементы функции при каждом вызове, вы можете добавить кеш:
fruits = seqtools.add_cache(fruits)
Назначение предметов не работает через сопоставления, очевидно, поэтому вам придется обдумать это.
Сортировка в конечном итоге оценит все элементы в списке, поэтому вы можете сделать это заранее и вызвать обычный метод list.sort().
Помещение лямбды в список поначалу звучит неплохо, но затем вы должны вызвать этот специальный (или все) индексы вашего списка. Вы не можете перебрать список, вы не можете отсортировать список,...
Имхо проще создать функцию, которая предоставляет вам списки:
from random import randint
def gimme_fruits ():
return [ "Orange", "Banana", f"{randint(2,5)} Cherries",]
print(gimme_fruits())
Выход:
['Orange', 'Banana', '3 Cherries']
['Orange', 'Banana', '4 Cherries']
['Orange', 'Banana', '2 Cherries']
Каждый список "фиксирован" по количеству вишен - но вы можете сделать это:
for f in gimme_fruits() + gimme_fruits() + gimme_fruits():
print(f)
Чтобы получить ваши витамины:
Orange
Banana
3 Cherries
Orange
Banana
3 Cherries
Orange
Banana
3 Cherries
__getitem__
per se? как насчет сортировки?