O que o objeto Reticências faz?

539

Enquanto navegava ociosamente no namespace, notei um objeto de aparência estranha chamado Ellipsis, ele não parece ser ou faz nada de especial, mas é um componente disponível globalmente.

Após uma pesquisa, descobri que ele é usado em alguma variante obscura da sintaxe de fatiamento por Numpy e Scipy ... mas quase nada mais.

Este objeto foi adicionado ao idioma especificamente para oferecer suporte ao Numpy + Scipy? A elipse tem algum significado ou uso genérico?

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
Salim Fadhley
fonte
Veja as respostas para stackoverflow.com/questions/752602/…
Patrick McElhaney 21/04/2009
19
Eu achei assim: entrei x=[];x.append(x);print(x)para ver como ele lidava com objetos cíclicos estritos. Voltou [[...]]. Pensei: "Gostaria de saber o que acontece se eu digitar [[...]]. Meu palpite era que isso geraria um erro de sintaxe. Em vez disso, ele retornou [[Ellipsis]]. Python é tão estranho. A pesquisa do Google que me seguiu me levou a esta página.
Cyoce
22
note que o ...em um repr recursiva é apenas um espaço reservado e não tem relação comEllipsis
Eevee
16
Em uma nota totalmente lateral, ponto triplo na importação significa "importar de dois pacotes para cima".
Mad Physicist
1
@croq stackoverflow.com/q/32395926/2988730 . stackoverflow.com/q/1054271/2988730 . Esses dois devem explicar tudo, com links adequados para documentos e PEP nas respostas.
Mad Physicist

Respostas:

558

Isso surgiu em outra questão recentemente. Vou elaborar minha resposta a partir daí:

Elipse é um objeto que pode aparecer na notação de fatia. Por exemplo:

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

Sua interpretação é puramente até o que quer que implementa a __getitem__função e vê Ellipsisobjetos lá, mas a sua principal (e intencional) uso está no numpy biblioteca de terceiros, que adiciona um tipo de matriz multidimensional. Como existem mais de uma dimensão, o fatiamento se torna mais complexo do que apenas um índice de início e parada; é útil poder cortar em várias dimensões também. Por exemplo, dada uma matriz 4x4, a área superior esquerda seria definida pela fatia [: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]])

Estendendo isso ainda mais, as reticências são usadas aqui para indicar um espaço reservado para o restante das dimensões da matriz não especificadas. Pense nisso como indicando a fatia completa [:]para todas as dimensões da lacuna em que está posicionada; portanto, para uma matriz 3d, a[...,0]é a mesma que a[:,:,0]para 4d a[:,:,:,0], da mesma forma que a[0,...,0]é a[0,:,:,0](com quantos dois pontos no meio compõem o número completo). de dimensões na matriz).

Curiosamente, em python3, o Ellipsis literal ( ...) é utilizável fora da sintaxe da fatia, para que você possa realmente escrever:

>>> ...
Ellipsis

Além dos vários tipos numéricos, não, acho que não é usado. Tanto quanto sei, foi adicionado apenas para uso numpy e não possui suporte básico além de fornecer o objeto e a sintaxe correspondente. O objeto que estava lá não exigia isso, mas o suporte literal "..." para fatias exigia.

Brian
fonte
22
também é usado na dica do tipo PEP484 em arquivos stub
noɥʇʎԀʎzɐɹƆ
24
Caso alguém esteja curioso: ele também é usado no typingmódulo da biblioteca padrão : por exemplo, Callable[..., int]para indicar uma chamada que retorna um intsem especificar a assinatura ou Tuple[str, ...]para indicar uma tupla homogênea de strings de comprimento variável.
precisa saber é o seguinte
6
FYI, a estrutura FastAPI (que é para python 3.6+) também (agora) a usa. fastapi.tiangolo.com/tutorial/query-params-str-validations
Andrew Allaire
2
@ArtOfWarfare, você está totalmente certo, e isso é proveniente de alguém que diz verbalmente "reticências" em vez de interromper as frases.
PrimeRibeyeDeal
Eu achei isto. Parece aparecer quando você faz uma auto-referência (referência circular) em uma lista: a = [1, 2]; a[0] = a; print(a)[[...], 2]. É a mesma coisa ou um uso diferente?
Bill
220

No Python 3, você pode usar o literal Ellipsis ...como um espaço reservado "nop" para o código:

def will_do_something():
    ...

Isso não é mágico; qualquer expressão pode ser usada em vez de ..., por exemplo:

def will_do_something():
    1

(Não é possível usar a palavra "sancionado", mas posso dizer que esse uso não foi totalmente rejeitado por Guido.)

tzot
fonte
181
Em uma meia convenção, frequentemente vejo o ...uso em que as pessoas desejam indicar algo que pretendem preencher mais tarde (um bloco vazio 'todo') e passsignificar um bloco destinado a não ter código.
amigos estão
26
O Python também possui o NotImplementedliteral, que é útil quando você deseja que sua função incompleta retorne algo significativo (em vez de Nonecomo no seu exemplo). (Outra usecase: Implementação de operações aritméticas )
zvyn
13
@ zvyn Isso não é literal. É apenas um nome. Por exemplo, NotImplemented = 'something_else'é python válido, mas ... = 'something_else'é um erro de sintaxe.
22416
4
@zvyn E se uma exceção ocorresse ao importar esse módulo? :)
pizzapants184
7
@zvyn NotImplementednão pretende ser uma alternativa para None. Seu uso é bastante restrito. Veja a documentação aqui
hans
69

