Que signifient les backticks pour l'interpréteur python: `num`

87

Je joue avec les compréhensions de listes et je suis tombé sur ce petit extrait sur un autre site:

return ''.join([`num` for num in xrange(loop_count)])

J'ai passé quelques minutes à essayer de reproduire la fonction (en tapant) avant de réaliser que le `num`bit la cassait.

Que fait le fait d'inclure une déclaration dans ces caractères? D'après ce que je peux voir, c'est l'équivalent de str (num). Mais quand je l'ai chronométré:

return ''.join([str(num) for num in xrange(10000000)])

Cela prend 4.09s alors que:

return ''.join([`num` for num in xrange(10000000)])

prend 2,43 s.

Les deux donnent des résultats identiques mais l'un est beaucoup plus lent. Qu'est-ce qui se passe ici?

EDIT: Bizarrement ... repr()donne des résultats légèrement plus lents que `num`. 2,99 contre 2,43. Utilisation de Python 2.6 (je n'ai pas encore essayé la version 3.0).

Dominique Bou-Samra
la source
8
Après avoir lu "un autre site" sur skymind.com/~ocrow/python_string , j'avais une question similaire et j'ai trouvé cette page. Belle question et bonne réponse :)
netvope

Réponses:

122

Les backticks sont un alias obsolète pour repr(). Ne les utilisez plus, la syntaxe a été supprimée dans Python 3.0.

Utiliser des backticks semble être plus rapide que d'utiliser repr(num)ou num.__repr__()en version 2.x. Je suppose que c'est parce qu'une recherche supplémentaire dans le dictionnaire est nécessaire dans l'espace de noms global (pour repr) ou dans l'espace de noms de l'objet (pour __repr__), respectivement.


L'utilisation du dismodule prouve mon hypothèse:

def f1(a):
    return repr(a)

def f2(a):
    return a.__repr__()

def f3(a):
    return `a`

Démontage montre:

>>> import dis
>>> dis.dis(f1)
  3           0 LOAD_GLOBAL              0 (repr)
              3 LOAD_FAST                0 (a)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE
>>> dis.dis(f2)
  6           0 LOAD_FAST                0 (a)
              3 LOAD_ATTR                0 (__repr__)
              6 CALL_FUNCTION            0
              9 RETURN_VALUE        
>>> dis.dis(f3)
  9           0 LOAD_FAST                0 (a)
              3 UNARY_CONVERT       
              4 RETURN_VALUE   

f1implique une recherche globale pour repr, f2une recherche d'attribut pour __repr__, tandis que l'opérateur backtick est implémenté dans un opcode séparé. Comme il n'y a pas de surcharge pour la recherche dans le dictionnaire ( LOAD_GLOBAL/ LOAD_ATTR) ni pour les appels de fonction ( CALL_FUNCTION), les backticks sont plus rapides.

Je suppose que les gens de Python ont décidé qu'avoir une opération de bas niveau séparée pour repr()ne valait pas la peine, et avoir à la fois repr()et des backticks viole le principe

"Il devrait y avoir une - et de préférence une seule - façon évidente de le faire"

donc la fonctionnalité a été supprimée dans Python 3.0.

Ferdinand Beyer
la source
Je voulais savoir comment remplacer les backticks par un appel de fonction, mais il semble que ce ne soit pas possible, ou est-ce?
Jiri
2
Utilisez repr () au lieu de backticks. Les backticks sont une syntaxe dépréciée pour repr () come 3.0. En fait, je préfère l'apparence des backticks plutôt que d'appeler UNE AUTRE fonction.
Dominic Bou-Samra
8
La raison pour laquelle les backticks sont obsolètes est aussi à cause du caractère `lui-même; il peut être difficile de taper (sur certains claviers), difficile de voir ce que c'est, difficile à imprimer correctement dans les livres Python. Etc.
u0b34a0f6ae
4
@ kaizer.se: Merci de l'avoir signalé. C'est probablement la raison principale de la suppression des backticks, voir la déclaration Guidos dans les archives de la liste de diffusion: mail.python.org/pipermail/python-ideas/2007-January/000054.html
Ferdinand Beyer
La question initiale qui a été posée était parce que je ne pouvais pas trouver de backticks sur mon clavier;) Sous le tilde, il semble après googler.
Dominic Bou-Samra
10

Les citations Backtick ne sont généralement pas utiles et ont disparu dans Python 3.

Pour ce que ça vaut, ceci:

''.join(map(repr, xrange(10000000)))

est légèrement plus rapide que la version backtick pour moi. Mais s'inquiéter à ce sujet est probablement une optimisation prématurée.

bobince
la source
2
Pourquoi faire un pas en arrière et utiliser la carte au lieu des compréhensions de liste / itérateur?
nikow
4
En fait, timeitdonne des résultats plus rapides pour ''.join(map(repr, xrange(0, 1000000)))que pour ''.join([repr(i) for i in xrange(0, 1000000)])(encore pire pour ''.join( (repr(i) for i in xrange(0, 1000000)) )). C'est un peu décevant ;-)
RedGlyph
8
Le résultat de bobince ne me surprend pas. En règle générale, les boucles implicites en Python sont plus rapides que les boucles explicites, souvent considérablement plus rapides. mapest implémenté en C, en utilisant une boucle C, qui est beaucoup plus rapide qu'une boucle Python exécutée dans la machine virtuelle.
Ferdinand Beyer
7
Pas étonné non plus, c'est juste dommage pour la réputation des compréhensions de liste (avec un hit de 30% dans cet exemple). Mais je préfère avoir un code clair plutôt que rapide, à moins que ce ne soit vraiment important, donc pas grand-chose ici. Cela étant dit, la fonction map () ne me paraît pas floue, LC est parfois surfaite.
RedGlyph
4
mapme semble parfaitement clair et concis, et je ne connais même pas Python.
Zenexer
1

Je suppose que numcela ne définit pas la méthode __str__(), il str()faut donc faire une deuxième recherche __repr__.

Les backticks recherchent directement __repr__. Si c'est vrai, utiliser à la repr()place des backticks devrait vous donner les mêmes résultats.

Aaron Digulla
la source