Ukryte funkcje Pythona [zamknięte]


1419

Jakie są mniej znane, ale przydatne funkcje języka programowania Python?

  • Spróbuj ograniczyć odpowiedzi do rdzenia Pythona.
  • Jedna funkcja na odpowiedź.
  • Podaj przykład i krótki opis funkcji, a nie tylko link do dokumentacji.
  • Oznacz obiekt, używając tytułu jako pierwszego wiersza.

Szybkie linki do odpowiedzi:

Odpowiedzi:


740

Łańcuchowe operatory porównania:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

W przypadku, gdy myślisz, że działa 1 < x, wychodzi True, a następnie porównuje True < 10, co również oznacza True, że nie, to naprawdę nie to, co się dzieje (patrz ostatni przykład). To naprawdę przekłada się na 1 < x and x < 10i x < 10 and 10 < x * 10 and x*10 < 100, ale z mniejszym pisaniem i każdym z nich semestr jest oceniany tylko raz.


121
To bardzo pomocne. Powinien być standardem we wszystkich językach. Niestety tak nie jest.
stalepretzel

8
powinieneś również dodać kilka przykładów, które zwracają również false. takie jak >>> 10 <x <20 False
ShoeLace

19
Odnosi się to również do innych operatorów porównania, dlatego ludzie czasami są zaskoczeni, dlaczego kod typu (5 w [5] jest Prawdą) jest Fałszem (ale na początku nie jest oczywiste, że jawnie testuje się na booleanach).
Miles

19
Dobrze, ale uważaj na równość, na przykład „in” i „=”. „A in B == C in D” oznacza „(A in B) i (B == C) i (C in D)”, co może być nieoczekiwane.
Charles Merriam,

15
Azafe: Porównania Lispa naturalnie działają w ten sposób. To nie jest szczególny przypadek, ponieważ nie ma innego (rozsądnego) sposobu interpretacji (< 1 x 10). Możesz nawet zastosować je do pojedynczych argumentów, takich jak (= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/…
Ken

512

Pobierz drzewo parsowania wyrażenia regularnego w Pythonie, aby debugować wyrażenie regularne.

Wyrażenia regularne są świetną funkcją Pythona, ale ich debugowanie może być uciążliwe i zbyt łatwo jest pomylić wyrażenie regularne.

Na szczęście Python może wydrukować drzewo analizy wyrażeń regularnych, przekazując nieudokumentowaną, eksperymentalną, ukrytą flagę re.DEBUG(właściwie 128) do re.compile.

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

Po zrozumieniu składni możesz dostrzec swoje błędy. Nie widzimy, że zapomniałem uciec []in [/font].

Oczywiście możesz to połączyć z dowolnymi flagami, takimi jak skomentowane wyrażenia regularne:

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
Z wyjątkiem parsowania HTML za pomocą wyrażeń regularnych jest powolny i bolesny. Nawet wbudowany moduł analizatora składni „html” nie używa wyrażeń regularnych do wykonania pracy. A jeśli moduł HTML ci się nie podoba, istnieje wiele modułów analizatora składni XML / HTML, które wykonują zadanie bez konieczności ponownego tworzenia koła.
BatchyX

Link do dokumentacji na temat składni wyjściowej byłby świetny.
Personman

1
Powinna to być oficjalna część Pythona, a nie eksperymentalna ... RegEx jest zawsze trudny, a możliwość śledzenia tego, co się dzieje, jest naprawdę pomocna.
Cahit

460

wyliczać

Zawijaj iterowalny wyliczeniem, a otrzymasz element wraz z jego indeksem.

Na przykład:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

Bibliografia:


56
Dziwi mnie, że nie jest to rutynowo omawiane w tutorialach dotyczących list pythonowych.
Draemon

45
I przez cały ten czas pisałem w ten sposób: dla i w zakresie (len (a)): ... a następnie używając [i], aby uzyskać bieżący element.
Fernando Martin

4
@Berry Tsakala: O ile mi wiadomo, nie było to przestarzałe.
JAB

23
Cholera jasna, to jest niesamowite. for i in xrange (len (a)): zawsze był moim najmniej ulubionym idiomem python.
Personman

15
wyliczanie może zaczynać się od dowolnego indeksu, nie jest konieczne 0. Przykład: „dla i, pozycja w wyliczeniu ( lista , start = 1): wydrukuj i, pozycja” rozpocznie wyliczanie od 1, a nie 0.
dmitry_romanov

419

Tworzenie obiektów generatorów

Jeśli napiszesz

x=(n for n in foo if bar(n))

możesz wyjść z generatora i przypisać go do x. Teraz oznacza to, że możesz to zrobić

for n in x:

Zaletą tego jest to, że nie potrzebujesz pośredniego magazynu, który byłby potrzebny, gdybyś to zrobił

x = [n for n in foo if bar(n)]

W niektórych przypadkach może to prowadzić do znacznego przyspieszenia.

Możesz dołączyć wiele instrukcji if na końcu generatora, w zasadzie replikując zagnieżdżone dla pętli:

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

Możesz także użyć do tego celu zagnieżdżonej listy, tak?
shapr

54
Na szczególną uwagę zasługują narzuty pamięci. Wartości są obliczane na żądanie, więc nigdy nie masz w pamięci całego wyniku zrozumienia listy. Jest to szczególnie pożądane, jeśli później wykonasz iterację tylko części zrozumienia listy.
saffsd

19
Nie jest to szczególnie „ukryte” imo, ale warto również zauważyć, że nie można przewinąć obiektu generatora, podczas gdy można powtarzać listę dowolną liczbę razy.
susmits,

13
Funkcja „bez przewijania” generatorów może powodować pewne zamieszanie. W szczególności, jeśli wydrukujesz zawartość generatora do debugowania, użyj go później do przetworzenia danych, to nie działa. Dane są generowane, zużywane przez print (), a następnie nie są dostępne do normalnego przetwarzania. Nie dotyczy to wyrażeń listowych, ponieważ są one całkowicie przechowywane w pamięci.
johntellsall

4
Podobna (dup?) Odpowiedź: stackoverflow.com/questions/101268/hidden-features-of-python/... Należy jednak pamiętać, że odpowiedź, którą tu linkowałem, mówi o NAPRAWDĘ DOBREJ prezentacji o mocy generatorów. Naprawdę powinieneś to sprawdzić.
Denilson Sá Maia,

353

iter () może przyjąć argument wywoływalny

Na przykład:

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

iter(callable, until_value)Funkcja wielokrotnie wzywa callablei daje swój wynik aż until_valuezostanie zwrócony.


Czy jako początkujący Python możesz wyjaśnić, dlaczego lambdasłowo kluczowe jest tutaj potrzebne?
SiegeX,

@SiegeX bez lambda, f.read (1) byłby obliczany (zwracając ciąg) przed przekazaniem go do funkcji iteracyjnej. Zamiast tego lambda tworzy anonimową funkcję i przekazuje ją iteracji.
jmilloy

339

Uważaj na zmienne argumenty domyślne

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

Zamiast tego powinieneś użyć wartownika oznaczającego „nie podano” i zastąpić zmienną, którą chcesz domyślnie:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
To zdecydowanie jedna z bardziej nieprzyjemnych ukrytych funkcji. Od czasu do czasu na to wpadam.
Torsten Marek,

77
Znalazłem to o wiele łatwiej zrozumieć, gdy dowiedziałem się, że domyślne argumenty żyją w krotce, która jest atrybutem funkcji, np foo.func_defaults. Które, będąc krotką, jest niezmienne.
Robert Rossney,

2
@grayger: Gdy wykonywana jest instrukcja def, jej argumenty są oceniane przez interpretera. Spowoduje to utworzenie (lub ponowne powiązanie) nazwy obiektu kodu (zestawu funkcji). Jednak domyślne argumenty są tworzone w postaci obiektów w momencie definicji. Jest to prawdą w przypadku dowolnego obiektu domyślnie, ale znaczącego (ujawniającego widoczną semantykę), gdy obiekt jest zmienny. Nie ma możliwości ponownego powiązania domyślnej nazwy argumentu w zamknięciu funkcji, chociaż można ją oczywiście pominąć dla dowolnego wywołania lub można ponownie zdefiniować całą funkcję).
Jim Dennis

