Co robi obiekt Ellipsis?


539

Podczas bezczynnego przeglądania przestrzeni nazw zauważyłem dziwnie wyglądający obiekt o nazwie Ellipsis, nie wydaje się, że jest ani nie robi nic specjalnego, ale jest wbudowanym globalnie narzędziem.

Po wyszukiwaniu odkryłem, że jest on używany w jakimś niejasnym wariancie składni krojenia przez Numpy i Scipy ... ale prawie nic innego.

Czy ten obiekt został dodany do języka specjalnie w celu obsługi Numpy + Scipy? Czy elipsa ma w ogóle jakieś ogólne znaczenie lub zastosowanie?

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
Znalazłem to tak: weszłam x=[];x.append(x);print(x), aby zobaczyć, jak radzi sobie ze strajkami cyklicznych obiektów. Wrócił [[...]]. Pomyślałem: „Zastanawiam się, co się stanie, jeśli napiszę [[...]]? Zgaduję, że spowodowałoby to błąd składniowy. Zamiast tego wrócił [[Ellipsis]]. Python jest taki dziwny. Wyszukiwanie Google przywiodło mnie na tę stronę.
Cyoce

22
zauważ, że ...rekursywne powtórzenie jest tylko symbolem zastępczym i nie ma związku zEllipsis
Eevee,

16
Z drugiej strony, potrójna kropka w imporcie oznacza „import z dwóch paczek w górę”.
Szalony fizyk

1
@croq stackoverflow.com/q/32395926/2988730 . stackoverflow.com/q/1054271/2988730 . Ci dwaj powinni wyjaśnić wszystko, z odpowiednimi linkami do dokumentów i PEP w odpowiedziach.
Mad Physicist

Odpowiedzi:


557

To pojawiło się niedawno w innym pytaniu . Stamtąd rozwinę moją odpowiedź :

Elipsa jest obiektem, który może pojawić się w notacji plastra. Na przykład:

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

Jego interpretacja zależy wyłącznie od tego, co implementuje __getitem__funkcję i widzi w niej Ellipsisobiekty, ale jej główne (i zamierzone) zastosowanie znajduje się w numpy zewnętrznej bibliotece, która dodaje wielowymiarowy typ tablicy. Ponieważ istnieje więcej niż jeden wymiar, krojenie staje się bardziej złożone niż tylko indeks start i stop; przydatne jest również cięcie na wiele wymiarów. Na przykład, biorąc pod uwagę tablicę 4x4, lewy górny obszar byłby zdefiniowany przez plasterek [: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]])

Rozszerzając to dalej, Ellipsis służy tutaj do wskazania symbolu zastępczego dla pozostałych nieokreślonych wymiarów tablicy. Pomyśl o tym jako o wskazaniu pełnego wycinka [:]dla wszystkich wymiarów w szczelinie, w której jest umieszczony, więc dla tablicy 3d a[...,0]jest taki sam jak a[:,:,0]i dla 4d a[:,:,:,0], podobnie a[0,...,0]jest a[0,:,:,0](z jednak wieloma dwukropkami pośrodku tworzą pełną liczbę wymiarów w tablicy).

Co ciekawe, w python3, literał Ellipsis ( ...) jest użyteczny poza składnią plastra, więc możesz napisać:

>>> ...
Ellipsis

Poza różnymi typami liczbowymi, nie, nie sądzę, żeby był używany. O ile mi wiadomo, został dodany wyłącznie do użytku numpy i nie ma żadnej podstawowej obsługi poza dostarczeniem obiektu i odpowiedniej składni. Obiekt znajdujący się tam nie wymagał tego, ale dosłowna obsługa „...” wycinków tak.


22
jest również używany w podpowiedziach typu PEP484 w plikach pośredniczących
noɥʇʎԀʎzɐɹƆ

