Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Argument optionnel de méthode dont la valeur par défaut serait un attribut de l' objet ?

2 réponses
Avatar
Bruno Piguet
Bonsoir,

J'aimerais avoir un objet, doté d'une méthode qui fait quelquechose
avec un attribut de l'objet, mais qui puisse faire la même chose avec un
argument optionnel, s'il est présent.

Pour l'instant, j'ai implanté ça de la manière suivante :

class MaClasse:
def __init__(self, arg1):
self.un_attribut = arg1

def une_methode(self, opt=None):
if opt:
valeur = opt
else:
valeur = self.un_attribut
print valeur

Et ça marche bien.
Si je fais :

mon_objet = MaClasse("valeur d'origine")
mon_objet.une_methode()
mon_objet.une_methode("valeur de remplacement")

j'obtiens bien:
>>>
valeur d'origine
valeur de remplacement
>>>

Je trouve que c'est un peu lourd, alors j'ai tenté autrement :

def autre_methode(self, opt=self.un_attribut):
print opt

Mais ça ne marche pas. Voici ce que me dit Python :
Traceback (most recent call last):
File "C:\[...]\methode_defaut.py", line 1, in <module>
class MaClasse:
File "C:\[...]\methode_defaut.py", line 12, in MaClasse
def autre_methode(self, opt=self.un_attribut):
NameError: name 'self' is not defined

Quelqu'un aurait une idée de syntaxe concise pour ce cas, qui soit
acceptée par Python ?

Merci d'avance,

Bruno.

2 réponses

Avatar
Pierre Quentel
On 11 juin, 22:26, Bruno Piguet wrote:
Bonsoir,

     J'aimerais avoir un objet, doté d'une méthode qui fait que lquechose
avec un attribut de l'objet, mais qui puisse faire la même chose avec u n
argument optionnel, s'il est présent.

     Pour l'instant, j'ai implanté ça de la manière suivante :

class MaClasse:
     def __init__(self, arg1):
         self.un_attribut = arg1

     def une_methode(self, opt=None):
         if opt:
             valeur = opt
         else:
             valeur = self.un_attribut
         print valeur

Et ça marche bien.
Si je fais :

mon_objet = MaClasse("valeur d'origine")
mon_objet.une_methode()
mon_objet.une_methode("valeur de remplacement")

j'obtiens bien:
 >>>
valeur d'origine
valeur de remplacement
 >>>

Je trouve que c'est un peu lourd, alors j'ai tenté autrement :

     def autre_methode(self, opt=self.un_attribut):
         print opt

Mais ça ne marche pas. Voici ce que me dit Python :
Traceback (most recent call last):
   File "C:[...]methode_defaut.py", line 1, in <module>
     class MaClasse:
   File "C:[...]methode_defaut.py", line 12, in MaClasse
     def autre_methode(self, opt=self.un_attribut):
NameError: name 'self' is not defined

Quelqu'un aurait une idée de syntaxe concise pour ce cas, qui soit
acceptée par Python ?

Merci d'avance,

Bruno.



Bonjour,

Je ne vois rien de mieux que ton code, que je simplifierais juste
comme ceci :

=============
class MaClasse:

def __init__(self, arg1):
self.un_attribut = arg1

def une_methode(self, valeur=None):
if valeur is None:
valeur = self.un_attribut
print valeur
===============

Cordialement,
Pierre
Avatar
Bruno Desthuilliers
Bruno Piguet a écrit :
Bonsoir,

J'aimerais avoir un objet, doté d'une méthode qui fait quelquechose
avec un attribut de l'objet, mais qui puisse faire la même chose avec un
argument optionnel, s'il est présent.

Pour l'instant, j'ai implanté ça de la manière suivante :

class MaClasse:
def __init__(self, arg1):
self.un_attribut = arg1

def une_methode(self, opt=None):
if opt:
valeur = opt



Attention, certains objets Python ont une valeur fausse dans le contexte
d'une expression booléenne (entre autres les zero numériques, la
chaine vide, et les conteneurs - liste, dict, set etc - vides). Si ces
valeurs sont légales comme argument, il serait préférable de tester
explicitement None, ie:


if opt is not None:
valeur = opt
else:
valeur = self.un_attribut
print valeur




Egalement, ça peut se simplifier soit avec l'operateur ternaire (Python
2.5x), soit avec l'opérateur 'or':

# 2.5x

valeur = self.un_attribut if opt is None else opt
# ou
valeur = opt if opt is not None else self.un_attribut

# < 2.5
# attention, piège si self.un_attribut a une valeur false
valeur = opt is None and self.un_attribut or opt


Et ça marche bien.
Si je fais :

mon_objet = MaClasse("valeur d'origine")
mon_objet.une_methode()
mon_objet.une_methode("valeur de remplacement")

j'obtiens bien:
>>>
valeur d'origine
valeur de remplacement
>>>

Je trouve que c'est un peu lourd, alors j'ai tenté autrement :

def autre_methode(self, opt=self.un_attribut):
print opt

Mais ça ne marche pas.



Evidemment. Au moment où le def est évalué, ni la classe, ni a fortiori
une instance de celle-ci n'existent. Pour rappel, il n'y a *absolument
rien* de magique dans 'self' - c'est juste une convention de nommage.

Que l'instruction 'def' soit placée au top-level ou dans le corps d'une
instruction 'class' ne change *rien* à son fonctionnement - dans tous
les cas, elle crée un objet function et l'assigne au nom de la fonction
dans l'espace de nommage courant. Si tu accèdes directement à ce nom en
court-circuitant la résolution d'attributs, tu a bien un objet function,
pas un objet method:

type(MaClasse.__dict__['une_methode'])
=> <type 'function'>

C'est lors de l'accès via la syntaxe obj.attr que le mécanisme de
résolution d'attribut (par défaut, object.__getattribute__) invoque le
protocole descripteur (méthode __get__) de l'objet function, lequel
retourne un objet method, qui n'est qu'un wrapper autour de la fonction,
l'instance et la classe. Et c'est finalement cet objet méthode qui
appelle la fonction en 'injectant' l'instance (ou la classe pour une
classmethod) comme premier argument.


Voici ce que me dit Python :
Traceback (most recent call last):
File "C:[...]methode_defaut.py", line 1, in <module>
class MaClasse:
File "C:[...]methode_defaut.py", line 12, in MaClasse
def autre_methode(self, opt=self.un_attribut):
NameError: name 'self' is not defined



Of course.

Quelqu'un aurait une idée de syntaxe concise pour ce cas, qui soit
acceptée par Python ?



Il serait possible d'écrire un décorateur pour ça, mais ça n'en vaut
pas nécessairement le coup. Dans la pratique, l'opérateur
conditionnel permet de gérer le cas en une seule ligne (je ne
qualifierais pas ça de 'lourd' personnellement), et d'une façon lisible
et explicite.

Dans le pire des cas, si tu dois gérer ce problème pour plusieurs
méthodes d'une même classe, une méthode utilitaire peut être envisagée:

class MaClasse(object):
def __init__(self, defaut):
self.un_attribut = defaut

def _resoudre(self, val, attr):
return val if val is not None else getattr(self, attr)

def une_methode(self, opt=None):
opt = self._resoudre(opt, 'un_attribut')
print opt


HTH