3
@Robert oczywiście argumenty mogą być niezmienne, ale obiekty, na które wskazują, niekoniecznie są niezmienne.
poolie

16
Jeden szybki hack, aby nieco skrócić inicjalizację: x = x lub []. Możesz użyć tego zamiast 2-wierszowej instrukcji if.
dave mankoff

317

Przesyłanie wartości do funkcji generatora . Na przykład mając tę ​​funkcję:

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

Możesz:

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

Zgoda. Potraktujmy to jako paskudny przykład ukrytej funkcji Pythona :)
Rafał Dowgird,

89
W innych językach uważam, że to magiczne urządzenie nazywane jest „zmienną”.
finnw

5
coroutine powinny być coroutines, a genenerator także powinien być sobą, bez mieszania. Mega-świetny link i dyskusja oraz przykłady na ten temat tutaj: dabeaz.com/coroutines
u0b34a0f6ae

31
@finnw: przykład implementuje coś podobnego do zmiennej. Jednak tej funkcji można użyć na wiele innych sposobów ... w przeciwieństwie do zmiennej. Powinno być również oczywiste, że podobną semantykę można zaimplementować przy użyciu obiektów (w szczególności klasy imitującej metodę wywołania Pythona ).
Jim Dennis

4
To zbyt trywialny przykład dla osób, które nigdy nie widziały (i prawdopodobnie nie zrozumieją) wspólnych procedur. Przykład, który implementuje średnią bieżącą bez ryzyka przepełnienia zmiennej sumy, jest dobry.
Prashant Kumar,

313

Jeśli nie lubisz używać białych znaków do oznaczania zakresów, możesz użyć stylu C {}, wydając:

from __future__ import braces

122
To jest złe. :)
Jason Baker

37
>>> z __future__ import nawiasów klamrowych Plik „<stdin>”, wiersz 1 Błąd składni: brak szansy: P
Benjamin W. Smith

40
to bluźnierstwo!
Berk D. Demir

