Что делает объект Ellipsis?

540

В то время как я бездельничал в пространстве имен, я заметил странно выглядящий объект под названием Ellipsis, он, кажется, не делает или делает что-то особенное, но это глобально доступный встроенный объект.

После поиска я обнаружил, что он используется в каком-то непонятном варианте синтаксиса нарезки Нампи и Сципи ... но почти ничего больше.

Был ли этот объект добавлен в язык специально для поддержки Numpy + Scipy? Ellipsis имеет какое-либо общее значение или использование вообще?

D:\workspace\numpy>python
Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> Ellipsis
Ellipsis
Салим Фадли
источник
См. Ответы на stackoverflow.com/questions/752602/…
Патрик МакЭлхани
19
Я нашел это следующим образом: я вошел x=[];x.append(x);print(x), чтобы посмотреть, как он обрабатывает строковые циклические объекты. Вернулся [[...]]. Я подумал: «Интересно, что произойдет, если я [[...]][[Ellipsis]]
наберу текст
22
обратите внимание, что ...в рекурсивном repr это просто заполнитель и не имеет никакого отношения кEllipsis
Eevee
16
С другой стороны, тройная точка в импорте означает «импорт из двух пакетов вверх».
Безумный физик
1
@croq stackoverflow.com/q/32395926/2988730 . stackoverflow.com/q/1054271/2988730 . Эти двое должны объяснить все, с правильными ссылками на документы и PEP в ответах.
Безумный физик

Ответы:

559

Это возникло в другой вопрос недавно. Я уточню мой ответ оттуда:

Многоточие - это объект, который может появляться в обозначениях срезов. Например:

myList[1:2, ..., 0]

Его интерпретация является чисто до любого Реализует __getitem__функцию и видит Ellipsisобъекты, но его основное (и предназначено) использование в Numpy библиотеки третьей стороны, которая добавляет многомерный массив типа. Поскольку существует более одного измерения, нарезка становится более сложной, чем просто индекс начала и остановки; полезно также иметь возможность разрезать по нескольким измерениям. Например, с учетом массива 4x4 верхняя левая область будет определяться срезом [:2,:2]:

>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12],
       [13, 14, 15, 16]])

>>> a[:2,:2]  # top left
array([[1, 2],
       [5, 6]])

Расширяя это далее, Ellipsis используется здесь, чтобы указать местозаполнитель для остальных размеров массива, не указанных. Думайте об этом как об указании полного среза [:]для всех размеров в зазоре, который он поместил, поэтому для трехмерного массива a[...,0]то же самое, что a[:,:,0]и для 4d a[:,:,:,0], аналогично, a[0,...,0]есть a[0,:,:,0](хотя все колоны в середине составляют полное число размеров в массиве).

Интересно, что в python3 литерал Ellipsis ( ...) используется вне синтаксиса слайса, поэтому вы можете написать:

>>> ...
Ellipsis

Кроме различных числовых типов, нет, я не думаю, что это используется. Насколько я знаю, он был добавлен исключительно для простого использования и не имеет поддержки ядра, кроме предоставления объекта и соответствующего синтаксиса. Объект, находящийся там, не требовал этого, но буквальная «...» поддержка срезов сделала.

Брайан
источник
22
он также используется в подсказках типа PEP484 в файлах-заглушках
noɥʇʎԀʎzɐɹƆ
24
На всякий случай, если кому-то интересно: он также используется в typingмодуле стандартной библиотеки : например, Callable[..., int]для указания вызываемого объекта, который возвращает intбез указания сигнатуры, или Tuple[str, ...]для обозначения однородного набора строк переменной длины.
Анакханд
6
К вашему сведению, среда FastAPI (которая предназначена для Python 3.6+) также (сейчас) использует ее. fastapi.tiangolo.com/tutorial/query-params-str-validations
Эндрю Аллер
2
@ArtOfWarfare вы совершенно правы, и это исходит от того, кто устно говорит «многоточие», а не прерывается между предложениями.
PrimeRibeyeDeal
Я нашел это. Похоже, он появляется, когда вы создаете ссылку на себя (круговую ссылку) в списке: a = [1, 2]; a[0] = a; print(a)дает [[...], 2]. Это то же самое или другое использование?
Билл
220

В Python 3 вы можете использовать литерал Ellipsis ...в качестве заполнителя «nop» для кода:

def will_do_something():
    ...

Это не магия; любое выражение может быть использовано вместо ..., например:

def will_do_something():
    1

(Не могу использовать слово «санкционировано», но я могу сказать, что это использование не было прямо отвергнуто Гвидо.)

tzot
источник
181
В полу-соглашении я часто вижу, ...когда люди хотят указать что-то, что они намереваются заполнить позже (пустой блок «todo») и passчто означает блок, не имеющий кода.
Гарет Латти
26
Python также имеет NotImplementedлитерал, который полезен, когда вы хотите, чтобы ваша неполная функция возвращала что-то значимое (а не Noneкак в вашем примере). (Другой вариант использования: реализация арифметических операций )
Звин
13
@zvyn Это не буквально. Это просто имя. Например NotImplemented = 'something_else', допустим Python, но ... = 'something_else'это синтаксическая ошибка.
Вим
4
@zvyn Что, если при импорте этого модуля возникла исключительная ситуация? :)
pizzapants184
7
@zvyn NotImplementedне является альтернативой None. Его использование довольно узкое. См. Документацию здесь
Ханс
69

Начиная с Python 3.5 и PEP484 , буквенный многоточие используется для обозначения определенных типов при проверке статического типа при использовании модуля ввода .

Пример 1:

Однородные кортежи произвольной длины могут быть выражены с использованием, например, одного типа и многоточия Tuple[int, ...]

Пример 2:

