Il est plus rapide et plus lisible pour construire l'objet, puis l'attacher à self
.
class Test1(object):
def __init__(self):
d = {}
d['a'] = 1
d['b'] = 2
d['c'] = 3
self.d = d
class Test2(object):
def __init__(self):
self.d = {}
self.d['a'] = 1
self.d['b'] = 2
self.d['c'] = 3
import dis
print "Test1.__init__"
dis.dis(Test1.__init__)
print "Test2.__init__"
dis.dis(Test2.__init__)
disassemles à:
Test1.__init__
4 0 BUILD_MAP 0
3 STORE_FAST 1 (d)
5 6 LOAD_CONST 1 (1)
9 LOAD_FAST 1 (d)
12 LOAD_CONST 2 ('a')
15 STORE_SUBSCR
6 16 LOAD_CONST 3 (2)
19 LOAD_FAST 1 (d)
22 LOAD_CONST 4 ('b')
25 STORE_SUBSCR
7 26 LOAD_CONST 5 (3)
29 LOAD_FAST 1 (d)
32 LOAD_CONST 6 ('c')
35 STORE_SUBSCR
8 36 LOAD_FAST 1 (d)
39 LOAD_FAST 0 (self)
42 STORE_ATTR 0 (d)
45 LOAD_CONST 0 (None)
48 RETURN_VALUE
Test2.__init__
12 0 BUILD_MAP 0
3 LOAD_FAST 0 (self)
6 STORE_ATTR 0 (d)
13 9 LOAD_CONST 1 (1)
12 LOAD_FAST 0 (self)
15 LOAD_ATTR 0 (d)
18 LOAD_CONST 2 ('a')
21 STORE_SUBSCR
14 22 LOAD_CONST 3 (2)
25 LOAD_FAST 0 (self)
28 LOAD_ATTR 0 (d)
31 LOAD_CONST 4 ('b')
34 STORE_SUBSCR
15 35 LOAD_CONST 5 (3)
38 LOAD_FAST 0 (self)
41 LOAD_ATTR 0 (d)
44 LOAD_CONST 6 ('c')
47 STORE_SUBSCR
48 LOAD_CONST 0 (None)
51 RETURN_VALUE
Vous pouvez voir que STORE_ATTR
seulement une fois qu'il est appelé à faire la première manière à la fin. Dans l'autre sens, STORE_ATTR
est toujours appelé au début, mais LOAD_ATTR
est appelé pour chaque accès au dictionnaire. Plus il y a d'affectations, plus le coût est élevé. Toutes les autres instructions sont les mêmes. C'est toujours un coût ridiculement faible.
Cette astuce peut être exploitée pour faire tourner des boucles avec de nombreuses itérations plus rapidement. Il est pas rare de voir des choses comme
foo = self.foo
factorial = math.factorial
for x in really_big_iterator:
foo(factorial(x))
une autre astuce consiste à passer des fonctions globales comme arguments par défaut à une fonction qui a une boucle comme ça ou est appelé un tas pour sauver quelques recherches d'attributs: il est dans la portée locale qui est le premier regardé po
def fast(iterators, sum=sum):
for i in iterator:
yield sum(i)
maintenant sum est juste dans le champ d'application local.
Je pense que vous avez fourni la meilleure raison.Si j'ai une fonction qui effectue des effets secondaires, même si les effets secondaires ne dépassent pas self, je retarderai ces effets jusqu'à ce que la fonction soit terminée avec succès. C'est une bonne habitude dans n'importe quelle fonction où il y a la possibilité d'une exception qui arrête l'exécution à mi-chemin. –