335
Myślę, że możemy mieć tutaj błąd składniowy, czyż nie powinno to być „z __past__ import nawiasów klamrowych”?
Bill K

47
z __cruft__ import nawiasów klamrowych
Phillip B Oldham

305

Argument kroku w operatorach wycinków. Na przykład:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

Przypadek specjalny x[::-1]jest przydatnym idiomem dla „x reverse”.

>>> a[::-1]
[5,4,3,2,1]

31
moim zdaniem znacznie wyraźniejsza jest funkcja reverse (). >>> lista (odwrócona (zakres (4))) [3, 2, 1, 0]
Christian Oudard

3
jak lepiej napisać „ten ia string” [:: - 1]? odwrócone wydaje się nie pomagać
Berry Tsakala

24
Problem z odwróconą () polega na tym, że zwraca iterator, więc jeśli chcesz zachować typ odwróconej sekwencji (krotka, ciąg, lista, Unicode, typy użytkowników ...), potrzebujesz dodatkowego kroku, aby ją przekonwertować .
Rafał Dowgird

6
def reverse_string (string): return string [:: - 1]
pi.

4
@pi Myślę, że jeśli ktoś wie wystarczająco dużo, aby zdefiniować odwrotny ciąg znaków, to można pozostawić znak [:: - 1] w kodzie i zadbać o jego znaczenie i poczucie, że jest odpowiedni.
physicsmichael

289

Dekoratorzy

Dekoratory pozwalają na zawinięcie funkcji lub metody w inną funkcję, która może dodawać funkcjonalność, modyfikować argumenty lub wyniki itp. Dekoratory piszesz jeden wiersz powyżej definicji funkcji, zaczynając od znaku „at” (@).

Przykład pokazuje print_argsdekorator, który drukuje argumenty dekorowanej funkcji przed jej wywołaniem:

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
Podczas definiowania dekoratorów polecam dekorowanie dekoratora za pomocą @decorator. Tworzy dekorator, który zachowuje sygnaturę funkcji podczas introspekcji. Więcej informacji tutaj: phyast.pitt.edu/~micheles/python/documentation.html
sirwart

45
Jak to jest ukryta funkcja?
Vetle

50
Cóż, nie jest obecny w najprostszych tutorialach Pythona i natknąłem się na to długo po tym, jak zacząłem używać Pythona. To właśnie nazwałbym ukrytą funkcją, prawie tak samo jak inne najlepsze posty tutaj.
DzinX,

16
vetler, pytania dotyczą „mniej znanych, ale użytecznych funkcji języka programowania Python”. Jak mierzysz „mniej znane, ale przydatne funkcje”? Mam na myśli, w jaki sposób któreś z tych ukrytych funkcji są ukryte?
Johnd

4
@vetler Większość rzeczy tutaj nie jest prawie „ukryta”.
Humphrey Bogart

288

