Que fait l'objet Ellipsis?


540

En surfant paresseusement sur l'espace de noms, j'ai remarqué un objet d'apparence étrange appelé Ellipsis, il ne semble pas être ou faire quelque chose de spécial, mais c'est un module intégré disponible dans le monde entier.

Après une recherche, j'ai trouvé qu'il est utilisé dans une variante obscure de la syntaxe de découpage par Numpy et Scipy ... mais presque rien d'autre.

Cet objet a-t-il été ajouté au langage spécifiquement pour prendre en charge Numpy + Scipy? Ellipsis a-t-il une signification ou une utilisation générique?

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


19
Je l'ai trouvé comme ceci: je suis entré x=[];x.append(x);print(x), pour voir comment il gérait les objets cycliques en chaîne. Il est revenu [[...]]. Je me suis dit: "Je me demande ce qui se passe si je tape [[...]]? Je suppose que cela déclencherait une erreur de syntaxe. Au lieu de cela, il est revenu [[Ellipsis]]. Python est tellement bizarre. La recherche Google qui a suivi m'a amené à cette page.
Cyoce

22
notez que le ...dans une repr récursive est juste un espace réservé et n'a aucun rapport avecEllipsis
Evoli

16
D'un autre côté, le point triple dans l'importation signifie "importer à partir de deux paquets".
Mad Physicist

1
@croq stackoverflow.com/q/32395926/2988730 . stackoverflow.com/q/1054271/2988730 . Ces deux devraient tout expliquer, avec des liens appropriés vers les documents et le PEP dans les réponses.
Mad Physicist

Réponses:


559

Cela a été soulevé récemment dans une autre question . Je développerai ma réponse à partir de là:

Les points de suspension sont un objet qui peut apparaître en notation de tranche. Par exemple:

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

Son interprétation dépend uniquement de ce qui implémente la __getitem__fonction et y voit des Ellipsisobjets, mais son utilisation principale (et prévue) se trouve dans la bibliothèque tierce numpy , qui ajoute un type de tableau multidimensionnel. Puisqu'il y a plus d'une dimension, le découpage devient plus complexe qu'un simple index de début et de fin; il est également utile de pouvoir découper en plusieurs dimensions. Par exemple, étant donné un tableau 4x4, la zone en haut à gauche serait définie par la tranche [: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]])

Pour étendre cela, Ellipsis est utilisé ici pour indiquer un espace réservé pour le reste des dimensions du tableau non spécifié. Considérez-le comme indiquant la tranche complète [:]pour toutes les dimensions de l'espace dans lequel il est placé, donc pour un tableau 3D, a[...,0]est le même que a[:,:,0]pour 4d a[:,:,:,0], de même, a[0,...,0]est a[0,:,:,0](avec autant de deux-points au milieu constituent le nombre complet des dimensions dans le tableau).

Fait intéressant, en python3, le Ellipsis literal ( ...) est utilisable en dehors de la syntaxe de tranche, vous pouvez donc réellement écrire:

>>> ...
Ellipsis

À part les différents types numériques, non, je ne pense pas que ce soit utilisé. Pour autant que je sache, il a été ajouté uniquement pour une utilisation numpy et n'a aucun support de base autre que la fourniture de l'objet et de la syntaxe correspondante. L'objet étant là ne l'exigeait pas, mais le support littéral "..." pour les tranches le faisait.


22
il est également utilisé dans les indications de type PEP484 dans les fichiers de raccord
noɥʇʎԀʎzɐɹƆ

24
Juste au cas où quelqu'un serait curieux: il est également utilisé dans le typingmodule de bibliothèque standard : par exemple Callable[..., int]pour indiquer un appelable qui retourne un intsans spécifier la signature, ou Tuple[str, ...]pour indiquer un tuple de chaînes homogène de longueur variable.
Anakhand

6
Pour info, le framework FastAPI (qui est pour python 3.6+) l'utilise également (maintenant). fastapi.tiangolo.com/tutorial/query-params-str-validations
Andrew Allaire

2
@ArtOfWarfare vous avez tout à fait raison, et cela vient de quelqu'un qui dit verbalement "des points de suspension" au lieu de s'interrompre entre les phrases.
PrimeRibeyeDeal

J'ai trouvé ça. Il semble apparaître lorsque vous faites une auto-référence (référence circulaire) dans une liste: a = [1, 2]; a[0] = a; print(a)donne [[...], 2]. Est-ce la même chose ou une utilisation différente?
Bill

220

Dans Python 3, vous pouvez utiliser le littéral Ellipsis ...comme espace réservé "nop" pour le code:

def will_do_something():
    ...

Ce n'est pas magique; n'importe quelle expression peut être utilisée à la place de ..., par exemple:

def will_do_something():
    1

(Je ne peux pas utiliser le mot «sanctionné», mais je peux dire que cette utilisation n'a pas été catégoriquement rejetée par Guido.)


181
Dans une demi-convention, je vois souvent ...utilisé où les gens veulent indiquer quelque chose qu'ils ont l'intention de remplir plus tard (un bloc vide 'todo') et passsignifier un bloc destiné à ne pas avoir de code.
Gareth Latty

26
Python a également le NotImplementedlittéral, qui est utile lorsque vous voulez que votre fonction incomplète renvoie quelque chose de significatif (au lieu de Nonecomme dans votre exemple). (Autre cas d'utilisation: implémentation d'opérations arithmétiques )
zvyn

13
@zvyn Ce n'est pas un littéral. C'est juste un nom. Par exemple, NotImplemented = 'something_else'c'est du python valide, mais ... = 'something_else'c'est une erreur de syntaxe.
wim

4
@zvyn Que faire si une exception s'est produite lors de l'importation de ce module? :)
pizzapants184

