¿Qué hace el objeto de puntos suspensivos?

540

Mientras navegaba distraídamente por el espacio de nombres, noté que se llamaba un objeto de aspecto extraño Ellipsis, que no parece ser o no hace nada especial, pero es un componente incorporado disponible a nivel mundial.

Después de una búsqueda descubrí que Numpy y Scipy lo usan en alguna variante oscura de la sintaxis de corte ... pero casi nada más.

¿Se agregó este objeto al lenguaje específicamente para admitir Numpy + Scipy? ¿Ellipsis tiene algún significado genérico o uso?

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
fuente
Vea las respuestas a stackoverflow.com/questions/752602/…
Patrick McElhaney el
19
Lo encontré así: entré x=[];x.append(x);print(x)para ver cómo manejaba la cadena de objetos cíclicos. Se volvió [[...]]. Pensé "Me pregunto qué sucede si escribo en [[...]]mi suposición era que arrojaría un error de sintaxis En cambio, volvió?. [[Ellipsis]]Python es tan raro de búsqueda Google El que me sobrevino trajo a esta página...
Cyoce
22
tenga ...en cuenta que en una repetición recursiva es solo un marcador de posición y no tiene relación conEllipsis
Eevee
16
En una nota totalmente al margen, el punto triple en la importación significa "importar desde dos paquetes en adelante".
Físico loco
1
@croq stackoverflow.com/q/32395926/2988730 . stackoverflow.com/q/1054271/2988730 . Esos dos deberían explicar todo, con enlaces adecuados a documentos y PEP en las respuestas.
Físico loco

Respuestas:

559

Esto surgió en otra pregunta recientemente. Explicaré mi respuesta a partir de ahí:

Elipsis es un objeto que puede aparecer en notación de corte. Por ejemplo:

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

Su interpretación es puramente hasta cualquier implementa la __getitem__función y ve Ellipsislos objetos allí, pero su principal (y la intención) es el uso en el numpy biblioteca de terceros, lo que añade un tipo de matriz multidimensional. Como hay más de una dimensión, el corte se vuelve más complejo que solo un índice de inicio y detención; También es útil poder cortar en varias dimensiones. Por ejemplo, dada una matriz 4x4, el área superior izquierda estaría definida por el segmento [: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]])

Extendiendo esto más, Elipsis se usa aquí para indicar un marcador de posición para el resto de las dimensiones de la matriz no especificadas. Piense en ello como indicando el corte completo [:]para todas las dimensiones en el espacio en el que se coloca, por lo que para una matriz 3D, a[...,0]es igual a[:,:,0]y para 4d a[:,:,:,0], de manera similar, a[0,...,0]esa[0,:,:,0] (con sin embargo muchos signos de dos puntos en la composición media de hasta el número completo de dimensiones en la matriz).

Curiosamente, en python3, el Elipsis literal ( ...) se puede usar fuera de la sintaxis de corte, por lo que puede escribir:

>>> ...
Ellipsis

Aparte de los diversos tipos numéricos, no, no creo que se use. Hasta donde yo sé, se agregó únicamente para un uso complejo y no tiene soporte principal aparte de proporcionar el objeto y la sintaxis correspondiente. El objeto que estaba allí no requería esto, pero el soporte literal "..." para los cortes sí.

Brian
fuente
22
también se usa en sugerencias de tipo PEP484 en archivos de resguardo
noɥʇʎԀʎzɐɹƆ
24
Por si alguien tiene curiosidad: también se usa en el typingmódulo de biblioteca estándar : por ejemplo, Callable[..., int]para indicar un invocable que devuelve un intsin especificar la firma, o Tuple[str, ...]para indicar una tupla homogénea de cadenas de longitud variable.
Anakhand
66
Para su información, el marco FastAPI (que es para Python 3.6+) también lo usa (ahora). fastapi.tiangolo.com/tutorial/query-params-str-validations
Andrew Allaire
2
@ArtOfWarfare tiene toda la razón, y esto proviene de alguien que dice verbalmente "puntos suspensivos" en lugar de irse entre las oraciones.
PrimeRibeyeDeal
Encontré esto. Parece aparecer cuando hace una autorreferencia (referencia circular) en una lista: a = [1, 2]; a[0] = a; print(a)da [[...], 2]. ¿Es esto lo mismo o un uso diferente?
Bill
220

En Python 3, puede usar el literal de puntos suspensivos ...como un marcador de posición "nop" para el código:

def will_do_something():
    ...

Esto no es magia; se puede usar cualquier expresión en lugar de ..., por ejemplo:

def will_do_something():
    1

(No puedo usar la palabra "sancionado", pero puedo decir que Guido no rechazó este uso ).

tzot
fuente
181
En una media convención, a menudo veo ...que las personas quieren indicar algo que tienen la intención de completar más adelante (un bloque vacío 'todo') y passsignifican un bloque que no tiene código.
Gareth Latty
26
Python también tiene el NotImplementedliteral, que es útil cuando desea que su función incompleta devuelva algo significativo (en lugar de Nonecomo en su ejemplo). (Otro caso de uso: Implementación de operaciones aritméticas )
zvyn
13
@zvyn Eso no es literal. Es solo un nombre. Por ejemplo, NotImplemented = 'something_else'es Python válido, pero ... = 'something_else'es un error de sintaxis.
wim
44
@zvyn ¿Qué sucede si se produjo una excepción al importar ese módulo? :)
pizzapants184
77
@zvyn NotImplementedno pretende ser una alternativa a None. Su uso es bastante limitado. Ver documentación aquí
Hans
69