Składnia for ... else (patrz http://docs.python.org/ref/for.html )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

Blok „else” będzie normalnie wykonywany na końcu pętli for, chyba że wywołane zostanie przerwanie.

Powyższy kod można emulować w następujący sposób:

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
Myślę, że składnia for / else jest niezręczna. „Czuje się” tak, jakby klauzula else powinna być wykonana, jeśli ciało pętli nigdy nie zostanie wykonane.
codeape

14
ah. Nigdy tego nie widziałem! Ale muszę powiedzieć, że to trochę mylące. Kto by oczekiwał, że blok else wykona się tylko wtedy, gdy break nigdy tego nie zrobi? Zgadzam się z Codeape: Wygląda na to, że wpisano inną nazwę dla pustych foos.
Daren Thomas

52
wydaje się, że słowem kluczowym powinno być wreszcie, nie więcej
Jiaaro

21
Tyle że w końcu jest już używany w taki sposób, że ten pakiet jest zawsze wykonywany.

7
Na pewno nie powinien być „inny”. Może „wtedy” lub coś, a potem „jeszcze”, gdy pętla nigdy nie została wykonana.
Tor Valamo,

258

Od 2.5 dyktatury mają specjalną metodę, __missing__która jest wywoływana dla brakujących elementów:

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

W collectionswywołanej jest również podklasa dict, defaultdictktóra działa prawie tak samo, ale wywołuje funkcję bez argumentów dla nieistniejących elementów:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

Polecam konwersję takich nagrań na zwykłe nagrania przed przekazaniem ich do funkcji, które nie oczekują takich podklas. Wiele kodów używa d[a_key]i łapie KeyErrors, aby sprawdzić, czy istnieje element, który dodałby nowy element do dykta.


10
Wolę używać setdefault. m = {}; m.setdefault ('foo', 1)
grayger

22
@Grayger miał to na myśli m={}; m.setdefault('foo', []).append(1).
Cristian Ciupitu

1
Są jednak przypadki, w których przekazywanie defaultdict jest bardzo przydatne. Funkcja może na przykład wykonywać iterację po wartości i działa dla niezdefiniowanych kluczy bez dodatkowego kodu, ponieważ domyślnie jest to pusta lista.
Marian

3
defaultdict jest lepszy w niektórych okolicznościach niż setdefault, ponieważ nie tworzy obiektu domyślnego, chyba że brakuje klucza. setdefault tworzy go niezależnie od tego, czy go brakuje, czy nie. Jeśli utworzenie domyślnego obiektu jest drogie, może to być hit wydajnościowy - dostałem przyzwoite przyspieszenie w jednym programie, zmieniając wszystkie wywołania setdefault.
Whatang,

2
defaultdictjest również silniejszy niż setdefaultmetoda w innych przypadkach. Na przykład, dla liczący dd = collections.defaultdict(int) ... dd[k] += 1vs d.setdefault(k, 0) += 1.
Mike Graham,

247

Zamiana wartości w miejscu

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

Prawa strona zadania jest wyrażeniem, które tworzy nową krotkę. Lewa strona zadania natychmiast rozpakowuje, że (bez odniesienia) krotka do nazw ai b.

Po przypisaniu nowa krotka nie jest przywoływana i jest oznaczana do wyrzucania elementów bezużytecznych, a wartości powiązane ai bzostały zamienione.

Jak zauważono w sekcji samouczka poświęconej Pythonowi na temat struktur danych ,

Zauważ, że wielokrotne przypisywanie jest tak naprawdę kombinacją pakowania krotek i rozpakowywania sekwencji.


1
Czy to wykorzystuje więcej prawdziwej pamięci niż tradycyjny sposób? Sądzę, że tak, ponieważ tworzysz krotkę zamiast tylko jednej zmiennej wymiany
Nathan

75
Nie zużywa więcej pamięci. Zużywa mniej ... Właśnie napisałem to w obie strony i zdekompilowałem kod bajtowy ... kompilator optymalizuje, jak można się spodziewać. Wyniki dis pokazały, że konfiguruje zmienne, a następnie ROT_TWOing. ROT_TWO oznacza „zamień dwa najwyższe warianty stosów” ... Właściwie to całkiem sprytny.
królewski

5
Nieumyślnie wskazujesz także inną fajną cechę Pythona, polegającą na tym, że możesz pośrednio stworzyć krotkę przedmiotów, oddzielając je przecinkami.
asmeurer

3
Dana the Sane: przypisanie w Pythonie jest instrukcją, a nie wyrażeniem, więc to wyrażenie byłoby niepoprawne, gdyby = miało wyższy priorytet (tj. Zostało zinterpretowane jako, (b = b), a).
hbn

5
To najmniej ukryta funkcja, którą tutaj przeczytałem. Ładne, ale wyraźnie opisane w każdym tutorialu Python.
Thiago Chaves,

235

Czytelne wyrażenia regularne

W Pythonie możesz podzielić wyrażenie regularne na wiele wierszy, nazwać swoje dopasowania i wstawić komentarze.

Przykładowa pełna składnia (od Dive do Python ):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

Przykładowe dopasowania nazewnictwa (z wyrażenia regularnego HOWTO )

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

Możesz także napisać wyrażeniem regularnym wyrażenie regularne bez użycia re.VERBOSEliterackiej łańcuchowej konkatenacji.

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
Nie wiem, czy naprawdę uważam tę funkcję za Python, większość silników RE ma pełną opcję.
Jeremy Banks,

18
Tak, ale ponieważ nie można tego zrobić w grep lub w większości redaktorów, wiele osób nie wie, że tam jest. Fakt, że inne języki mają równoważną funkcję, nie sprawia, że ​​nie jest to użyteczna i mało znana funkcja Pythona
Mark Baker,

7
W dużym projekcie z dużą ilością zoptymalizowanych wyrażeń regularnych (czytaj: zoptymalizowany dla maszyny, ale nie dla ludzi), ugryzłem punktor i przekonwertowałem je wszystkie na pełną składnię. Teraz wprowadzanie nowych programistów do projektów jest znacznie łatwiejsze. Od teraz egzekwujemy pełne RE dla każdego projektu.
Berk D. Demir

Wolę tylko powiedzieć: setki = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD) itp. Język ma już sposób na nadawanie nazw rzeczom, sposób dodawania komentarzy i sposób łączenia ciągów. Po co używać tutaj specjalnej składni bibliotek do rzeczy, które język ma już doskonale? Wydaje się, że idzie bezpośrednio przeciwko Eplisowi 9. Perlisowi.
Ken

3
@Ken: wyrażenie regularne nie zawsze może znajdować się bezpośrednio w źródle, można je odczytać z ustawień lub pliku konfiguracyjnego. Zezwolenie na komentarze lub dodatkowe białe znaki (dla czytelności) może być bardzo pomocne.

222

Rozpakowywanie argumentów funkcji

Możesz rozpakować listę lub słownik jako argumenty funkcji za pomocą *i **.

Na przykład:

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

Bardzo przydatny skrót, ponieważ listy, krotki i dyktanda są szeroko stosowane jako kontenery.


27
* jest również znany jako operator splat
Gabriel

3
Podoba mi się ta funkcja, ale pylint niestety nie.
Stephen Paulger,

5
Rada pylinta nie jest prawem. Drugi sposób, zastosowanie (na żądanie, arg_seq, arg_map), jest przestarzały od 2.3.
Yann Vernier