Можно объявить возвращаемый тип вызываемого объекта без указания сигнатуры вызова, подставив буквенный многоточие (три точки) в список аргументов:

def partial(func: Callable[..., str], *args) -> Callable[..., str]:
    # Body
Феникс
источник
46

Вы также можете использовать многоточие при указании ожидаемого вывода doctest :

class MyClass(object):
    """Example of a doctest Ellipsis

    >>> thing = MyClass()
    >>> # Match <class '__main__.MyClass'> and <class '%(module).MyClass'>
    >>> type(thing)           # doctest:+ELLIPSIS
    <class '....MyClass'>
    """
    pass
Chiggs
источник
9
Но включает ли это на самом деле объект Ellipsis? Разве это не просто особенность анализатора / совпадения doctest?
akaihola
1
@akaihola Я бы сказал, что это так, как описано на doctest.ELLIPSIS . Я ожидаю, что большинство, если не все виды использования, ...являются синтаксическими, а не useфактическим объектом Ellipsis. Не правда ли, не более чем удобное название для адаптируемой концепции?
nealmcb
34

Из документации Python :

Этот объект обычно используется нарезкой (см. Slicings ). Он не поддерживает никаких специальных операций. Существует ровно один объект с многоточием, названный Ellipsis (встроенное имя). type(Ellipsis)()производит синглтон Ellipsis.

Это написано как Ellipsisили ....

Симон Лишке
источник
25

Подводя итог тому, что говорили другие, начиная с Python 3, Ellipsis, по сути, является еще одной одноэлементной константой, аналогичной None, но без конкретного предполагаемого использования. Существующее использование включает в себя:

  • В синтаксисе среза для представления полного среза в оставшихся измерениях
  • В подсказке типа указывается только часть типа ( Callable[..., int]или Tuple[str, ...])
  • В типе файлов-заглушек указать, что есть значение по умолчанию без указания его

Возможное использование может включать:

  • В качестве значения по умолчанию для мест, где Noneдопустимая опция
  • Как контент для функции, которую вы еще не реализовали
Мэтью Д. Шолфилд
источник
14

__getitem__минимальный ...пример в пользовательском классе

Когда магический синтаксис ...передается []в пользовательский класс, __getitem__()получает Ellipsisобъект класса.

Затем класс может делать все, что захочет, с этим объектом Singleton.

Пример:

class C(object):
    def __getitem__(self, k):
        return k

# Single argument is passed directly.
assert C()[0] == 0

# Multiple indices generate a tuple.
assert C()[0, 1] == (0, 1)

# Slice notation generates a slice object.
assert C()[1:2:3] == slice(1, 2, 3)

# Ellipsis notation generates the Ellipsis class object.
# Ellipsis is a singleton, so we can compare with `is`.
assert C()[...] is Ellipsis

# Everything mixed up.
assert C()[1, 2:3:4, ..., 6] == (1, slice(2,3,4), Ellipsis, 6)

Встроенный listкласс Python выбирает, чтобы дать ему семантику диапазона, и любое разумное использование этого также, конечно, должно.

Лично я бы просто избегал этого в своих API и вместо этого создал бы отдельный, более явный метод.

Протестировано в Python 3.5.2 и 2.7.12.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
источник
запустите это с аргументом -O, и ваш код всегда будет выполняться; D
moshevi
12

Вы можете использовать Ellipsis самостоятельно, в пользовательских ситуациях нарезки, как это делал numpy, но он не используется ни в одном встроенном классе.

Я не знаю, был ли он добавлен специально для использования в numpy, но я, конечно, не видел его где-либо еще.

Смотрите также: Как вы используете синтаксис нарезки многоточия в Python?

Сикора
источник
7

Как уже упоминалось @ noɥʇʎԀʎzɐɹƆ и @phoenix - вы действительно можете использовать его в файлах-заглушках. например

class Foo:
    bar: Any = ...
    def __init__(self, name: str=...) -> None: ...

Дополнительную информацию и примеры использования этого многоточия можно найти здесь https://www.python.org/dev/peps/pep-0484/#stub-files.

henryJack
источник
2

Его предполагаемое использование не должно быть только для этих сторонних модулей. Он не упоминается должным образом в документации по Python (или, может быть, я просто не смог этого найти), но многоточие ...фактически используется в CPython по крайней мере в одном месте.

Он используется для представления бесконечных структур данных в Python. Я наткнулся на это обозначение во время игры со списками.

Смотрите этот вопрос для получения дополнительной информации.

Aseem Bansal
источник
8
Разные вещи. Этот вопрос касается ellipsisвстроенного типа и Ellipsisобъекта. Представление бесконечных структур данных с помощью эллипсов предназначено исключительно для отображения, не имеющего ничего общего с ellipsisтипом или Ellipsisобъектом.
Chys
3
@chys На самом деле, это происходит незначительным образом - __repr__строки Python стремятся быть действительными выражениями Python - если бы это не было для многоточия, существующего в языке, как оно есть, представление не было бы допустимым выражением.
Гарет Латти
3
@ Lattyware Ну, это правда, оригинальный дизайн, так задумано. Он также намерен eval(repr(a))стремиться быть равным a. К сожалению, на практике это время от времени ложно, даже для встроенных типов. Попробуйте это: a=[]; a.append(a); eval(repr(a)). repr(a)является [[...]]недопустимым выражением в Python 2. (В Python 3 оно допустимо, но результатом eval является нечто иное, все еще противоречащее первоначальному замыслу.)
chys
1

Это эквивалентно.

l=[..., 1,2,3]
l=[Ellipsis, 1,2,3]

...константа, определенная внутри built-in constants.

эллипсис

Так же, как и многоточие буквально «...». Специальное значение используется в основном в сочетании с расширенным синтаксисом секционирования для пользовательских типов данных контейнера.

прости
источник