Est-il possible d'avoir des variables de classe statiques ou des méthodes en Python? Quelle syntaxe est requise pour ce faire?
Les variables déclarées à l'intérieur de la définition de classe, mais pas à l'intérieur d'une méthode sont des variables de classe ou statiques:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Comme le souligne @ millerdev , cela crée une i
variable au niveau de la classe , mais elle est distincte de toute i
variable au niveau de l'instance , vous pourriez donc avoir
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Ceci est différent de C ++ et Java, mais pas si différent de C #, où un membre statique n'est pas accessible à l'aide d'une référence à une instance.
Découvrez ce que le didacticiel Python a à dire sur le sujet des classes et des objets de classe .
@Steve Johnson a déjà répondu concernant les méthodes statiques , également documentées sous "Fonctions intégrées" dans la référence de bibliothèque Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy recommande les méthodes de classe par rapport à la méthode statique, car la méthode reçoit ensuite le type de classe comme premier argument, mais je suis encore un peu flou sur les avantages de cette approche par rapport à la méthode statique. Si vous l'êtes aussi, cela n'a probablement pas d'importance.
@classmethod
plus@staticmethod
AFAIK est que vous obtenez toujours le nom de la classe la méthode a été invoquée, même si elle est une sous - classe. Une méthode statique n'a pas ces informations, elle ne peut donc pas appeler une méthode redéfinie, par exemple.const.py
avecPI = 3.14
et vous pouvez l'importer partout.from const import PI
i = 3
n'est pas une variable statique, c'est un attribut de classe, et comme il est distinct d'un attribut de niveau instance,i
il ne se comporte pas comme une variable statique dans d'autres langages. Voir la réponse de millerdev , la réponse de Yann , et ma réponse ci - dessous.i
(variable statique) sera en mémoire même si je crée des centaines d'instances de cette classe?@Blair Conrad a déclaré que les variables statiques déclarées à l'intérieur de la définition de classe, mais pas à l'intérieur d'une méthode sont des variables de classe ou "statiques":
Il y a quelques pièges ici. Poursuivant sur l'exemple ci-dessus:
Remarquez comment la variable d'instance
t.i
s'est désynchronisée avec la variable de classe "statique" lorsque l'attribut ai
été défini directement surt
. Ceci est dû au faiti
a été relié à l'intérieur de l't
espace de noms, qui est distinct de l'Test
espace de noms. Si vous souhaitez modifier la valeur d'une variable "statique", vous devez la modifier dans la portée (ou l'objet) où elle a été initialement définie. Je mets "statique" entre guillemets car Python n'a pas vraiment de variables statiques au sens où C ++ et Java en ont.Bien qu'il ne dise rien de spécifique sur les variables ou méthodes statiques, le didacticiel Python contient des informations pertinentes sur classes et les objets de classe .
@Steve Johnson a également répondu concernant les méthodes statiques, également documentées sous "Fonctions intégrées" dans la référence de bibliothèque Python.
@beid a également mentionné classmethod, qui est similaire à staticmethod. Le premier argument d'une méthode de classe est l'objet classe. Exemple:
la source
class Test(object):
,_i = 3
,@property
,def i(self)
,return type(self)._i
,@i.setter
,def i(self,val):
,type(self)._i = val
. Maintenant , vous pouvez le fairex = Test()
,x.i = 12
,assert x.i == Test.i
.Méthodes statiques et de classe
Comme les autres réponses l'ont noté, les méthodes statiques et de classe sont facilement réalisables à l'aide des décorateurs intégrés:
Comme d'habitude, le premier argument de
MyMethod()
est lié à l'objet instance de classe. En revanche, le premier argument deMyClassMethod()
est lié à l'objet de classe lui-même (par exemple, dans ce cas,Test
). PourMyStaticMethod()
, aucun des arguments n'est lié et avoir des arguments est facultatif."Variables statiques"
Cependant, implémenter des "variables statiques" (enfin, des variables statiques mutables , de toute façon, si ce n'est pas une contradiction en termes ...) n'est pas aussi simple. Comme l'a souligné millerdev dans sa réponse , le problème est que les attributs de classe de Python ne sont pas vraiment des "variables statiques". Considérer:
En effet, la ligne
x.i = 12
a ajouté un nouvel attribut d'instancei
àx
au lieu de modifier la valeur de l' attribut deTest
classei
.Le comportement partiel attendu des variables statiques, c'est-à-dire la synchronisation de l'attribut entre plusieurs instances (mais pas avec la classe elle-même; voir "gotcha" ci-dessous), peut être obtenu en transformant l'attribut de classe en propriété:
Vous pouvez maintenant:
La variable statique restera désormais synchronisée entre toutes les instances de classe .
(REMARQUE: c'est-à-dire, sauf si une instance de classe décide de définir sa propre version de
_i
! Mais si quelqu'un décide de faire CELA, il mérite ce qu'il obtient, n'est-ce pas ???)Notez que techniquement parlant, ce
i
n'est toujours pas une «variable statique» du tout; c'est unproperty
, qui est un type spécial de descripteur. Cependant, leproperty
comportement est désormais équivalent à une variable statique (mutable) synchronisée sur toutes les instances de classe."Variables statiques" immuables
Pour un comportement de variable statique immuable, omettez simplement le
property
setter:Maintenant, tenter de définir l'
i
attribut d' instance retournera unAttributeError
:Un Gotcha à connaître
Notez que les méthodes ci-dessus ne fonctionnent qu'avec les instances de votre classe - elles ne fonctionneront pas lors de l'utilisation de la classe elle-même . Ainsi, par exemple:
La ligne
assert Test.i == x.i
produit une erreur, car l'i
attribut deTest
etx
sont deux objets différents.Beaucoup de gens trouveront cela surprenant. Mais cela ne devrait pas l'être. Si nous revenons en arrière et inspectons notre
Test
définition de classe (la deuxième version), nous prenons note de cette ligne:De toute évidence, le membre
i
deTest
doit être unproperty
objet, qui est le type d'objet renvoyé par laproperty
fonction.Si vous trouvez cela déroutant, vous y pensez probablement encore du point de vue d'autres langages (par exemple Java ou c ++). Vous devriez aller étudier l'
property
objet, sur l'ordre dans lequel les attributs Python sont retournés, le protocole de descripteur et l'ordre de résolution des méthodes (MRO).Je présente ci-dessous une solution au 'gotcha' ci-dessus; cependant, je suggère - vigoureusement - que vous n'essayez pas de faire quelque chose comme ce qui suit jusqu'à ce que - au moins - vous compreniez bien pourquoi
assert Test.i = x.i
une erreur se produit.Variables statiques réelles et réelles -
Test.i == x.i
Je présente la solution (Python 3) ci-dessous à titre informatif uniquement. Je ne l'approuve pas comme une "bonne solution". J'ai des doutes quant à la nécessité réelle d'émuler le comportement des variables statiques d'autres langages en Python. Cependant, peu importe s'il est réellement utile, ce qui suit devrait aider à mieux comprendre le fonctionnement de Python.
MISE À JOUR: cette tentative est vraiment assez horrible ; si vous insistez pour faire quelque chose comme ça (indice: s'il vous plaît ne le faites pas; Python est un langage très élégant et le faire en se comportant comme un autre langage n'est tout simplement pas nécessaire), utilisez plutôt le code dans la réponse d'Ethan Furman .
Émulation du comportement de variables statiques d'autres langues à l'aide d'une métaclasse
Une métaclasse est la classe d'une classe. La métaclasse par défaut pour toutes les classes en Python (c'est-à-dire les classes "nouveau style" après Python 2.3 je crois) est
type
. Par exemple:Cependant, vous pouvez définir votre propre métaclasse comme ceci:
Et appliquez-le à votre propre classe comme ceci (Python 3 uniquement):
Ci-dessous se trouve une métaclasse que j'ai créée qui tente d'émuler le comportement de "variable statique" d'autres langues. Il fonctionne essentiellement en remplaçant le getter, le setter et le deleter par défaut par des versions qui vérifient si l'attribut demandé est une "variable statique".
Un catalogue des "variables statiques" est stocké dans l'
StaticVarMeta.statics
attribut. Toutes les demandes d'attribut sont initialement tentées d'être résolues à l'aide d'un ordre de résolution de remplacement. J'ai appelé cela «l'ordre de résolution statique» ou «SRO». Cela se fait en recherchant l'attribut demandé dans l'ensemble des "variables statiques" pour une classe donnée (ou ses classes parentes). Si l'attribut n'apparaît pas dans le "SRO", la classe retombera sur le comportement par défaut de l'attribut get / set / delete (c'est-à-dire "MRO").la source
Test
(avant de l'utiliser pour instancier des instances) comme étant dans le domaine de la méta-programmation? Par exemple, vous modifiez le comportement de classe en faisantTest.i = 0
(ici, vous détruisez simplement entièrement l'objet de propriété). Je suppose que le "mécanisme de propriété" intervient uniquement sur l'accès à la propriété sur les instances d'une classe (à moins que vous ne changiez le comportement sous-jacent en utilisant une méta-classe comme intermédiaire, peut-être). Btw, veuillez terminer cette réponse :-)Vous pouvez également ajouter des variables de classe aux classes à la volée
Et les instances de classe peuvent changer les variables de classe
la source
Personnellement, j'utilisais une méthode de classe chaque fois que j'avais besoin d'une méthode statique. Principalement parce que je reçois la classe comme argument.
ou utilisez un décorateur
Pour les propriétés statiques .. Il est temps de rechercher une définition de python .. la variable peut toujours changer. Il en existe deux types mutables et immuables. Il existe également des attributs de classe et des attributs d'instance. Rien de tel que les attributs statiques au sens de java & c ++
Pourquoi utiliser la méthode statique au sens pythonique, si elle n'a aucun rapport avec la classe! Si j'étais vous, j'utiliserais la méthode de classe ou définirais la méthode indépendamment de la classe.
la source
Une chose spéciale à noter sur les propriétés statiques et les propriétés d'instance, illustrée dans l'exemple ci-dessous:
Cela signifie avant d'affecter la valeur à la propriété d'instance, si nous essayons d'accéder à la propriété via l'instance, la valeur statique est utilisée. Chaque propriété déclarée dans la classe python a toujours un emplacement statique en mémoire .
la source
Les méthodes statiques en python sont appelées méthodes de classe . Jetez un œil au code suivant
Notez que lorsque nous appelons la méthode myInstanceMethod , nous obtenons une erreur. En effet, il nécessite que cette méthode soit appelée sur une instance de cette classe. La méthode myStaticMethod est définie comme une méthode de classe à l'aide du décorateur @classmethod .
Juste pour les coups de pied et les rires, nous pourrions appeler myInstanceMethod sur la classe en passant dans une instance de la classe, comme ceci:
la source
@staticmethod
;@classmethod
est (évidemment) pour les méthodes de classe (qui sont principalement destinées à être utilisées comme constructeurs alternatifs, mais peuvent servir à la rigueur de méthodes statiques qui reçoivent une référence à la classe par laquelle elles ont été appelées).Lorsque vous définissez une variable membre en dehors d'une méthode membre, la variable peut être statique ou non statique selon la façon dont la variable est exprimée.
Par exemple:
Les résultats sont
la source
Il est possible d'avoir
static
des variables de classe, mais cela ne vaut probablement pas la peine.Voici une preuve de concept écrite en Python 3 - si l'un des détails exacts est faux, le code peut être modifié pour correspondre à peu près à ce que vous entendez par
static variable
:et en cours d'utilisation:
et quelques tests:
la source
Vous pouvez également appliquer une classe statique à l'aide de la métaclasse.
Ensuite, chaque fois que vous essayez d'initialiser MyClass par accident, vous obtenez une StaticClassError.
la source
__new__
parents ...Un point très intéressant sur la recherche d'attributs de Python est qu'il peut être utilisé pour créer des " variables virtuelles ":
Normalement, il n'y a aucune affectation à ceux-ci après leur création. Notez que la recherche utilise
self
car, bien qu'ellelabel
soit statique dans le sens où elle n'est pas associée à une instance particulière , la valeur dépend toujours de la (classe de l'instance).la source
En ce qui concerne cette réponse , pour une variable statique constante , vous pouvez utiliser un descripteur. Voici un exemple:
résultant en ...
Vous pouvez toujours lever une exception si ignorer tranquillement la valeur de réglage (
pass
ci-dessus) n'est pas votre truc. Si vous recherchez une variable de classe statique de style Java C ++:Jetez un œil à cette réponse et au HOWTO des documents officiels pour plus d'informations sur les descripteurs.
la source
@property
, ce qui revient à utiliser un descripteur, mais c'est beaucoup moins de code.Absolument Oui, Python en lui-même n'a pas explicitement de membre de données statiques, mais nous pouvons en avoir ainsi
production
explication
la source
Oui, certainement possible d'écrire des variables et des méthodes statiques en python.
Variables statiques: les variables déclarées au niveau de la classe sont appelées variables statiques accessibles directement à l'aide du nom de classe.
Variables d'instance: les variables liées et accessibles par l'instance d'une classe sont des variables d'instance.
Méthodes statiques: similaires aux variables, les méthodes statiques sont accessibles directement en utilisant le nom de classe. Pas besoin de créer une instance.
Mais gardez à l'esprit qu'une méthode statique ne peut pas appeler une méthode non statique en python.
la source
Pour éviter toute confusion potentielle, je voudrais opposer des variables statiques et des objets immuables.
Certains types d'objets primitifs comme les entiers, les flottants, les chaînes et les touches sont immuables en Python. Cela signifie que l'objet auquel un nom donné fait référence ne peut pas changer s'il appartient à l'un des types d'objet susmentionnés. Le nom peut être réaffecté à un autre objet, mais l'objet lui-même ne peut pas être modifié.
Le fait de rendre une variable statique va encore plus loin en interdisant au nom de la variable de pointer vers tout autre objet que celui vers lequel il pointe actuellement. (Remarque: il s'agit d'un concept logiciel général et non spécifique à Python; veuillez consulter les publications des autres pour plus d'informations sur la mise en œuvre de la statique dans Python).
la source
La meilleure façon que j'ai trouvée est d'utiliser une autre classe. Vous pouvez créer un objet puis l'utiliser sur d'autres objets.
Avec l'exemple ci-dessus, j'ai créé une classe nommée
staticFlag
.Cette classe doit présenter la var statique
__success
(Var Var statique statique).tryIt
classe représentait la classe régulière que nous devons utiliser.Maintenant, j'ai créé un objet pour un drapeau (
staticFlag
). Ce drapeau sera envoyé comme référence à tous les objets réguliers.Tous ces objets sont ajoutés à la liste
tryArr
.Résultats de ce script:
la source
Variables statiques dans la fabrique de classes python3.6
Pour toute personne utilisant une fabrique de classes avec python3.6 et plus, utilisez le
nonlocal
mot - clé pour l'ajouter à la portée / au contexte de la classe en cours de création comme suit:la source
hasattr(SomeClass, 'x')
estFalse
. je doute que ce soit ce que quelqu'un entend par une variable statique.some_var
immuable et défini statiquement, ou n'est-ce pas? Qu'est-ce que l'accès getter extérieur a à voir avec une variable statique ou non? j'ai tellement de questions maintenant. aimerait entendre des réponses lorsque vous aurez le temps.some_var
n'est pas du tout un membre du groupe. En Python, tous les membres de la classe sont accessibles depuis l'extérieur de la classe.nonlocal
clavier clavette la portée de la variable. La portée d'une définition de corps de classe est indépendante de la portée dans laquelle elle se trouve lorsque vous ditesnonlocal some_var
, c'est-à-dire simplement créer une référence de nom non local (lire: PAS dans la portée de définition de classe) à un autre objet nommé. Par conséquent, il n'est pas attaché à la définition de classe car il n'est pas dans la portée du corps de classe.C'est donc probablement un hack, mais j'ai utilisé
eval(str)
pour obtenir un objet statique, une sorte de contradiction, en python 3.Il existe un fichier Records.py qui n'a que des
class
objets définis avec des méthodes statiques et des constructeurs qui enregistrent certains arguments. Ensuite, à partir d'un autre fichier .py, jeimport Records
dois sélectionner dynamiquement chaque objet, puis l'instancier à la demande en fonction du type de données lues.Donc, où
object_name = 'RecordOne'
ou le nom de la classe, j'appellecur_type = eval(object_name)
, puis pour l'instancier, vous le faitescur_inst = cur_type(args)
Cependant, avant d'instancier, vous pouvez appeler des méthodes statiques,cur_type.getName()
par exemple, un peu comme l'implémentation d'une classe de base abstraite ou quel que soit l'objectif. Cependant, dans le backend, il est probablement instancié en python et n'est pas vraiment statique, car eval renvoie un objet .... qui doit avoir été instancié .... qui donne un comportement statique.la source
Vous pouvez utiliser une liste ou un dictionnaire pour obtenir un "comportement statique" entre les instances.
la source
Si vous essayez de partager une variable statique pour, par exemple, l'augmenter sur d'autres instances, quelque chose comme ce script fonctionne très bien:
la source