1
Rada pylinta może nie być prawem, ale to cholernie dobra rada. Debugowanie kodu, który nadmiernie oddaje się takim rzeczom, jest czystym piekłem. Jak zauważa oryginalny plakat, jest to przydatny skrót .
Andrew

2
Widziałem to raz w kodzie i zastanawiałem się, co to zrobiło. Niestety trudno jest znaleźć w Google „Python **”
Fraser Graham,

205

ROT13 jest prawidłowym kodowaniem kodu źródłowego, jeśli użyto właściwej deklaracji kodowania na górze pliku kodu:

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
Świetny! Zauważ, jak ciągi bajtów są brane dosłownie, ale ciągi Unicode są dekodowane: trycevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
niestety jest usunięty z py3k
mykhal

9
Jest to dobre do obejścia programu antywirusowego.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
To nie ma nic wspólnego z kodowaniem, to po prostu Python napisany w języku walijskim. :-P
Olivier Verdier

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria

183

Tworzenie nowych typów w pełni dynamiczny sposób

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

który jest dokładnie taki sam jak

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

Prawdopodobnie nie najbardziej użyteczna rzecz, ale miło wiedzieć.

Edycja : Stała nazwa nowego typu powinna być NewTypedokładnie taka sama jak w przypadku classinstrukcji.

Edycja : Dostosowano tytuł, aby dokładniej opisać funkcję.


8
Ma to duży potencjał przydatności, np. JIT ORM
Mark Cidade

8
Używam go do generowania klas HTML-Form na podstawie dynamicznych danych wejściowych. Bardzo dobrze!
pi.

15
Uwaga: wszystkie klasy są tworzone w czasie wykonywania. Możesz więc użyć instrukcji „class” w ramach warunku lub funkcji (bardzo przydatne do tworzenia rodzin klas lub klas, które działają jak zamknięcia). Ulepszeniem, jakie niesie „typ”, jest możliwość dokładnego zdefiniowania dynamicznie generowanego zestawu atrybutów (lub baz).
spookylukey

1
Możesz także tworzyć anonimowe typy z pustym ciągiem, takie jak: type ('', (object,), {'x': 'blah'})
bluehavana

3
Może być bardzo przydatny do wstrzykiwania kodu.
Avihu Turzion

179

Menedżery kontekstu i instrukcja „ with

Menedżer kontekstu, wprowadzony w PEP 343 , jest obiektem działającym jako kontekst wykonawczy dla zestawu instrukcji.

Ponieważ funkcja korzysta z nowych słów kluczowych, jest wprowadzana stopniowo: jest dostępna w Pythonie 2.5 poprzez __future__dyrektywę. Python 2.6 i nowsze wersje (w tym Python 3) domyślnie są dostępne.

Często używałem wyrażenia „z”, ponieważ uważam, że jest to bardzo przydatna konstrukcja, oto krótkie demo:

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

To, co dzieje się tutaj za kulisami, polega na tym, że instrukcja „with” wywołuje funkcje specjalne __enter__i __exit__metody na obiekcie pliku. Szczegóły wyjątku są również przekazywane, __exit__jeśli z treści instrukcji with został zgłoszony jakiś wyjątek, umożliwiając tam obsługę wyjątków.

W tym konkretnym przypadku oznacza to, że gwarantuje zamknięcie pliku, gdy wykonanie wykracza poza zakres withpakietu, niezależnie od tego , czy nastąpi to normalnie, czy też zgłoszono wyjątek. Jest to w zasadzie sposób wyodrębnienia wspólnego kodu obsługi wyjątków.

Inne typowe przypadki użycia to blokowanie za pomocą wątków i transakcji w bazie danych.


3
Nie zatwierdziłbym recenzji kodu, która importowała cokolwiek z przyszłości . Funkcje są bardziej urocze niż przydatne, i zwykle kończą się wprowadzeniem nowych użytkowników Pythona.
płatny frajer

6
Tak, takie „słodkie” funkcje, takie jak zagnieżdżone zakresy i generatory, lepiej pozostawić tym, którzy wiedzą, co robią. I każdy, kto chce być kompatybilny z przyszłymi wersjami Pythona. W przypadku zagnieżdżonych zakresów i generatorów „przyszłe wersje” Pythona oznaczają odpowiednio 2.2 i 2.5. W przypadku instrukcji with „przyszłe wersje” języka Python oznaczają 2.6.
Chris B.

10
Może się to wydawać oczywiste, ale w Pythonie 2.6 + nie trzeba już importować z przyszłości . jest teraz słowem kluczowym pierwszej klasy.
fitzgeraldsteele

25
W wersji 2.7 możesz mieć wiele withs:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson

5
@Austin nie mogłem uzyskać tej składni do pracy na 2.7. to jednak zadziałało: with open('filea') as filea, open('fileb') as fileb: ...
wim

168

Słowniki mają metodę get ()

Słowniki mają metodę „get ()”. Jeśli zrobisz d [„klucz”], a klucza go nie ma, otrzymasz wyjątek. Jeśli wykonasz d.get („klucz”), otrzymasz zwrot Brak, jeśli „klucz” nie istnieje. Możesz dodać drugi argument, aby odzyskać ten element zamiast None, np .: d.get ('key', 0).

