Les traits cachés de Python [fermé]

quelles sont les fonctionnalités moins connues mais utiles du langage de programmation Python?

  • essayez de limiter les réponses à Python core.
  • une caractéristique par réponse.
  • donne un exemple et une brève description de la fonctionnalité, pas seulement un lien vers la documentation.
  • étiqueter la caractéristique en utilisant un titre comme première ligne.

Liens rapides vers les réponses:

1420
demandé sur compie 2008-09-19 15:50:36

30 réponses

opérateurs de comparaison chaînage:

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

dans le cas où vous pensez qu'il fait 1 < x , qui sort comme True , et puis comparer True < 10 , qui est aussi True , alors non, ce n'est vraiment pas ce qui se passe (voir le dernier exemple.) Cela se traduit en fait par 1 < x and x < 10 , et x < 10 and 10 < x * 10 and x*10 < 100 , mais avec moins de Dactylographie et chaque terme n'est évalué qu'une seule fois.

741
répondu Thomas Wouters 2012-01-18 16:23:50

obtenez l'arbre d'analyse Python regex pour déboguer votre regex.

les expressions régulières sont une grande caractéristique de python, mais les déboguer peut être pénible, et il est trop facile d'obtenir un regex erroné.

heureusement, python peut imprimer l'arbre regex parse, en passant le drapeau caché expérimental et non documenté re.DEBUG (en fait, 128) à 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

une fois que vous comprenez la syntaxe, vous pouvez repérer vos erreurs. On y voit que j'ai oublié d'échapper au [] dans [/font] .

bien sûr, vous pouvez le combiner avec tous les drapeaux que vous voulez, comme commenté regexes:

>>> 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)
512
répondu BatchyX 2012-03-06 14:28:47

énumérer

envelopper un itérable avec enumerate et il donnera l'article avec son index.

par exemple:


>>> 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
>>>

, les Références:

460
répondu Dave 2010-07-14 08:39:06

la Création de générateurs d'objets

si vous écrivez

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

vous pouvez sortir le générateur et l'affecter à x. Maintenant, cela signifie que vous pouvez faire

for n in x:

L'avantage, c'est que vous n'avez pas besoin de stockage intermédiaire, dont vous aurez besoin si vous l'avez fait

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

Dans certains cas, cela peut conduire à vitesse importante.

vous pouvez ajoutez de nombreuses instructions if à la fin du générateur, en reproduisant essentiellement les boucles emboîtées:

>>> 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)
419
répondu freespace 2009-11-23 14:36:53

iter() peut prendre un callable argument

par exemple:

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

la fonction iter(callable, until_value) appelle à plusieurs reprises callable et donne son résultat jusqu'à ce que until_value soit retourné.

353
répondu mbac32768 2010-05-28 15:06:07

soyez prudent avec les arguments par défaut mutables

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

à la place, vous devriez utiliser une valeur sentinelle indiquant "non indiqué" et remplacer par le mutable que vous voulez par défaut:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]
339
répondu Jason Baker 2010-07-14 02:12:47

l'Envoi de valeurs dans le générateur de fonctions . Par exemple, ayant cette fonction:

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

vous pouvez:

>>> 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
317
répondu Rafał Dowgird 2011-04-10 21:54:30

si vous n'aimez pas utiliser whitespace pour dénoter les portées, vous pouvez utiliser le C-style {} en émettant:

from __future__ import braces
314
répondu eduffy 2008-09-21 22:01:53

L'étape de l'argument dans la tranche des opérateurs. Par exemple:

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

le cas spécial x[::-1] est un idiome utile pour "X inversé".

>>> a[::-1]
[5,4,3,2,1]
305
répondu Rafał Dowgird 2008-09-19 13:33:42

décorateurs

décorateurs permettent d'envelopper une fonction ou une méthode dans une autre fonction qui peut ajouter des fonctionnalités, modifier des arguments ou des résultats, etc. Vous écrivez décorateurs une ligne au-dessus de la définition de la fonction, en commençant par un signe "at" (@).

exemple montre un print_args décorateur qui imprime les arguments de la fonction décorée avant de l'appeler:

>>> 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
289
répondu DzinX 2010-04-15 16:18:11

Le pour les...syntaxe else (voir ) http://docs.python.org/ref/for.html )

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

le bloc "else" sera normalement exécuté à la fin de la boucle for, à moins que la coupure ne soit appelée.

le code ci-dessus pourrait être émulé comme suit:

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")
288
répondu rlerallut 2011-04-10 21:57:34

à partir de 2.5 dicts ont une méthode spéciale __missing__ qui est invoquée pour les éléments manquants:

>>> 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]}

il y a aussi une sous-classe de dict dans collections appelée defaultdict qui fait à peu près la même chose mais appelle une fonction sans arguments pour les éléments non existants:

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

je recommande de convertir de tels dicts en dicts réguliers avant de les passer à des fonctions qui ne s'attendent pas à de telles sous-classes. Beaucoup d'utilisations de code d[a_key] et saisit des erreurs-clés pour vérifier s'il existe un élément qui ajouterait un nouvel élément au dict.