No Python 3.5 e no PEP484 , as reticências literais são usadas para indicar certos tipos para um verificador de tipo estático ao usar o módulo de digitação .

Exemplo 1:

As tuplas homogêneas de comprimento arbitrário podem ser expressas usando um tipo e elipse, por exemplo Tuple[int, ...]

Exemplo 2:

É possível declarar o tipo de retorno de uma chamada, sem especificar a assinatura da chamada, substituindo reticências literais (três pontos) pela lista de argumentos:

def partial(func: Callable[..., str], *args) -> Callable[..., str]:
    # Body
Fénix
fonte
46

Você também pode usar as reticências ao especificar a saída esperada do 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
fonte
9
Mas isso realmente envolve o objeto Reticências? Não é apenas um recurso do analisador / analisador de documentos?
akaihola
1
@akaihola Eu diria que sim, conforme descrito em doctest.ELLIPSIS . Espero que a maioria, se não todos os usos, ...sejam sintáticos, e não useo objeto de elipse real. Não é realmente nada além de um nome útil para um conceito adaptável?
Nealmcb
34

Na documentação do Python :

Esse objeto é comumente usado em fatias (consulte Fatias ). Não suporta operações especiais. Há exatamente um objeto de reticências, chamado Reticências (um nome interno). type(Ellipsis)()produz o Ellipsis singleton.

Está escrito como Ellipsisou ....

Simon Lieschke
fonte
25

Resumindo o que outros disseram, a partir do Python 3, o Ellipsis é essencialmente outra constante singleton semelhante a None, mas sem um uso específico pretendido. Os usos existentes incluem:

  • Na sintaxe da fatia para representar a fatia completa nas dimensões restantes
  • Na dica de tipo para indicar apenas parte de um tipo ( Callable[..., int]ou Tuple[str, ...])
  • No tipo de arquivo stub para indicar que existe um valor padrão sem especificá-lo

Os usos possíveis podem incluir:

  • Como valor padrão para locais onde Noneé uma opção válida
  • Como o conteúdo de uma função que você ainda não implementou
Matthew D. Scholefield
fonte
14

__getitem__...exemplo mínimo em uma classe personalizada

Quando a sintaxe mágica ...é passada para []uma classe personalizada, __getitem__()recebe um Ellipsisobjeto de classe.

A classe pode fazer o que quiser com esse objeto Singleton.

Exemplo:

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)

A listclasse interna do Python escolhe fornecer a semântica de um intervalo, e qualquer uso sensato dela também deve.

Pessoalmente, eu ficaria longe disso nas minhas APIs e criaria um método separado e mais explícito.

Testado em Python 3.5.2 e 2.7.12.

Ciro Santilli adicionou uma nova foto
fonte
executar este com a -O argumento e seu código sempre será executado; D
moshevi
12

Você pode usar as reticências você mesmo, em situações de fatiamento personalizadas, como o numpy fez, mas não tem uso em nenhuma classe incorporada.

Não sei se foi adicionado especificamente para uso em numpy, mas certamente não o vi usado em outros lugares.

Consulte também: Como você usa a sintaxe de corte de reticências no Python?

sykora
fonte
7

Conforme mencionado por @ noɥʇʎԀʎzɐɹƆ e @phoenix - você pode realmente usá-lo em arquivos stub. por exemplo

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

Mais informações e exemplos de como usar essas reticências podem ser encontradas aqui https://www.python.org/dev/peps/pep-0484/#stub-files

henryJack
fonte
2

Seu uso pretendido não deve ser apenas para esses módulos de terceiros. Ele não é mencionado corretamente na documentação do Python (ou talvez eu simplesmente não tenha conseguido encontrá-lo), mas as reticências ...são realmente usadas no CPython em pelo menos um local.

É usado para representar infinitas estruturas de dados em Python. Eu me deparei com essa notação enquanto brincava com listas.

Veja esta pergunta para mais informações.

Aseem Bansal
fonte
8
Coisas diferentes.Esta pergunta pergunta sobre o ellipsistipo interno e o Ellipsisobjeto. Representar estruturas de dados infinitas com elipses é apenas para exibição, não tendo nada a ver com ellipsistipo ou Ellipsisobjeto.
chys
3
@chys Na verdade, ele funciona de uma maneira pequena - as __repr__seqüências de caracteres Python visam ser expressões válidas em Python - se não fosse por reticências existentes na linguagem, a representação não seria uma expressão válida.
Gareth Latty
3
@ Lattyware Bem, é verdade que o design original pretende. Ele também pretende eval(repr(a))ser igual a a. Infelizmente, é falso de tempos em tempos na prática, mesmo para tipos internos. Tente isto: a=[]; a.append(a); eval(repr(a)). repr(a)é [[...]], expressão inválida no Python 2. (Em Python 3 é válida, mas o resultado eval é algo diferente, ainda contrária à intenção original.)
chys
1

Isso é equivalente.

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

...é uma constante definida por dentro built-in constants.

Elipse

O mesmo que as reticências literais "...". Valor especial usado principalmente em conjunto com a sintaxe de fatia estendida para tipos de dados de contêineres definidos pelo usuário.

prosti
fonte