Doskonale nadaje się do dodawania liczb:

sum[value] = sum.get(value, 0) + 1


39
sprawdź także metodę setdefault.
Daren Thomas

27
również sprawdź klasę collections.defaultdict.
jfs,

8
Jeśli używasz języka Python w wersji 2.7 lub nowszej lub 3.1 lub nowszej, sprawdź klasę Counter w module kolekcji. docs.python.org/library/collections.html#collections.Counter
Elias Zamaria

O rany, przez cały ten czas robiłem get(key, None). Nie miałem pojęcia, że Nonezostał dostarczony domyślnie.
Jordan Reiter

152

Deskryptory

Są magią kryjącą się za całym szeregiem podstawowych funkcji Pythona.

Kiedy używasz dostępu przerywanego do wyszukiwania członka (np. Xy), Python najpierw szuka członka w słowniku instancji. Jeśli nie zostanie znaleziony, szuka go w słowniku klas. Jeśli znajdzie go w słowniku klas, a obiekt zaimplementuje protokół deskryptora, zamiast go zwracać, Python wykonuje go. Deskryptor jest dowolną klasę, która realizuje __get__, __set__lub __delete__metod.

Oto, w jaki sposób zaimplementujesz własną (tylko do odczytu) wersję właściwości za pomocą deskryptorów:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

i użyjesz go tak jak wbudowanej właściwości ():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

Deskryptory są używane w Pythonie do implementacji między innymi właściwości, metod powiązanych, metod statycznych, metod klas i gniazd. Ich zrozumienie ułatwia zrozumienie, dlaczego wiele rzeczy, które wcześniej wyglądały jak „dziwactwa” Pythona, są takie, jakie są.

Raymond Hettinger ma świetny samouczek , który lepiej opisuje je niż ja.


To duplikat dekoratorów, prawda !? ( stackoverflow.com/questions/101268/… )
gecco

2
nie, dekoratory i deskryptory to zupełnie inne rzeczy, chociaż w przykładowym kodzie tworzę dekorator deskryptorów. :)
Nick Johnson

1
Innym sposobem na to jest lambda:foo = property(lambda self: self.__foo)
Pete Peterson

1
@PetePeterson Tak, ale propertysam jest implementowany z deskryptorami, co było celem mojego postu.
Nick Johnson

142

Przypisanie warunkowe

x = 3 if (y == 1) else 2

Robi dokładnie tak, jak to brzmi: „przypisz 3 do x, jeśli y wynosi 1, w przeciwnym razie przypisz 2 do x”. Pamiętaj, że pareny nie są konieczne, ale podoba mi się ich czytelność. Możesz również połączyć go w łańcuch, jeśli masz coś bardziej skomplikowanego:

x = 3 if (y == 1) else 2 if (y == -1) else 1

Chociaż w pewnym momencie idzie to trochę za daleko.

Pamiętaj, że możesz użyć if ... else w dowolnym wyrażeniu. Na przykład:

(func1 if y == 1 else func2)(arg1, arg2) 

Tutaj func1 zostanie wywołany, jeśli y wynosi 1, a func2, w przeciwnym razie. W obu przypadkach odpowiednia funkcja zostanie wywołana z argumentami arg1 i arg2.

Analogicznie obowiązuje również:

x = (class1 if y == 1 else class2)(arg1, arg2)

gdzie klasa 1 i klasa 2 to dwie klasy.


29
Zadanie nie jest częścią specjalną. Równie łatwo możesz zrobić coś takiego: zwróć 3, jeśli (y == 1) else 2.
Brian

25
Ten alternatywny sposób to pierwszy raz, gdy widziałem zaciemnionego Pythona.
Craig McQueen,

3
Kylebrooks: W tym przypadku nie ma zwarcia operatorów logicznych. Będzie oceniać tylko 2, jeśli bool (3) == False.
RoadieRich

15
to kodowanie w stylu wstecznym wprawia mnie w zakłopotanie. coś takiego x = ((y == 1) ? 3 : 2)ma dla mnie więcej sensu
mpen

13
Wydaje mi się, że jest wręcz przeciwnie do @Mark, operatory trójskładnikowe w stylu C zawsze mnie myliły, czy prawą czy środkową stroną jest to, co ocenia się w fałszywym stanie? Wolę trójskładnikową składnię Pythona.
Jeffrey Harris,

141

Doctest : dokumentacja i testy jednostkowe w tym samym czasie.

Przykład wyodrębniony z dokumentacji Python:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
Doctesty są z pewnością fajne, ale naprawdę nie podoba mi się to wszystko, co musisz wpisać, aby sprawdzić, czy coś powinno wzbudzić wyjątek
TM.

60
Doctesty są przereklamowane i zanieczyszczają dokumentację. Jak często testujesz samodzielną funkcję bez setUp ()?
płatny frajer

2
kto mówi, że nie możesz mieć konfiguracji w trakcie testu dokumentów? napisz funkcję, która generuje kontekst i zwraca locals()następnie w twoim doctest do locals().update(setUp())= D
Jiaaro