A partir de Python 3.5 y PEP484 , los puntos suspensivos literales se usan para denotar ciertos tipos a un verificador de tipo estático cuando se usa la escritura módulo de .

Ejemplo 1:

Las tuplas homogéneas de longitud arbitraria se pueden expresar usando un tipo y puntos suspensivos, por ejemplo Tuple[int, ...]

Ejemplo 2

Es posible declarar el tipo de retorno de un invocable sin especificar la firma de la llamada sustituyendo una elipsis literal (tres puntos) por la lista de argumentos:

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

También puede usar los puntos suspensivos al especificar la salida doctest esperada :

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
fuente
99
Pero, ¿esto realmente involucra el objeto Elipsis? ¿No es solo una característica del analizador / analizador doctest?
akaihola
1
@akaihola Yo diría que sí, como se describe en doctest.ELLIPSIS . Espero que la mayoría, si no todos los usos de, ...sean sintácticos, y no useel objeto de puntos suspensivos real. ¿No es realmente nada más que un nombre práctico para un concepto adaptable?
nealmcb
34

De la documentación de Python :

Este objeto se usa comúnmente para cortar (ver Cortar ). No admite operaciones especiales. Hay exactamente un objeto de puntos suspensivos, denominado Puntos suspensivos (un nombre incorporado). type(Ellipsis)()produce la elipsis singleton.

Está escrito como Ellipsiso ....

Simon Lieschke
fuente
25

Resumiendo lo que otros han dicho, a partir de Python 3, Ellipsis es esencialmente otra constante singleton similar a None, pero sin un uso previsto particular. Los usos existentes incluyen:

  • En sintaxis de corte para representar el corte completo en las dimensiones restantes
  • En sugerencias de tipo para indicar solo una parte de un tipo ( Callable[..., int]o Tuple[str, ...])
  • En tipo stub files para indicar que hay un valor predeterminado sin especificarlo

Los posibles usos podrían incluir:

  • Como valor predeterminado para lugares donde Nonees una opción válida
  • Como el contenido de una función que aún no ha implementado
Matthew D. Scholefield
fuente
14

__getitem__...ejemplo mínimo en una clase personalizada

Cuando la sintaxis mágica ...se pasa a []una clase personalizada, __getitem__()recibe un Ellipsisobjeto de clase.

La clase puede hacer lo que quiera con este objeto Singleton.

Ejemplo:

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)

El Python incorporado list clase elige darle la semántica de un rango, y cualquier uso sensato de él también debería, por supuesto.

Personalmente, me mantendría alejado de esto en mis API y crearía un método separado y más explícito.

Probado en Python 3.5.2 y 2.7.12.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
ejecute esto con el argumento -O y su código siempre se ejecutará; D
moshevi
7

Como lo mencionaron @ noɥʇʎԀʎzɐɹƆ y @phoenix: de hecho, puede usarlo en archivos stub. p.ej

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

Puede encontrar más información y ejemplos de cómo usar estos puntos suspensivos aquí https://www.python.org/dev/peps/pep-0484/#stub-files

henryjack
fuente
2

Su uso previsto no debería ser solo para estos módulos de terceros. No se menciona correctamente en la documentación de Python (o tal vez simplemente no pude encontrar eso), pero los puntos suspensivos ...se usan en CPython en al menos un lugar.

Se utiliza para representar estructuras de datos infinitas en Python. Encontré esta notación mientras jugaba con las listas.

Vea esta pregunta para más información.

Aseem Bansal
fuente
8
Diferentes cosas. Esta pregunta se refiere al tipo ellipsisincorporado y al Ellipsisobjeto. La representación de estructuras de datos infinitas con puntos suspensivos es puramente para mostrar, no tiene nada que ver con el ellipsistipo o el Ellipsisobjeto.
chys
3
@chys En realidad, lo hace de una manera pequeña: las __repr__cadenas de Python pretenden ser expresiones Python válidas; si no fuera por los puntos suspensivos existentes en el lenguaje, la representación no sería una expresión válida.
Gareth Latty
3
@Lattyware Bueno, es cierto que el diseño original lo pretende. También tiene la eval(repr(a))intención de ser igual a a. Desafortunadamente, es falso de vez en cuando en la práctica, incluso para los tipos incorporados. Trate de hacer esto: a=[]; a.append(a); eval(repr(a)). repr(a)es decir [[...]], expresión inválida en Python 2. (En Python 3 es válido, pero el resultado de la evaluación es algo diferente, aún contrario a la intención original.)
chys
1

Esto es equivalente

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

...Es una constante definida en su interior built-in constants.

Elipsis

Lo mismo que la elipsis literal "...". Valor especial utilizado principalmente junto con la sintaxis de segmentación extendida para tipos de datos de contenedor definidos por el usuario.

prosti
fuente