54 votes

Modèle Django et l'astuce des locaux

Les livres de django donnent l'astuce locale afin d'éviter de taper une longue liste de paramètres comme dictionnaire de contexte.

http://www.djangobook.com/en/2.0/chapter04/

Exemple :

def current_datetime(request):
    dt_now = datetime.datetime.now()
    return render_to_response('current.html', {'dt_now': dt_now})

devient :

def current_datetime(request):
    dt_now = datetime.datetime.now()
    return render_to_response('current.html', locals())

Il le recommande aux programmeurs paresseux, mais signale une surcharge qui peut avoir un impact sur les performances.

J'aimerais savoir si certains d'entre vous utilisent l'astuce des locaux sur des applications réelles. La recommandez-vous ou s'agit-il d'une mauvaise pratique ?

81voto

Alex Martelli Points 330805

Je n'aime pas les répétitions. Je pense que le principe "DRY", "Don't Repeat Yourself", est un principe clé de la programmation. Par conséquent, j'ai effectivement utilisé locals() dans des situations similaires. Le rendu des modèles de Django est loin d'être la seule situation de ce type : le cas général est " une fonction ou un opérateur qui accepte un dict, mais qui ne se soucie pas que le dict contienne des entrées supplémentaires ". (Par exemple, le formatage ordinaire des chaînes de caractères en Python est un autre cas de ce genre).

Cependant, il existe un principe opposé : les programmes devraient être compréhensibles d'une manière aussi localisée que possible -- cela facilite la maintenance et le remaniement (car cela évite d'avoir à étudier d'autres fichiers pour vérifier quels remaniements sont acceptables). Cela suggère, pour le locals() que c'est OK si le modèle (ou le format de chaîne de caractères, etc.) est un littéral local (un cas rare où seules quelques variables sont probablement utilisées et où, par conséquent, le format de chaîne de caractères n'est pas utilisé). locals() n'est pas une victoire énorme !-), mais problématique dans le cas normal où le modèle se trouve dans un fichier différent.

Ainsi, en utilisant locals() dans la plupart des cas, cela entrave sérieusement le remaniement. Dans presque toutes les situations en Python, les variables locales et leurs noms peuvent être librement modifiés dans le cadre d'un remaniement local, puisqu'ils n'ont pas d'effet "visible de l'extérieur"... mais l'utilisation de la fonction locals() casse cela -- soudainement vous ne pouvez plus renommer une variable avec un nom différent offrant une meilleure clarté, refactoriser le flux de code d'une manière qui supprime le besoin d'une variable, etc, etc, sans étudier à chaque fois un fichier template séparé pour vérifier si l'ancien nom pourrait ne pas être nécessaire (et éventuellement éditer le fichier template, ce qui peut être non trivial, par exemple s'il est maintenu dans plusieurs langues naturelles différentes pour des raisons d'i18n/L10n).

Par conséquent, en plus de la question secondaire de la performance, il existe une forte pression. contre en utilisant locals() dans un code "sérieux", "de production" -- un code qui nécessite une maintenance à long terme et donc un remaniement et une localisation faciles. Ainsi, lorsque je "programme du mieux que je peux", plutôt que de "faire des économies", je suis conscient que je dois éviter de locals() .

Les valeurs que vous voulez avoir dans le contexte dans lequel le modèle est rendu ne sont pas nécessairement "naturellement" disponibles sous forme de noms nus locaux, après tout ; peut-être que certaines ou beaucoup d'entre elles sont des résultats de calculs, des éléments de listes ou de dictionnaires, et ainsi de suite. Dans ce cas, la tentation de "couper les coins ronds" avec des noms nus est grande. locals() est plus facile à éviter si vous accumulez ces valeurs dans un dictionnaire approprié plutôt que de leur attribuer des noms locaux nus.

Ce n'est pas le compromis le plus facile, car deux bons principes (éviter la répétition et avoir une bonne localité) s'opposent inévitablement - donc, bonne question ! Et ce n'est pas une question qui se prête à des réponses tranchées, noires ou blanches, c'est pourquoi j'ai essayé de développer les deux côtés. En fin de compte, je pense que c'est l'un de ces aspects de "style" où une équipe de programmation serait bien avisée d'adopter une directive de style uniforme pour l'équipe et de s'y tenir -- au moins, cela supprime le besoin de prendre une décision encore et encore chaque fois que le problème se pose, et produit une base de code plus homogène (et donc maintenable). [[Je dois avouer que ce point spécifique n'a jamais été explicitement abordé dans les directives de style des équipes auxquelles j'ai participé, bien que beaucoup d'autres l'aient fait!-)]].

3 votes

+1 pour plusieurs raisons. L'une d'entre elles m'a immédiatement frappé si vous avez un groupe de processeurs contextuels par défaut qui fournissent certaines valeurs standard à toutes vos vues. C'est déjà assez grave si vous surchargez accidentellement l'un d'entre eux avec une valeur qui a été explicitement passée au modèle, mais vous vous arracherez les cheveux si c'était un écrasement fortuit parce qu'il y a une valeur local() avec le même nom que le "nom global" du processeur contextuel.

28voto

niels Points 427

J'ai souvent pensé à faire ce qui suit, mais je ne suis pas sûr que cela soit vraiment utile.

class MyStruct(object):
     pass

def my_view(request, id):
    c = MyStruct()
    c.customer = ..
    c.invoice = ..
    c.date = ..
    return render_to_response('xxx,html',c.__dict__)

8 votes

Oh mon dieu ! - C'est génial !

1 votes

Il suffit d'ajouter ce commentaire à la définition de la classe : # Les attributs seront définis à l'extérieur init pylint : disable=W0201

3 votes

Pourquoi ne pas utiliser une simple dictée ?

12voto

Daniel Roseman Points 199743

Je n'aime pas ça, personnellement. Il n'y a probablement aucune raison à ma préférence, si ce n'est le vieux dicton de Python "Explicit is better than implicit". J'aime savoir exactement ce qui entre dans mes modèles.

0 votes

Moi aussi, je n'aime pas ça, c'est trop sec et si un bug survient, on ne peut pas bien le déboguer

3voto

Dave Webb Points 90034

Je l'ai utilisé sans aucun problème (jusqu'à présent !).

Je n'aime pas particulièrement la dactylographie, c'est pourquoi je l'aime bien. Code comme

'customer' : customer,
'invoice' : invoice,
'date' : date

Cela me semble ridicule et si je peux l'éviter, je le ferai. L'une des raisons pour lesquelles j'aime Python est l'absence de texte passe-partout (bien que ce ne soit pas vraiment un texte passe-partout mais il y ressemble).

2voto

Tom van Enckevort Points 3462

Je suppose que cela dépend du nombre de variables locales que vous définissez dans votre fonction.

S'il correspond exactement au nombre que vous voulez renvoyer à votre modèle, ou si les variables "supplémentaires" sont des structures simples comme des entiers ou des booléens, alors je pense qu'il n'y a pas de raison de les renvoyer explicitement, car cela demande plus de travail.

Mais d'un autre côté, si votre vue comporte beaucoup de variables d'aide complexes, comme des instances de votre modèle que vous utilisez dans la vue pour générer les données que vous voulez envoyer au modèle, vous pouvez envisager d'utiliser des variables explicites pour retourner au modèle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X