7
@zvyn NotImplementedn'est pas destiné à être une alternative à None. Son utilisation est assez étroite. Voir la documentation ici
hans

69

Depuis Python 3.5 et PEP484 , les points de suspension littéraux sont utilisés pour désigner certains types à un vérificateur de type statique lors de l'utilisation du module de saisie .

Exemple 1:

Les tuples homogènes de longueur arbitraire peuvent être exprimés en utilisant un type et des points de suspension, par exemple Tuple[int, ...]

Exemple 2:

Il est possible de déclarer le type de retour d'un appelable sans spécifier la signature d'appel en substituant une ellipse littérale (trois points) à la liste des arguments:

def partial(func: Callable[..., str], *args) -> Callable[..., str]:
    # Body

46

Vous pouvez également utiliser les points de suspension pour spécifier le doctorat attendu sortie :

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

9
Mais cela implique-t-il réellement l'objet Ellipsis? N'est-ce pas seulement une caractéristique de l'analyseur / matcher doctest?
akaihola

1
@akaihola Je dirais que oui, comme décrit sur doctest.ELLIPSIS . Je m'attends à ce que la plupart sinon toutes les utilisations de ...soient syntaxiques, et non usel'objet Ellipsis réel. N'est-ce vraiment rien de plus qu'un nom pratique pour un concept adaptable?
nealmcb

34

Dans la documentation Python :

Cet objet est couramment utilisé par le tranchage (voir Tranchage ). Il ne prend en charge aucune opération spéciale. Il existe exactement un objet points de suspension, nommé points de suspension (un nom intégré). type(Ellipsis)()produit le singleton Ellipsis.

Il est écrit comme Ellipsisou ....


25

Résumant ce que d'autres ont dit, à partir de Python 3, Ellipsis est essentiellement une autre constante singleton similaire None, mais sans utilisation particulière. Les utilisations existantes comprennent:

  • Dans la syntaxe de tranche pour représenter la tranche complète dans les dimensions restantes
  • Dans l'indication de type pour n'indiquer qu'une partie d'un type ( Callable[..., int]ouTuple[str, ...] )
  • Dans les fichiers stub de type pour indiquer qu'il existe une valeur par défaut sans la spécifier

Les utilisations possibles pourraient inclure:

  • Par défaut pour les endroits où Noneest une option valide
  • En tant que contenu d'une fonction que vous n'avez pas encore implémentée

14

__getitem__...exemple minimal dans une classe personnalisée

Lorsque la syntaxe magique ...est transmise à []une classe personnalisée, __getitem__()reçoit un Ellipsisobjet de classe.

La classe peut alors faire ce qu'elle veut avec cet objet Singleton.

Exemple:

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)

Le Python intégré list classe choisit de lui donner la sémantique d'une plage, et toute utilisation sensée devrait également bien sûr.

Personnellement, je m'en tenir à l'écart dans mes API et créer à la place une méthode distincte et plus explicite.

Testé en Python 3.5.2 et 2.7.12.


exécutez cela avec l' argument -O et votre code s'exécutera toujours; D
moshevi


7

Comme mentionné par @ noɥʇʎԀʎzɐɹƆ et @phoenix - Vous pouvez en effet l'utiliser dans des fichiers stub. par exemple

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

Plus d'informations et d'exemples sur la façon d'utiliser ces points de suspension peuvent être découverts ici https://www.python.org/dev/peps/pep-0484/#stub-files


2

Son utilisation prévue ne devrait pas être réservée à ces modules tiers. Il n'est pas mentionné correctement dans la documentation Python (ou peut-être que je ne le trouve pas), mais les points de suspension ...sont en fait utilisés dans CPython à au moins un endroit.

Il est utilisé pour représenter des structures de données infinies en Python. Je suis tombé sur cette notation en jouant avec des listes.

Voir cette question pour plus d'informations.


8
Différentes choses: cette question porte sur le type ellipsisintégré et l' Ellipsisobjet. La représentation de structures de données infinies avec des ellipses est purement pour l'affichage, n'ayant rien à voir avec le ellipsistype ou l' Ellipsisobjet.
chys

3
@chys En fait, il le fait d'une petite manière - les __repr__chaînes Python visent à être des expressions Python valides - sans les ellipses existant dans le langage comme il le fait, la représentation ne serait pas une expression valide.
Gareth Latty

3
@Lattyware Eh bien, c'est vrai que le design original le prévoit. Il vise également eval(repr(a))à être égal à a. Malheureusement, c'est faux de temps en temps dans la pratique, même pour les types intégrés. Essayez ceci: a=[]; a.append(a); eval(repr(a)). repr(a)est [[...]]une expression non valide dans Python 2. (Dans Python 3, c'est valide, mais le résultat de l'évaluation est quelque chose de différent, toujours contraire à l'intention d'origine.)
chys

1

C'est équivalent.

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

...est une constante définie à l'intérieur built-in constants.

Ellipse

Identique à l'ellipse littérale "...". Valeur spéciale utilisée principalement en conjonction avec la syntaxe de découpage étendue pour les types de données de conteneur définis par l'utilisateur.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.