2010-09-23 6 views
1

Quelqu'un peut-il s'il vous plaît la preuve pourquoi il est une mauvaise pratique à utiliser la solution comme ceci:django/importations de python perfomance

Dans les vues de django dans 98% des cas, vous devez utiliser

from django.http import HttpResponseRedirect 
    from django.core.urlresolvers import reverse 
    from django.utils.translation import ugettext as _ 

de toute façon dans mon projet mon chaque point de vue a ces importations et tout est utilisé presque dans chaque seconde fonction d'une vue: maintenant ajouter quelques modèles et formes

from datetime import datetime 
from django.conf import settings 
from django.contrib.auth.models import User 
from django.core.urlresolvers import reverse 
from django.core import paginator 
from django.db import connection 
from django.db.models import Q 
from django.http import HttpResponseRedirect, Http404, HttpResponse 
from django.shortcuts import render_to_response, get_object_or_404 
from django.template import RequestContext 
from django.utils.translation import ugettext as _ 

, et j'ai 50 lignes de conneries qui est impossible à r pas du tout.

La première chose qui m'est venue à l'esprit est bien sûr de faire plus de vues, de diviser certaines opérations et etc et etc .. mais toujours environ 30 lignes d'importations tuant mon orientation en code.

Ensuite, j'ai juste décidé de mettre tout ce qui est utilisé dans les vues par 95% du temps, dans le répertoire /project/app/imports/view.py. Maintenant, j'ai toutes les choses courantes avec ONE importer, mais mon collègue m'a attaqué, qu'il est très difficile de lire ce genre de code, parce que vous ne pouvez pas voir ce qui est importé, et pourquoi diable il est si difficile de ouvre un onglet de plus dans votre IDE .. ??? [en particulier ceci va aux utilisateurs de vim, ils ont des FRAMES, et il utilise vim]

J'ai fait la même chose avec les modèles, mes modèles ont leur propre répertoire, parce qu'il y a plus de 50 là dedans, et ces fichiers ne sont pas petits - environ 150 lignes chacun .. Même ces fichiers ont peu de modèles à l'intérieur .. donc je vais juste faire quelque chose comme:

from myapp.models.mymodel import * 

et il y a quelques endroits où je fais simplement: from myapp.models import * [ .py de initialisation myapp/imports dir a lieu ici]

Problèmes:

1) ok donc premier problème est l'espace de noms, ce type d'importation de modèle est peut-être vraiment ridicule .. mais la décision avec des vues et des formes, est tout simplement rien lazziness pour ouvrir un onglet supplémentaire dans votre IDE

2) problème de performance? mon collègue se disputant vraiment beaucoup avec cet argument, que "chaque importation prend 256kb de RAM" ?? (en exécutant le fichier .pyc compilé? Non je ne crois pas que;)

La question en fait est sur le problème de performance en raison des importations.

p.s. Je suis vraiment nouveau en python (juste 3 mois), et j'ouvre les arguments OBJECTIFS pour tous les problèmes et inconvénients de cette solution.

MISE À JOUR

Une fois que je posé la question sur la façon de déplacer les importations de fichier autonome pour que personne ne se plaint de cette =) question est here

Répondre

2

Gardez à l'esprit que vous pouvez importer un ensemble de sous-paquets. Alors

from django.conf import settings 
from django.contrib.auth.models import User 
from django.core.urlresolvers import reverse 
from django.core import paginator 
from django.db import connection 
from django.db.models import Q 
from django.http import HttpResponseRedirect, Http404, HttpResponse 
from django.shortcuts import render_to_response, get_object_or_404 
from django.template import RequestContext 
from django.utils.translation import ugettext as _ 

peut devenir

from django import conf, contrib, db, http, shortcuts, template, utils 
from django.core import urlresolvers, paginator 

qui est bref, vous permet d'éviter d'écrire django partout, et laisse assez évident où quelque chose comme urlresolvers.reverse vient. Cela a également l'avantage de ne pas mapper les noms généraux comme reverse à des fonctionnalités très spécifiques, vous laissant avec un code plus lisible.

5