12
Jeśli samodzielna funkcja wymaga setUp, istnieje duże prawdopodobieństwo, że należy oddzielić od niektórych niepowiązanych elementów lub umieścić w klasie. Przestrzeń nazw klasy doctest może być następnie ponownie użyta w testach metod klasy, więc to trochę jak setUp, tylko SUCHY i czytelny.
Andy Mikhaylenko

4
„Jak często testujesz samodzielną funkcję” - wiele. Uważam, że doktryny często pojawiają się naturalnie w procesie projektowania, kiedy decyduję się na fasady.
Gregg Lind,

138

Nazwane formatowanie

% -formatting pobiera słownik (stosuje również sprawdzanie poprawności% i /% s itp.).

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

A ponieważ locals () jest także słownikiem, możesz po prostu przekazać to jako słownik i mieć% -substitions ze zmiennych lokalnych. Myślę, że jest to niezadowolone, ale upraszcza rzeczy ...

Nowe formatowanie stylu

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
Zostanie wycofany i ostatecznie zastąpiony przez metodę format () łańcucha.
Constantin,

3
Formatowanie nazwane jest bardzo przydatne dla tłumaczy, którzy zwykle widzą ciąg formatu bez nazw zmiennych dla kontekstu
pixelbeat

2
Wygląda na to, że działa w Pythonie 3.0.1 (potrzebny do dodania nawiasów wokół wywołania drukowania).
Pasi Savolainen,

9
hash , hę? Widzę skąd pochodzisz.
shylent

11
Formatowanie% s nie zostanie wycofane. str.format () jest z pewnością bardziej pytoniczny, jednak w rzeczywistości jest 10 razy wolniejszy w przypadku prostej zamiany łańcucha. Wierzę, że formatowanie% s jest nadal najlepszą praktyką.
Kenneth Reitz

132

Aby dodać więcej modułów Pythona (szczególnie zewnętrznych), większość ludzi wydaje się używać zmiennych środowiskowych PYTHONPATH lub dodaje dowiązania symboliczne lub katalogi w swoich katalogach pakietów stron. Innym sposobem jest użycie plików * .pth. Oto oficjalne wyjaśnienie doktora Pythona:

„Najwygodniejszym sposobem [modyfikacji ścieżki wyszukiwania Pythona] jest dodanie pliku konfiguracji ścieżki do katalogu, który już znajduje się na ścieżce Pythona, zwykle do katalogu ... / site-packages /. Pliki konfiguracji ścieżki mają rozszerzenie .pth , a każda linia musi zawierać jedną ścieżkę, która zostanie dołączona do sys.path. (Ponieważ nowe ścieżki są dołączone do sys.path, moduły w dodanych katalogach nie zastąpią standardowych modułów. Oznacza to, że nie można użyć tego mechanizmu do instalowania stałych wersji standardowych modułów.) ”


1
Nigdy nie nawiązałem połączenia między tym plikiem .pth w katalogu site-packages z setuptools a tym pomysłem. niesamowite.
dave paola

122

Wyjątek od pozostałych klauzul:

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

Użycie klauzuli else jest lepsze niż dodanie dodatkowego kodu do klauzuli try, ponieważ pozwala uniknąć przypadkowego wyłapania wyjątku, który nie został zgłoszony przez kod chroniony przez instrukcję try ....

Zobacz http://docs.python.org/tut/node10.html


8
+1 to jest niesamowite. Jeśli blok try zostanie wykonany bez wprowadzania bloków wyjątków, wówczas zostanie wprowadzony blok else. I wtedy oczywiście wykonywany jest wreszcie blok
inspectorG4dget

W końcu rozumiem, dlaczego istnieje „inne”! Dzięki.
taynaron,

Bardziej sensowne byłoby kontynuowanie, ale myślę, że jest już zajęte;)
Paweł Prażak

Zauważ, że na starszych wersjach Python2 nie możesz mieć obu innych: i wreszcie: klauzul dotyczących tej samej try: block
Kevin Horn

1
@ Paweł Prażak, jak wspomniał Kevin Horn, ta składnia została wprowadzona po początkowej wersji Pythona, a dodawanie nowych zastrzeżonych słów kluczowych do istniejącego języka jest zawsze problematyczne. Dlatego istniejące słowo kluczowe jest zwykle ponownie używane (por. „Auto” w najnowszym standardzie C ++).
Constantin,

114

Ponowne zgłaszanie wyjątków :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

Instrukcja „podbicia” bez argumentów w module obsługi błędów mówi Pythonowi, aby ponownie podniósł wyjątek z nienaruszonym oryginalnym śledzeniem , pozwalając powiedzieć „och, przepraszam, przepraszam, nie chciałem tego złapać, przepraszam, przepraszam. „

Jeśli chcesz drukować, przechowywać lub bawić się przy użyciu oryginalnego traceback, możesz go uzyskać za pomocą sys.exc_info (), a drukowanie w taki sposób, jak w Pythonie, odbywa się za pomocą modułu „traceback”.


Przepraszamy, ale jest to dobrze znana i powszechna funkcja prawie wszystkich języków.
Lucas S.

6
Zanotuj kursywę. Niektóre osoby zrobią raise ezamiast tego, co nie zachowuje oryginalnego śledzenia.
habnabit

