Quelle est la différence entre les méthodes de classe suivantes?
Est-ce que l'un est statique et l'autre non?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
@classmethod
à la définition. Le premier paramètre doit être appelé à lacls
place deself
et recevra l'objet classe plutôt qu'une instance de votre classe:Test.method_three()
eta_test.method_three()
sont équivalents.self
argument? Existe-t-il un cas d'utilisation solide pour cela?Réponses:
En Python, il existe une distinction entre les méthodes liées et non liées .
Fondamentalement, un appel à une fonction membre (comme
method_one
), une fonction liéeest traduit en
c'est-à-dire un appel à une méthode non liée. Pour cette raison, un appel à votre version de
method_two
échouera avec unTypeError
Vous pouvez modifier le comportement d'une méthode à l'aide d'un décorateur
Le décorateur indique à la métaclasse par défaut intégrée
type
(la classe d'une classe, cf. cette question ) de ne pas créer de méthodes liées pourmethod_two
.Maintenant, vous pouvez appeler une méthode statique à la fois sur une instance ou sur la classe directement:
la source
Les méthodes en Python sont une chose très, très simple une fois que vous avez compris les bases du système de descripteurs. Imaginez la classe suivante:
Voyons maintenant cette classe dans le shell:
Comme vous pouvez le voir si vous accédez à l'
foo
attribut de la classe, vous obtenez une méthode non liée, mais à l'intérieur du stockage de classe (le dict), il y a une fonction. Pourquoi ça? La raison en est que la classe de votre classe implémente un__getattribute__
qui résout les descripteurs. Cela semble complexe, mais ce n'est pas le cas.C.foo
est à peu près équivalent à ce code dans ce cas particulier:C'est parce que les fonctions ont une
__get__
méthode qui en fait des descripteurs. Si vous avez une instance d'une classe, c'est presque la même chose, c'est justeNone
l'instance de classe:Maintenant, pourquoi Python fait-il cela? Parce que l'objet méthode lie le premier paramètre d'une fonction à l'instance de la classe. C'est de là que vient le moi. Maintenant, parfois, vous ne voulez pas que votre classe fasse d'une fonction une méthode, c'est là
staticmethod
qu'entre en jeu:Le
staticmethod
décorateur encapsule votre classe et implémente un mannequin__get__
qui renvoie la fonction encapsulée en tant que fonction et non en tant que méthode:J'espère que cela l'explique.
la source
staticmethod
décorateur encapsule votre classe (...) Cette phrase est un peu trompeuse car la classe qui est encapsulée est la classe de la méthodefoo
et non la classe dans laquelle ellefoo
est définie.Lorsque vous appelez un membre de classe, Python utilise automatiquement une référence à l'objet comme premier paramètre. La variable
self
ne signifie en fait rien, c'est juste une convention de codage. Vous pourriez l'appelergargaloo
si vous le vouliez. Cela dit, l'appel à déclencheraitmethod_two
unTypeError
, car Python essaie automatiquement de passer un paramètre (la référence à son objet parent) à une méthode définie comme n'ayant aucun paramètre.Pour le faire fonctionner, vous pouvez ajouter ceci à votre définition de classe:
ou vous pouvez utiliser le
@staticmethod
décorateur de fonction .la source
la source
Class.instance_method() # The class cannot use an instance method
il peut utiliser. Il suffit de passer l'instance manuellement:Class.instance_method(a)
TyeError
ligne.a.class_method()
, il semble avoira.c
été mis à jour vers1
, donc l'appel aClass.class_method()
mis à jour laClass.c
variable vers2
. Cependant, lors de votre affectationa.c=5
, pourquoi neClass.c
pas être mis à jour5
?method_two ne fonctionnera pas car vous définissez une fonction membre mais ne lui dites pas de quoi la fonction est membre. Si vous exécutez la dernière ligne, vous obtiendrez:
Si vous définissez des fonctions membres pour une classe, le premier argument doit toujours être «self».
la source
Explication précise d'Armin Ronacher ci-dessus, développant ses réponses pour que les débutants comme moi le comprennent bien:
La différence dans les méthodes définies dans une classe, qu'il s'agisse d'une méthode statique ou d'une méthode d'instance (il existe encore un autre type - méthode de classe - non abordée ici, donc en la sautant), réside dans le fait qu'elles sont en quelque sorte liées à l'instance de classe ou non. Par exemple, dites si la méthode reçoit une référence à l'instance de classe pendant l'exécution
La
__dict__
propriété dictionnaire de l'objet classe contient la référence à toutes les propriétés et méthodes d'un objet classe et doncla méthode foo est accessible comme ci-dessus. Un point important à noter ici est que tout en python est un objet et donc les références dans le dictionnaire ci-dessus pointent elles-mêmes vers d'autres objets. Permettez-moi de les appeler objets de propriété de classe - ou en tant que CPO dans le cadre de ma réponse par souci de concision.
Si un CPO est un descripteur, alors l'interpréteur python appelle la
__get__()
méthode du CPO pour accéder à la valeur qu'il contient.Afin de déterminer si un CPO est un descripteur, l'interpréteur python vérifie s'il met en œuvre le protocole de descripteur. Mettre en œuvre le protocole descripteur, c'est mettre en œuvre 3 méthodes
par exemple
où
self
est le CPO (il peut s'agir d'une instance de liste, str, fonction, etc.) et est fourni par le runtimeinstance
est l'instance de la classe où ce CPO est défini (l'objet 'c' ci-dessus) et doit être explicitement fourni par nousowner
est la classe où ce CPO est défini (l'objet de classe 'C' ci-dessus) et doit être fourni par nous. Cependant, c'est parce que nous l'appelons sur le CPO. lorsque nous l'appelons sur l'instance, nous n'avons pas besoin de fournir cela car le runtime peut fournir l'instance ou sa classe (polymorphisme)value
est la valeur prévue pour le CPO et doit être fournie par nousTous les CPO ne sont pas des descripteurs. Par exemple
En effet, la classe de liste n'implémente pas le protocole de descripteur.
Ainsi, l'argument self in
c.foo(self)
est requis car sa signature de méthode est en fait la suivanteC.__dict__['foo'].__get__(c, C)
(comme expliqué ci-dessus, C n'est pas nécessaire car il peut être découvert ou polymorphe) Et c'est aussi pourquoi vous obtenez une TypeError si vous ne passez pas cet argument d'instance requis.Si vous remarquez que la méthode est toujours référencée via la classe Object C et que la liaison avec l'instance de classe est réalisée en passant un contexte sous la forme de l'objet d'instance dans cette fonction.
C'est assez génial car si vous choisissez de ne conserver aucun contexte ou aucune liaison à l'instance, tout ce qui était nécessaire était d'écrire une classe pour encapsuler le descripteur CPO et remplacer sa
__get__()
méthode pour ne nécessiter aucun contexte. Cette nouvelle classe est ce que nous appelons un décorateur et est appliquée via le mot clé@staticmethod
L'absence de contexte dans le nouveau CPO enveloppé ne
foo
génère pas d'erreur et peut être vérifiée comme suit:Le cas d'utilisation d'une méthode statique est plus un espace de noms et une maintenabilité du code (le retirer d'une classe et le rendre disponible dans tout le module, etc.).
Il est peut-être préférable d'écrire des méthodes statiques plutôt que des méthodes d'instance dans la mesure du possible, sauf si vous devez bien sûr contextualiser les méthodes (comme les variables d'instance d'accès, les variables de classe, etc.). L'une des raisons est de faciliter la récupération de place en ne conservant pas de référence indésirable aux objets.
la source
c'est une erreur.
tout d'abord, la première ligne doit être comme ça (attention aux majuscules)
Chaque fois que vous appelez une méthode d'une classe, elle se prend comme premier argument (d'où le nom self) et method_two donne cette erreur
la source
Le second ne fonctionnera pas parce que lorsque vous l'appelez comme ça, python essaie de l'appeler en interne avec l'instance a_test comme premier argument, mais votre method_two n'accepte aucun argument, donc ça ne marchera pas, vous obtiendrez un runtime Erreur. Si vous voulez l'équivalent d'une méthode statique, vous pouvez utiliser une méthode de classe. Les méthodes de classe en Python sont beaucoup moins nécessaires que les méthodes statiques dans des langages comme Java ou C #. Le plus souvent, la meilleure solution consiste à utiliser une méthode dans le module, en dehors d'une définition de classe, celles-ci fonctionnent plus efficacement que les méthodes de classe.
la source
Class Test(object): @staticmethod def method_two(): print(“called method_two”)
Un cas d'utilisation, je pensais à quand vous voulez que la fonction fasse partie d'une classe, mais ne voulez pas que l'utilisateur accède directement à la fonction. Ainsi, lemethod_two
peut être appelé par d'autres fonctions à l'intérieur de l'Test
instance, mais ne peut pas être appelé en utilisanta_test.method_two()
. Si j'utilisedef method_two()
, cela fonctionnera-t-il pour ce cas d'utilisation? Ou existe-t-il un meilleur moyen de modifier la définition de la fonction, afin qu'elle fonctionne comme prévu dans le cas d'utilisation ci-dessus?L'appel à method_two lèvera une exception pour ne pas accepter le paramètre auto, le runtime Python le transmettra automatiquement.
Si vous souhaitez créer une méthode statique dans une classe Python, décorez-la avec le
staticmethod decorator
.la source
Veuillez lire cette documentation de Guido First Class tout expliquant clairement comment les méthodes Unbound, Bound sont nées.
la source
La définition de
method_two
n'est pas valide. Lorsque vous appelezmethod_two
, vous obtiendrezTypeError: method_two() takes 0 positional arguments but 1 was given
de l'interprète.Une méthode d'instance est une fonction bornée lorsque vous l'appelez comme
a_test.method_two()
. Il accepte automatiquementself
, qui pointe vers une instance deTest
, comme premier paramètre. Grâce auself
paramètre, une méthode d'instance peut accéder librement aux attributs et les modifier sur le même objet.la source
Méthodes non liées
Les méthodes non liées sont des méthodes qui ne sont pas encore liées à une instance de classe particulière.
Méthodes liées
Les méthodes liées sont celles qui sont liées à une instance spécifique d'une classe.
Comme indiqué ici , self peut faire référence à différentes choses selon que la fonction est liée, non liée ou statique.
Jetez un œil à l'exemple suivant:
Puisque nous n'avons pas utilisé l'instance de classe -
obj
- lors du dernier appel, nous pouvons en quelque sorte dire qu'elle ressemble à une méthode statique.Si oui, quelle est la différence entre un
MyClass.some_method(10)
appel et un appel à une fonction statique décorée avec un@staticmethod
décorateur?En utilisant le décorateur, nous indiquons clairement que la méthode sera utilisée sans créer d'abord une instance pour elle. Normalement, on ne s'attendrait pas à ce que les méthodes des membres de classe soient utilisées sans l'instance et y accéder peut provoquer des erreurs possibles selon la structure de la méthode.
De plus, en ajoutant le
@staticmethod
décorateur, nous permettons également d'être atteint à travers un objet.Vous ne pouvez pas faire l'exemple ci-dessus avec les méthodes d'instance. Vous pouvez survivre au premier (comme nous l'avons fait auparavant), mais le second sera traduit en un appel non lié
MyClass.some_method(obj, 10)
qui déclenchera unTypeError
puisque la méthode d'instance prend un argument et que vous avez involontairement essayé d'en passer deux.Ensuite, vous pourriez dire: «si je peux appeler des méthodes statiques via une instance et une classe,
MyClass.some_static_method
etMyClass().some_static_method
que ce soient les mêmes méthodes». Oui!la source
Méthode liée = méthode d'instance
Méthode non liée = méthode statique.
la source