2015-04-25 2 views
11

Я хотел бы написать функцию в Python, которая принимает срез в качестве параметра. В идеале пользователь будет иметь возможность вызвать функцию следующим образом:Как написать функцию, которая берет срез?

foo(a:b:c) 

К сожалению, этот синтаксис не допускается Python - использование a:b:c допускается только в пределах [], не ().

поэтому я вижу три возможности для моей функции:

  1. Требовать пользователю использовать срез "конструктор" (где s_ действует как the version provided by numpy):

    foo(slice(a, b, c)) 
    foo(s_[a:b:c]) 
    
  2. Put логику моя функция в __getitem__:

    foo[a:b:c] 
    
  3. Откажитесь пытается взять кусочек и взять старт, стоп и шаг по отдельности:

    foo(a, b, c) 
    

Есть ли способ, чтобы получить оригинальный синтаксис для работы? Если нет, какой из синтаксисов обходных путей будет предпочтительнее? Или есть другой, лучший вариант?

+3

Я хотел бы использовать начало использования, остановки и шаг настройки по умолчанию значения –

+2

Как это основано прежде всего на мнении? Это вполне правильный вопрос. –

+0

Я вообще не вижу недостатков в использовании 'foo (a, b, c)', а не 'foo (a: b: c)'. – TigerhawkT3

ответ

10

Не удивите своих пользователей.

Если вы используете синтаксис разрезания в соответствии с тем, что разработчик ожидает от синтаксиса разреза, тот же самый разработчик будет ожидать операции с квадратными скобками, то есть метод __getitem__().

Если вместо этого возвращенный объект не является каким-то фрагментом исходного объекта, люди будут смущены, если придерживаетесь решения __getitem__(). Используйте вызов функции foo(a, b, c), не говорите об этом вообще, и необязательно назначайте значения по умолчанию, если это имеет смысл.

0

Использование [a:b:c] является, как вы заметили, синтаксисом. Интерпретатор сразу же поднимает syntax error на (a:b:c), прежде чем ваш код сможет что-то сделать со значениями. Вокруг этого синтаксиса нет способа переписать интерпретатор.

Это стоит иметь в виду, что переводчик переводит foo[a:b:c] в

foo.__getitem__(slice(a,b,c)) 

Сам slice объект не является очень сложным. Он имеет только 3 атрибута (start, step, stop) и метод indices. Это метод getitem, который имеет смысл этих значений.

np.s_ и другие функции/классы в np.lib.index_tricks являются хорошими примерами того, как __getitem__ и slice могут быть использованы для расширения (или упростить) индексацию.Например, они эквивалентны:

np.r_[3:4:10j] 
np.linspace(3,4,10) 

Как синтаксис foo(a,b,c), очень распространенный np.arange() использует его. Как и range и xrange. Поэтому вы и ваши пользователи должны быть хорошо знакомы с этим.

Поскольку все альтернативы дают вам три значения, они функционально эквивалентны (в скорости). Таким образом, выбор сводится к предпочтениям пользователей и знакомым.

В то время как ваша функция не может принимать a:b:c обозначения непосредственно, она может быть написана для обработки различных материалов - срез, 3 позиционных аргументов, кортежа, кортеж из ломтиков (как из s_) или именованных аргументов. И после базового индекса numpy вы можете различать кортежи и списки.

2

Ломтики имеют больше смысла, когда они выражаются как часть чего-то. Итак, другая альтернатива - быть более объектно-ориентированной: создать временный объект, представляющий ваш фрагмент чего-либо, и поместить вашу функцию в качестве метода.

Например, если ваша функция действительно:

foo(bar, a:b:c) 

или

bar.foo(a:b:c) 

, то вы можете заменить это:

bar[a:b:c].foo() 

Если bar[a:b:c] уже имеет другое значение, затем придумайте другое имя baz и выполните:

bar.baz[a:b:c].foo() 

Трудно дать убедительные примеры без реального контекста, потому что вы пытаетесь назвать связанные вещи с именами, которые делают интуитивный смысл, позволяют писать однозначный код, и относительно короткие.

Если вы действительно просто написать функцию на своей собственной операционной на срезе, то либо:

  1. Ваша функция изменяет кусочек, возвращая другой срез:

    bar[foo(a:b:c)] 
    

    Если это так, независимо от того, какой правильный синтаксис вы выберете, будет немного запутанным. Вероятно, вы не хотите использовать срезы, если вы нацелены на широкую аудиторию программистов Python.

  2. Ваша функция действительно работает на ломтик целых, так что вы можете сделать это явно с временным объектом:

    the_integers[a:b:c].foo() 
    
Смежные вопросы