258
répondu Armin Ronacher 2008-09-21 21:54:12

échange de valeurs en place

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

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

le côté droit de la cession est une expression qui crée un nouveau tuple. Le côté gauche de la cession déballe immédiatement ce tuple (non référencé) des noms a et b .

après la cession, le nouveau tuple n'est pas référencé et marqué pour la collecte des ordures, et les valeurs liées à a et b ont été échanger.

comme noté dans la section tutoriel Python sur les structures de données ,

notez que l'assignation multiple est en fait juste une combinaison d'empaquetage tuple et de déballage séquentiel.

247
répondu Lucas S. 2010-04-06 01:40:30

expressions régulières déchiffrables

en Python vous pouvez diviser une expression régulière sur plusieurs lignes, nommer vos correspondances et insérer des commentaires.

exemple de syntaxe verbeuse (de plongée en 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)

exemple de correspondance de noms (de Regular Expression HOWTO )

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

vous pouvez aussi verbosely Ecrire un regex sans utiliser re.VERBOSE grâce à la chaîne concaténation littérale.

>>> 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})$"
235
répondu user18044 2012-08-04 01:54:45

argument de fonction déballage

vous pouvez déballer une liste ou un dictionnaire comme arguments de fonction en utilisant * et ** .

par exemple:

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)

raccourci très utile car les listes, tuples et dicts sont largement utilisés comme conteneurs.

222
répondu e-satis 2010-06-23 12:13:20

ROT13 est un encodage valide pour le code source, lorsque vous utilisez la déclaration de codage de droite en haut du fichier de code:

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

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")
205
répondu André 2009-06-21 20:35:44

la Création de nouveaux types dans une dynamique de manière

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

qui est exactement le même que

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

Probablement pas la chose la plus utile, mais bon à savoir.

Edit : nom fixe du nouveau type, devrait être NewType pour être la même chose exacte qu'avec class déclaration.

Modifier : Corrigé le titre pour plus de précision décrire la fonctionnalité.

183
répondu Torsten Marek 2012-01-18 16:23:08

Contexte, les gestionnaires et les with " Déclaration

introduit dans PEP 343 , un context manager est un objet qui agit comme un contexte d'exécution pour une suite d'énoncés.

puisque la fonctionnalité utilise de nouveaux mots-clés, elle est introduite progressivement: elle est disponible en python 2.5 via la directive __future__ . Python 2.6 et au-dessus (y compris Python 3), Il est disponible par défaut.

j'ai utilisé le "avec" statement beaucoup parce que je pense que c'est une construction très utile, voici une démo rapide:

from __future__ import with_statement

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

ce qui se passe ici dans les coulisses, c'est que les méthodes avec" statement appellent les méthodes spéciales __enter__ et __exit__ sur l'objet file. Détails de l'Exception sont également passés __exit__ si tout exception a été déclenchée à partir de l'instruction du corps, permettant la gestion des exceptions pour y arriver.

ce que cela fait pour vous dans ce cas particulier, c'est qu'il garantit que le dossier est clos lorsque l'exécution tombe en dehors du champ d'application de la suite with , peu importe si cela se produit normalement ou si une exception a été jetée. Il s'agit essentiellement d'une manière de supprimer le code de traitement d'exception commun.

autres cas d'usage courant: verrouillage avec des threads et des transactions de base de données.

179
répondu Ycros 2010-04-06 02:02:02

les dictionnaires ont une méthode get ()

Les dictionnaires

ont une méthode " get ()". Si vous faites d['key'] et que key n'est pas là, vous obtenez une exception. Si vous ne d.get('key'), vous obtenez en retour Aucun si la " clé " n'est pas là. Vous pouvez ajouter un deuxième argument pour récupérer cet élément au lieu de None, par exemple: D. get ('key', 0).

c'est génial pour des choses comme additionner des nombres:

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

168
répondu Rory 2012-01-18 16:22:41

descripteurs

ils sont la magie derrière tout un tas de fonctionnalités Python.

lorsque vous utilisez un accès en pointillé pour rechercher un membre (par exemple, X. y), Python cherche d'abord le membre dans le dictionnaire d'instance. Si elle ne l'est pas, il le cherche dans la classe dictionnaire. Si il la trouve dans la classe dictionnaire, et l'objet implémente le protocole descripteur, au lieu de simplement retourner, Python exécute. Un descripteur est une classe qui met en œuvre les méthodes __get__ , __set__ , ou __delete__ .

Voici comment vous implémentez votre propre version (en lecture seule) de la propriété en utilisant des descripteurs:

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)

et que vous souhaitez utiliser comme un construit-dans la propriété():

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

les descripteurs sont utilisés en Python pour implémenter des propriétés, des méthodes liées, des méthodes statiques, des méthodes de classe et des fentes, entre autres choses. Comprendre le rend facile de voir pourquoi beaucoup de choses qui auparavant ressemblaient à des "excentricités" Python sont comme elles sont.

Raymond Hettinger a un excellent tutoriel qui fait un bien meilleur travail de les décrire que moi.