12
Może bardziej magiczny, exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]jest to równoważne, ale możesz zmienić te wartości (np. Zmienić typ wyjątku lub komunikat)
ianb

3
@Lucas S. Cóż, nie wiedziałem o tym i cieszę się, że tu jest napisane.
e-satis

Być może pokazuję tutaj moją młodość, ale zawsze bez problemu korzystałem ze składni Pythona 3 w Pythonie 2.7
wim

106

Główne wiadomości :)

import this
# btw look at this module's source :)

Odszyfrowane :

Zen of Python, autor: Tim Peters

Piękne jest lepsze niż brzydkie.
Jawne jest lepsze niż niejawne.
Prosty jest lepszy niż złożony.
Złożony jest lepszy niż skomplikowany.
Mieszkanie jest lepsze niż zagnieżdżone.
Rzadki jest lepszy niż gęsty.
Liczy się czytelność.
Przypadki specjalne nie są wystarczająco wyjątkowe, aby złamać zasady.
Chociaż praktyczność przewyższa czystość.
Błędy nigdy nie powinny przejść bezgłośnie.
Chyba że wyraźnie uciszony.
W obliczu dwuznaczności odmów pokusy zgadywania. Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.
Chociaż na początku taki sposób może nie być oczywisty, chyba że jesteś Holendrem.
Teraz jest lepiej niż nigdy.
Chociaż nigdy nie jest często lepszy niżwłaśnie teraz.
Jeśli implementacja jest trudna do wyjaśnienia, to zły pomysł.
Jeśli implementacja jest łatwa do wyjaśnienia, może to być dobry pomysł.
Przestrzenie nazw to jeden świetny pomysł - zróbmy więcej z nich!


1
Masz pojęcie, dlaczego źródło zostało zaszyfrowane w ten sposób? Czy to tylko dla zabawy, czy był jakiś inny powód?
MiniQuark,

42
sposób, w jaki napisane jest źródło, jest sprzeczny z zen!
hasen


2
Zaktualizowałem mój /usr/lib/python2.6/this.py zastępując stary kod tym kodem print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))i wygląda teraz znacznie lepiej !! :-D
fortran

2

105

Wypełnienie zakładki interaktywnego interpretera

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

Będziesz także musiał ustawić zmienną środowiskową PYTHONSTARTUP.


2
To bardzo przydatna funkcja. Tyle więc mam prosty skrypt, aby ją włączyć (plus kilka innych ulepszeń introspekcji): pixelbeat.org/scripts/inpy
pixelbeat

43
IPython daje ci to plus mnóstwo innych schludnych rzeczy
akaihola

Byłoby to bardziej przydatne w pytaniu pdb niż w zwykłym pytaniu python (ponieważ IPython i tak służy temu celowi). Nie wydaje się to jednak działać po wyświetleniu monitu pdb, prawdopodobnie dlatego, że pdb wiąże się z tabulatorem (co jest mniej przydatne). Próbowałem wywołać parse_and_bind () w wierszu polecenia pdb, ale nadal nie działało. Alternatywą dla otrzymania polecenia pdb z IPython jest więcej pracy, więc zwykle go nie używam.
haridsv

2
@haridsv - easy_install ipdb- wtedy możesz użyćimport ipdb; ipdb.set_trace()
Doug Harris

1
Na OSX [i wyobrażam sobie inne systemy korzystające z libedit] musisz to zrobićreadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

Wyjaśnienia list zagnieżdżonych i wyrażenia generatorów:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

Mogą one zastąpić duże fragmenty kodu zagnieżdżonej pętli.


„for j in range (i)” - czy to literówka? Zwykle potrzebujesz stałych zakresów dla i i j. Jeśli masz dostęp do tablicy 2d, stracisz połowę swoich elementów.
Peter Gibson

W tym przykładzie nie uzyskuję dostępu do żadnych tablic. Jedynym celem tego kodu jest pokazanie, że wyrażenia z wewnętrznych zakresów mogą uzyskać dostęp do wyrażeń z zewnętrznych. Produktem ubocznym jest lista par (x, y), takich jak 4> x> y> 0.
Rafał Dowgird

2
coś w rodzaju podwójnej integracji w rachunku różniczkowym lub podwójnego sumowania.
Yoo

22
Kluczową kwestią do zapamiętania w tym miejscu (co zajęło mi dużo czasu) jest to, że kolejność forinstrukcji ma być zapisana w takiej kolejności, w jakiej można oczekiwać, że zostaną zapisane w standardowej pętli for, od zewnątrz do wewnątrz.
sykora

2
Aby dodać do komentarza sykora: wyobraź sobie, że zaczynasz ze stosem fors i ifsi yield xwewnątrz. Aby przekonwertować to na wyrażenie generatora, xnajpierw przenieś , usuń wszystkie dwukropki (i yield) i otocz wszystko w nawiasach. Aby zamiast tego zrozumieć listę, zamień zewnętrzne pareny na nawiasy kwadratowe.
Ken Arnold

91

Przeciążenie operatora dla setwbudowanego:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

Więcej szczegółów ze standardowego odniesienia do biblioteki: Ustaw typy


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.