24
Na wszelki wypadek, gdy ktoś jest ciekawy: jest on również używany w typingmodule biblioteki standardowej : np. W Callable[..., int]celu wskazania wywołania, które zwraca znak intbez określania podpisu, lub w Tuple[str, ...]celu wskazania jednorodnej krotki ciągów o zmiennej długości.
Anakhand

6
FYI, framework FastAPI (który jest dla Pythona 3.6+) również go używa (teraz). fastapi.tiangolo.com/tutorial/query-params-str-validations
Andrew Allaire

2
@ ArtOfWarfare masz całkowitą rację, a to pochodzi od kogoś, kto ustnie mówi „elipsa” zamiast przerywać między zdaniami.
PrimeRibeyeDeal

Znalazłem to. Wydaje się, że pojawia się, gdy tworzysz samodzielne odniesienie (odwołanie cykliczne) na liście: a = [1, 2]; a[0] = a; print(a)daje [[...], 2]. Czy to to samo, czy inne zastosowanie?
Bill

219

W Pythonie 3 możesz użyć literału Ellipsis ...jako „zastępczego” symbolu zastępczego dla kodu:

def will_do_something():
    ...

To nie jest magia; zamiast wyrażenia można użyć dowolnego wyrażenia ..., np .:

def will_do_something():
    1

(Nie mogę użyć słowa „sankcjonowane”, ale mogę powiedzieć, że Guido nie odrzucił tego użycia ).


180
W pół-konwencji często widzę, że ...używane jest, gdy ludzie chcą wskazać coś, co zamierzają wypełnić później (pusty blok „do zrobienia”), a passto znaczy blok, który nie ma kodu.
Gareth Latty

26
Python ma również NotImplementedliterał, który jest przydatny, gdy chcesz, aby niekompletna funkcja zwróciła coś znaczącego (zamiast Nonejak w twoim przykładzie). (Kolejny
przypadek użycia

13
@zvyn To nie jest dosłowne. To tylko imię. Na przykład NotImplemented = 'something_else'jest poprawny python, ale ... = 'something_else'jest to błąd składniowy.
wim

4
@zvyn Co zrobić, jeśli wystąpił wyjątek podczas importowania tego modułu? :)
pizzapants184 24.04.17

7
@zvyn NotImplementednie jest alternatywą dla None. Jego użycie jest raczej wąskie. Zobacz dokumentację tutaj
hans

68

Począwszy od Python 3.5 i PEP484 , dosłowna wielokropek jest używana do oznaczania niektórych typów statycznego sprawdzania typów podczas korzystania z modułu pisania .

Przykład 1:

Krotki jednorodne o dowolnej długości można wyrazić za pomocą, na przykład, jednego rodzaju i elipsy Tuple[int, ...]

Przykład 2:

Możliwe jest zadeklarowanie typu zwracanego wywołania bez określania podpisu wywołania przez podstawienie literalnej elipsy (trzy kropki) na listę argumentów:

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

46

Można także użyć wielokropka podczas określania oczekiwanego wyniku 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

9
Ale czy faktycznie dotyczy to obiektu Ellipsis? Czy to nie tylko funkcja parsera / dopasowywania doctest?
akaihola

1
@akaihola Powiedziałbym, że tak, jak opisano w doctest.ELLIPSIS . Oczekuję, że większość, jeśli nie wszystkie zastosowania, ...są składniowe, a nie userzeczywisty obiekt Ellipsis. Czy tak naprawdę nie jest to nic innego jak przydatna nazwa adaptowalnej koncepcji?
nealmcb

34

Z dokumentacji Python :

Ten obiekt jest często używany do krojenia (patrz Krojenie ). Nie obsługuje żadnych operacji specjalnych. Istnieje dokładnie jeden obiekt elipsy o nazwie Ellipsis (nazwa wbudowana). type(Ellipsis)()tworzy singleton Ellipsis.

Jest napisane jako Ellipsislub ....


25

