web-dev-qa-db-fra.com

Valeurs par défaut pour les paramètres de fonction dans Python

Duplicate possible:
valeur par défaut du paramètre en tant que résultat de la méthode d'instance

Bien qu'il soit possible de définir des valeurs par défaut pour les paramètres de fonction en python:

def my_function(param_one='default')
    ...

Il semble ne pas être possible d'accéder à l'instance actuelle (self):

class MyClass(..):

    def my_function(self, param_one=self.one_of_the_vars):
        ...

Mes questions):

  • Est-ce vrai que je ne peux pas accéder à l'instance actuelle pour définir le paramètre par défaut dans les fonctions?
  • Si ce n'est pas possible: quelles sont les raisons et est-il imaginable que cela sera possible dans les futures versions de python?
56
paweloque

C'est écrit comme:

def my_function(self, param_one=None): # Or custom sentinel if None is vaild
    if param_one is None:
        param_one = self.one_of_the_vars

Et je pense qu'il est prudent de dire que cela n'arrivera jamais dans Python en raison de la nature que self n'existe pas tant que la fonction n'a pas démarré ... (vous ne pouvez pas référence, dans sa propre définition - comme tout le reste)

Par exemple: vous ne pouvez pas faire d = {'x': 3, 'y': d['x'] * 5}

57
Jon Clements

Il y a beaucoup plus que ce que vous pensez. Considérez les valeurs par défaut comme étant statique (= référence constante pointant vers un objet ) et stockés quelque part dans la définition; évalué au moment de la définition de la méthode; dans le cadre de la classe , pas de l'instance. Comme ils sont constants, ils ne peuvent pas dépendre de self.

Voici un exemple. C'est contre-intuitif, mais c'est tout à fait logique:

def add(item, s=[]):
    s.append(item)
    print len(s)

add(1)     # 1
add(1)     # 2
add(1, []) # 1
add(1, []) # 1
add(1)     # 3

Ceci imprimera 1 2 1 1 3.

Parce que cela fonctionne de la même manière que

default_s=[]
def add(item, s=default_s):
    s.append(item)

Évidemment, si vous modifiez default_s, il conserve ces modifications.

Il existe différentes solutions de contournement, notamment

def add(item, s=None):
    if not s: s = []
    s.append(item)

ou vous pouvez faire ceci:

def add(self, item, s=None):
    if not s: s = self.makeDefaultS()
    s.append(item)

Ensuite, la méthode makeDefaultS aura accès à self.

Une autre variante:

import types
def add(item, s=lambda self:[]):
    if isinstance(s, types.FunctionType): s = s("example")
    s.append(item)

ici, la valeur par défaut de s est un fonction d'usine.

Vous pouvez combiner toutes ces techniques:

class Foo:
    import types
    def add(self, item, s=Foo.defaultFactory):
        if isinstance(s, types.FunctionType): s = s(self)
        s.append(item)

    def defaultFactory(self):
        """ Can be overridden in a subclass, too!"""
        return []
22
Anony-Mousse

Les valeurs par défaut pour les paramètres sont évaluées lors de la "compilation", une fois. Donc, évidemment, vous ne pouvez pas accéder à self. L'exemple classique est list comme paramètre par défaut. Si vous y ajoutez des éléments, la valeur par défaut du paramètre change!

La solution de contournement consiste à utiliser un autre paramètre par défaut, généralement None, puis à vérifier et à mettre à jour la variable.

3
Karoly Horvath

Vous faites ici de multiples fausses hypothèses. Premièrement, la fonction appartient à une classe et non à une instance, ce qui signifie que la fonction impliquée est la même pour deux instances de la classe. Deuxièmement, les paramètres par défaut sont évalués au moment de la compilation et sont constants (comme dans, une référence d'objet constante - si le paramètre est un objet modifiable, vous pouvez le changer). Ainsi, vous ne pouvez pas accéder à self avec un paramètre par défaut et vous ne pourrez jamais le faire.

2
l4mpi