Передача синтаксиса среза Python вокруг функций
В Python можно ли инкапсулировать точно синтаксис общего среза и передать его? Я знаю, что я могу использовать slice
или __slice__
для эмуляции среза. Но я хочу передать тот же синтаксис, что и в квадратных скобках, которые будут использоваться с __getitem__
.
Например, предположим, что я написал функцию для возврата некоторого фрагмента списка.
def get_important_values(some_list, some_condition, slice):
elems = filter(some_condition, some_list)
return elems[slice]
Это отлично работает, если я вручную передаю объект среза:
In [233]: get_important_values([1,2,3,4], lambda x: (x%2) == 0, slice(0, None))
Out[233]: [2, 4]
Но то, что я хочу передать пользователю, - это точно такая же нарезка, которую они использовали бы с помощью __getitem__
:
get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:-1) )
# or
get_important_values([1,2,3,4], lambda x: (x%2) == 0, (0:) )
Очевидно, это создает синтаксическую ошибку. Но есть ли способ сделать эту работу без написания собственного мини-парсера для срезов типа x:y:t
и принуждения пользователя передать их в виде строк?
Мотивация
Я мог бы просто сделать этот пример функцией, возвращающей что-то прямое, например, filter(some_condition, some_list)
, которое будет весь результат в виде списка. Однако в моем фактическом примере внутренняя функция намного сложнее, и если я знаю фрагмент, который пользователь хочет раньше времени, я могу значительно упростить вычисление. Но я хочу, чтобы пользователь не должен был делать много лишнего, чтобы рассказать мне фрагмент раньше времени.
Ответы
Ответ 1
Возможно, что-то по следующим строкам будет работать для вас:
class SliceMaker(object):
def __getitem__(self, item):
return item
make_slice = SliceMaker()
print make_slice[3]
print make_slice[0:]
print make_slice[:-1]
print make_slice[1:10:2,...]
Идея заключается в том, что вместо slice
вы используете make_slice[]
для создания экземпляров slice
. Сделав это, вы сможете использовать знакомый синтаксис квадратных скобок во всей красе.
Ответ 2
Короче говоря, нет. Этот синтаксис действителен только в контексте оператора []
. Я мог бы предложить принять кортеж в качестве входных данных, а затем передать этот кортеж в slice()
. В качестве альтернативы, возможно, вы можете перепроектировать все, что вы делаете, чтобы get_important_values()
каким-то образом реализована как срезаемый объект.
Например, вы можете сделать что-то вроде:
class ImportantValueGetter(object):
def __init__(self, some_list, some_condition):
self.some_list = some_list
self.some_condition = some_condition
def __getitem__(self, key):
# Here key could be an int or a slice; you can do some type checking if necessary
return filter(self.some_condition, self.some_list)[key]
Возможно, вы, возможно, лучше сделаете это, превратив это в контейнерную ABC, но что общая идея.
Ответ 3
Один способ (для простых фрагментов) состоял бы в том, чтобы аргумент среза был либо dict, либо int,
т
get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, {0: -1})
или
get_important_values([1, 2, 3, 4], lambda x: (x%2) == 0, 1)
тогда синтаксис будет оставаться более или менее одинаковым.
Это не сработает, потому что, когда вы хотите делать что-то вроде
some_list[0:6:10..]