1) il n'y a rien, mais la paresse de ne pas préfixer vos noms importés avec le module d'où il vient. Ce n'est rien d'autre que de la paresse de ne pas vouloir faire défiler les importations vers le code. Comment est-ce que le fait d'avoir un tel fouillis d'importations dans un autre dossier facilite-t-il la lecture? Je le laisserais dans le fichier original où ils sont réellement utilisés.Ce améliore la lisibilité parce que si j'ai besoin de savoir d'où vient quelque chose, alors je peux juste aller en haut du fichier et le vérifier (en utilisant l'anneau de marque emacs pour revenir tout de suite). Cela facilite également la maintenance de la liste car il me suffit de faire une recherche rapide pour voir où quelque chose est utilisé (ou non).

2) Sur ma machine, il faut ~ 812 microsecondes pour importer un module.

$ python -mtimeit -s'import os' 'reload(os)' 
1000 loops, best of 3: 808 usec per loop 

Ceci va bien sûr varier grandement avec l'endroit où se trouve votre PYTHONPATH. Si la performance est si serrée, vous serez peut-être en mesure de vous en sortir en jonglant avec ça. YMMV.

Je ne suis pas sûr d'où votre collègue obtient le 256kb. Cela dépend de la taille des objets de code impliqués. Comme vous pouvez le voir, l'objet module réel ne prend que 24 octets sur ma machine 32 bits. J'ai le sentiment que cela dépendra du système.

>>> def sizeofmodule(mod): 
...  return sum(sys.getsizeof(getattr(mod, o)) for o in dir(mod)) 
... 
>>> sizeofmodule(itertools) 
8662 
>>> sizeofmodule(sys) 
10275 
>>> sizeofmodule(operator) 
5230 
+0

il ne s'agit pas de paresse de l'écriture, mais de la lecture, cela fait tout le désordre dans le code. donc ce n'est pas un argument de toute façon. Parlant de la performance, il a également dit que parce que ce projet aura des tonnes de visiteurs par jour [cela ira vraiment énorme], cela pourrait être un problème – holms

+0

btw Je parlais de mettre toutes les importations en fichier autonome =) – holms

+0

@holms, je sais exactement de quoi vous parlez. Je vous appelle simplement à vous être paresseux du point de vue de vos collègues. – aaronasterling

1

Quelques points à considérer:

Le temps qu'il faut pour importer un module est, dans presque tous les cas, tout à fait hors de propos: il arrive qu'une seule fois. Votre module de vue Django n'est pas importé et réévalué pour chaque requête; il est chargé une fois puis réutilisé. Si vos modules sont constamment rechargés, quelque chose est catastrophique.

Chaque importation est et non en prenant 256 Ko de mémoire. Peut-être que chaque fichier individuel, chargé une fois, est (bien que je doute que cela aussi), mais l'importation du même fichier à plusieurs reprises ne prend pas 256kb à chaque fois; c'est simplement créer une référence. Si l'utilisation de la mémoire est en question, il suffit de la profiler - chargez 10000 de quelque chose et voyez combien de mémoire est utilisée.

Pour les modules Django, vous n'avez pas toujours besoin de créer un répertoire pour chacun d'eux; J'importe chaque classe de modèle de models/__init__.py (par exemple from Customer import Customer), donc je peux dire from myapp.models import Profile, Customer, Book, .... La tendance pour les vues Django à avoir besoin d'une douzaine de lignes d'importations en haut est vraiment un problème. Il se transforme en boilerplate, code que vous copiez et collez chaque fois que vous démarrez un nouveau fichier. Le code source exigeant le passe-partout est un défaut majeur.

Dans le même temps, je déconseille fortement ce que certaines personnes pourraient recommander: import django, puis en utilisant des noms de modules complets. Le résultat est de taper des choses comme django.core.urlresolvers.reverse. Lorsque vous vous retrouvez régulièrement à copier et coller des noms de fonctions parce qu'ils sont trop longs, quelque chose a mal tourné.

Il n'y a pas de solution unique, claire et évidemment correcte. Mettre les choses qui sont systématiquement utilisées dans un autre module est une solution valable, mais il y a des problèmes légitimes: il est difficile de voir ce qui est importé, et où les résultats de l'importation sont utilisés.

Vous trouverez probablement moins d'objections de réaction de la gut si vous importez le module "collection de modules" lui-même - import djangohelpers ou import djangohelpers as dh. Ensuite, vous écrivez des choses comme dh.paginator. Il donne une portée claire aux noms, et il est beaucoup plus facile de voir où il est utilisé et d'où viennent les noms de certaines fonctions, que vous perdez avec "import *".

(Vous ne voulez probablement importer des choses comme Q et _ que les noms nus, cependant.)