Podsumowując, co powiedzieli inni, począwszy od Pythona 3, Ellipsis jest zasadniczo kolejną stałą singletonu podobną do None, ale bez określonego zamierzonego zastosowania. Istniejące zastosowania obejmują:

  • W składni wycinka do reprezentowania pełnego wycinka w pozostałych wymiarach
  • Podpowiedzi typu wskazują tylko część typu ( Callable[..., int]lub Tuple[str, ...])
  • W typach plików pośrednich wskazujących, że istnieje wartość domyślna bez jej określania

Możliwe zastosowania mogą obejmować:

  • Jako wartość domyślna dla miejsc, w których Nonejest poprawna opcja
  • Jako treść funkcji, której jeszcze nie zaimplementowałeś

14

__getitem__minimalny ...przykład w klasie niestandardowej

Kiedy magiczna składnia ...zostanie przekazana []w klasie niestandardowej, __getitem__()otrzymuje Ellipsisobiekt klasy.

Klasa może wtedy robić co chce z tym obiektem Singleton.

Przykład:

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)

Wbudowana listklasa Python decyduje się na semantykę zakresu, a każde rozsądne użycie go również powinno oczywiście.

Osobiście trzymałbym się z dala od tego w moich interfejsach API i zamiast tego stworzyłem osobną, bardziej jednoznaczną metodę.

Testowane w Python 3.5.2 i 2.7.12.


uruchom to z argumentem -O, a twój kod zawsze będzie działał; D
moshevi

12

Możesz używać Ellipsis samodzielnie, w niestandardowych sytuacjach krojenia, takich jak Numpy, ale nie ma zastosowania w żadnej wbudowanej klasie.

Nie wiem, czy został dodany specjalnie do użycia w numpy, ale na pewno nie widziałem go używanego gdzie indziej.

Zobacz także: Jak korzystać ze składni krojenia elipsy w Pythonie?


7

Jak wspomniano przez @ noɥʇʎԀʎzɐɹƆ i @phoenix - Rzeczywiście można go używać w plikach pośredniczących. na przykład

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

Więcej informacji i przykłady korzystania z tej wielokropka można znaleźć tutaj https://www.python.org/dev/peps/pep-0484/#stub-files


2

Jego przeznaczenie nie powinno dotyczyć tylko tych modułów innych firm. Nie jest to odpowiednio wymienione w dokumentacji Pythona (a może po prostu nie mogłem tego znaleźć), ale elipsa ...jest faktycznie używana w CPython w co najmniej jednym miejscu.

Służy do reprezentowania nieskończonych struktur danych w Pythonie. Natknąłem się na ten zapis, bawiąc się listami.

Zobacz to pytanie, aby uzyskać więcej informacji.


8
Różne rzeczy. To pytanie dotyczy ellipsiswbudowanego typu i Ellipsisobiektu. Reprezentowanie nieskończonych struktur danych za pomocą elips służy wyłącznie do wyświetlania, nie ma nic wspólnego z ellipsistypem lub Ellipsisobiektem.
chys

3
@chys W rzeczywistości robi to w niewielki sposób - __repr__ciągi Pythona mają być prawidłowymi wyrażeniami Pythona - gdyby nie elipsa występująca w tym języku, reprezentacja nie byłaby prawidłowym wyrażeniem.
Gareth Latty

3
@Lattyware Cóż, to prawda, że ​​oryginalny projekt tak zamierza. Ma również na eval(repr(a))celu być równym a. Niestety w praktyce jest to nieprawda, nawet dla typów wbudowanych. Spróbuj tego: a=[]; a.append(a); eval(repr(a)). repr(a)to [[...]]niepoprawne wyrażenie w Pythonie 2. (W Pythonie 3 jest poprawne, ale wynik ewaluacji jest czymś innym, wciąż sprzecznym z pierwotną intencją.)
chys

1

To jest równoważne.

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

...jest stałą zdefiniowaną w środku built-in constants.

Elipsa

To samo co dosłowne „...”. Specjalna wartość używana głównie w połączeniu z rozszerzoną składnią podziału na segmenty dla zdefiniowanych przez użytkownika typów danych kontenera.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.