152
répondu Nick Johnson 2012-01-18 16:22:21

Cession Conditionnelle

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

C'est exactement ce que cela ressemble: "attribuer 3 x si y est 1, sinon l'affectation de 2 à x". Notez que les parens ne sont pas nécessaires, mais je les aime pour la lisibilité. Vous pouvez aussi l'enchaîner si vous avez quelque chose de plus compliqué:

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

bien qu'à un certain point, il va un peu trop loin.

Notez que vous pouvez utiliser si ... d'autre, dans tout expression. Par exemple:

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

ici func1 sera appelé si y est 1 et func2, sinon. Dans les deux cas, la fonction correspondante sera appelée avec les arguments arg1 et arg2.

de la même manière, ce qui suit est également valable:

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

où les catégories 1 et 2 sont deux classes.

142
répondu tghw 2012-01-12 23:37:02

Doctest : documentation et essais unitaires en même temps.

exemple extrait de la documentation 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()
141
répondu Pierre-Jean Coudert 2012-01-18 16:18:31

mise en forme Nommée

% - formatage prend un dictionnaire(s'applique également %i / %s etc. validation.)

>>> 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.

et comme locals() est aussi un dictionnaire, vous pouvez simplement passer cela comme un dict et avoir des substitutions de % à partir de vos variables locales. Je pense que c'est mal vu, mais simplifie les choses..

Nouvelle Mise En Forme Du Style

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))
138
répondu Pasi Savolainen 2012-01-18 16:20:44

pour ajouter plus de modules python (en particulier des modules tiers), la plupart des gens semblent utiliser des variables D'environnement PYTHONPATH ou ils ajoutent des liens symboliques ou des répertoires dans leurs répertoires site-paquets. Une autre façon consiste à utiliser *.la pth fichiers. Voici l'explication officielle de python doc:

"le moyen Le plus pratique [modifier le chemin de recherche de python] est d'ajouter un chemin fichier de configuration vers un répertoire c'est déjà sur Python chemin, généralement, à la .../ site-packages/ répertoire. Fichiers de configuration des chemins ont une extension .pth, et chacun ligne doit contenir un seul chemin qui sera ajouté à sys.chemin. (Parce les nouveaux chemins sont ajoutés à sys.chemin, modules dans le Ajouté les répertoires ne supplantent pas la norme module. Cela signifie que vous ne pouvez pas utiliser cette mécanisme d'installation fixe versions de modules standard.) "

132
répondu dgrant 2008-09-22 08:43:11

Exception else clause:

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

l'utilisation de la clause else est préférable à l'ajout de code supplémentaire à la clause try parce qu'elle évite d'attraper accidentellement une exception qui n'a pas été soulevée par le code étant protégé par l'essai ... sauf instruction.

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

122
répondu Constantin 2010-09-22 05:55:08

Re-déclenchement d'exceptions :

# 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)

la déclaration' raise 'sans argument dans un gestionnaire d'erreurs dit à Python de relancer l'exception avec le traceback original intact , vous permettant de dire " Oh, désolé, désolé, Je ne voulais pas attraper ça, désolé, désolé."

si vous souhaitez imprimer, stocker ou jouer avec le traceback original, vous pouvez l'obtenir avec sys.exc_info(), et l'impression comme Python le ferait avec le module' traceback'.

114
répondu Thomas Wouters 2010-04-06 02:08:56

messages principaux:)

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

:

Le Zen de Python, par Tim Peters

beau est mieux que laid.

Explicite est mieux qu'implicites.

Simple vaut mieux que complexe.

Complexe est mieux que compliqué.

L'appartement est mieux que imbriqués.

Clairsemé vaut mieux que dense.

La lisibilité compte.

Les cas spéciaux ne sont pas assez spéciaux pour enfreindre les règles.

Bien que la praticité bat la pureté.

Les erreurs ne doivent jamais passer silencieusement.

Sauf s'il est explicitement réduit au silence.

Face à l'ambiguïté, refusez la tentation de deviner. Il devrait y avoir un, et de préférence seulement une façon évidente de le faire.

Bien que ce ne soit pas évident au début, sauf si vous êtes Hollandais.

Est maintenant mieux que jamais.

Bien que n'est jamais souvent mieux que droit maintenant.

Si l'implémentation est difficile à expliquer, c'est une mauvaise idée.

Si l' la mise en œuvre est facile à expliquer, il peut être une bonne idée.

Les Namespaces sont une excellente idée -- faisons-en plus!

106
répondu Mark 2009-10-20 07:08:14

Interactive Interprète Onglet Achèvement

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()

vous devrez également définir une variable d'environnement PYTHONSTARTUP.

105
répondu mjard 2008-10-03 18:38:15

liste imbriquée compréhensions et expressions génératrices:

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

ceux-ci peuvent remplacer d'énormes morceaux de code à boucle imbriquée.

91
répondu Rafał Dowgird 2008-09-19 12:45:44

surcharge de L'opérateur pour le set builtin:

>>> 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}

plus de détails de la bibliothèque standard référence: Set Types

91
répondu Kiv 2012-02-03 18:46:54