Je voudrais construire une méthode à l'intérieur d'une classe avec des arguments de valeurs par défaut tirés de cette classe. En général, je filtre certaines données. Dans ma classe, j'ai une méthode où normalement je passe un vecteur de données. Parfois, je n'ai pas le vecteur et je prends des données simulées. Chaque fois que je ne passe pas un vecteur particulier, je voudrais prendre des données simulées par défaut. J'ai pensé que cela devrait être une construction facile où dans ma définition de méthode, je dis a=self.vector
. Mais pour une raison quelconque, j'ai une erreur NameError: name 'self' is not defined
. La construction simplifiée est:
class baseClass(object): # This class takes an initial data or simulation
def __init__(self):
self.x = 1
self.y = 2
class extendedClass(baseClass): # This class does some filtering
def __init__(self):
baseClass.__init__(self)
self.z = 5
def doSomething(self, a=self.z):
self.z = 3
self.b = a
if __== '__main__':
a = extendedClass()
print a.__dict__
a.doSomething()
print a.__dict__
Une sortie que j'attendais devrait être:
{'y': 2, 'x': 1, 'z': 5}
{'y': 2, 'x': 1, 'z': 3, 'b': 5}
J'ai essayé l'affectation par défaut comme def doSomething(self, a=z):
évidemment cela ne fonctionne jamais. Autant que je sache, self.z
Est visible dans cette portée et ne devrait pas être un problème pour l'avoir comme valeur par défaut. Je ne sais pas pourquoi j'ai cette erreur et comment le faire. C'est probablement une question facile, mais j'essaie de le comprendre ou de trouver la solution sans manque depuis un certain temps déjà. J'ai trouvé similaire questions uniquement pour les autres langues.
Votre compréhension est fausse. self
est lui-même un paramètre de cette définition de fonction, il n'y a donc aucun moyen qu'il soit à portée à ce stade. Ce n'est que dans la portée de la fonction elle-même.
La réponse est simplement de définir par défaut l'argument sur None
, puis de vérifier cela dans la méthode:
def doSomething(self, a=None):
if a is None:
a = self.z
self.z = 3
self.b = a
Voici le démontage du code pour un exemple de module simple. Un objet de code est un conteneur en lecture seule pour le bytecode, les constantes et les noms qu'il utilise, et les métadonnées sur le nombre de variables locales, la taille de pile requise, etc. Notez que tous les objets de code sont compilés en tant que constantes. Ils sont créés au moment de la compilation. Mais les objets class A
Et function test
Sont instanciés au moment de l'exécution (par exemple lorsque le module est importé).
Pour créer la classe, BUILD_CLASS
Prend le nom 'A'
, Les bases Tuple
(object,)
Et un dict
qui contient les attributs du espace de noms de classe. C'est comme instancier manuellement un type en appelant type(name, bases, dict)
. Pour créer le dict
, une fonction est créée à partir de l'objet de code A
et appelée. Enfin, l'objet classe est stocké dans l'espace de noms du module via STORE_NAME
.
Dans l'objet de code A
, self.z
Est chargé sur la pile comme argument de MAKE_FUNCTION
. L'opération de bytecode LOAD_NAME
Recherchera self
dans les sections locales actuelles (c'est-à-dire l'espace de noms de classe en cours de définition), les globales du module et les commandes intégrées. Cela échouera évidemment si self
n'est pas défini dans la portée globale ou intégrée; il n'est clairement pas défini dans la portée locale.
Si elle réussissait, cependant, la fonction serait créée avec (self.z,)
Comme attribut __defaults__
, Puis stockée sous le nom local test
.
>>> code = compile('''
... class A(object):
... def test(self, a=self.z): pass
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 ('A')
3 LOAD_NAME 0 (object)
6 BUILD_Tuple 1
9 LOAD_CONST 1 (<code object A ...>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_NAME 1 (A)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
>>> dis.dis(code.co_consts[1]) # code object A
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
3 6 LOAD_NAME 2 (self)
9 LOAD_ATTR 3 (z)
12 LOAD_CONST 0 (<code object test ...>)
15 MAKE_FUNCTION 1
18 STORE_NAME 4 (test)
21 LOAD_LOCALS
22 RETURN_VALUE
@ uselpa: Votre exemple Pastebin (réécrit pour 2.x):
>>> code = compile('''
... default = 1
... class Cl(object):
... def __init__(self, a=default):
... print a
... Cl()
... default = 2
... Cl()
... ''', '<input>', 'exec')
>>> dis.dis(code)
2 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (default)
3 6 LOAD_CONST 1 ('Cl')
9 LOAD_NAME 1 (object)
12 BUILD_Tuple 1
15 LOAD_CONST 2 (<code object Cl ...>)
18 MAKE_FUNCTION 0
21 CALL_FUNCTION 0
24 BUILD_CLASS
25 STORE_NAME 2 (Cl)
6 28 LOAD_NAME 2 (Cl)
31 CALL_FUNCTION 0
34 POP_TOP
7 35 LOAD_CONST 3 (2)
38 STORE_NAME 0 (default)
8 41 LOAD_NAME 2 (Cl)
44 CALL_FUNCTION 0
47 POP_TOP
48 LOAD_CONST 4 (None)
51 RETURN_VALUE
Comme vous pouvez le voir, l'objet de classe Cl
(et l'objet fonction __init__
) N'est instancié et stocké qu'une seule fois dans le nom local 'Cl'
. Le module s'exécute séquentiellement au moment de l'exécution. Par conséquent, la nouvelle liaison du nom default
n'aura aucun effet sur la valeur par défaut dans __init__
.
Vous pouvez instancier dynamiquement une nouvelle fonction en utilisant le code précédemment compilé et une nouvelle valeur par défaut:
>>> default = 1
>>> class Cl(object):
... def __init__(self, a=default):
... print a
...
>>> from types import FunctionType
>>> default = 2
>>> Cl.__init__ = FunctionType(
... Cl.__init__.__code__, globals(), '__init__', (default,), None)
>>> c = Cl()
2
Ceci réutilise l'objet de code déjà compilé à partir de __init__.__code__
Pour créer une fonction avec un nouveau tuple __defaults__
:
>>> Cl.__init__.__defaults__
(2,)
Les arguments par défaut ne sont évalués qu'une seule fois, lorsque la définition est exécutée. Au lieu de cela, procédez comme suit:
def doSomething(self, a=None):
if a is None:
a = self.z
self.z = 3
self.b = a
Voir aussi http://docs.python.org/release/3.3.0/tutorial/controlflow.html#more-on-defining-functions .
Cela insérera self.z
si a
est None
/False
/empty_value
:
def doSomething(self, a=None):
self.z = 3
self.b = (a or self.z)