Question

Est-il possible d’avoir des variables de classe statiques ou des méthodes en python? Quelle syntaxe est nécessaire pour faire cela?

Était-ce utile?

La solution

Les variables déclarées dans la définition de classe, mais pas dans une méthode, sont des variables de classe ou statiques:

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3 

Comme @ millerdev , cela crée une classe niveau i variable, mais distincte de toute variable i de niveau instance, vous pourriez donc avoir

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

Cela diffère de C ++ et Java, mais pas tellement de C #, où un membre statique est inaccessible à l'aide d'une référence à une instance.

Voir ce que le didacticiel Python dit au sujet des classes et objets de classe .

@Steve Johnson a déjà répondu à propos des méthodes statiques , documenté également sous " Fonctions intégrées " dans la référence de la bibliothèque Python .

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidy recommande les la méthode de classe sur staticmethod, comme méthode reçoit le type de classe comme premier argument, mais je suis encore un peu flou sur les avantages de cette approche par rapport à staticmethod. Si vous êtes aussi, cela n'a probablement pas d'importance.

Autres conseils

@Blair Conrad a déclaré que les variables statiques déclarées dans la définition de la classe, mais pas dans une méthode, sont class ou "statique". variables:

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

Il y a quelques pièges ici. En reprenant l'exemple ci-dessus:

>>> t = Test()
>>> t.i     # "static" variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the "static" variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the "static" variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6
>>> u = Test()
>>> u.i
6           # changes to t do not affect new instances of Test

# Namespaces are one honking great idea -- let's do more of those!
>>> Test.__dict__
{'i': 6, ...}
>>> t.__dict__
{'i': 5}
>>> u.__dict__
{}

Notez que la variable d'instance t.i est désynchronisée par rapport à " statique " variable de classe lorsque l'attribut i a été défini directement sur t . En effet, i a été lié à nouveau dans l'espace de noms t , qui est distinct de l'espace de noms Test . Si vous souhaitez modifier la valeur d'un " statique " variable, vous devez la modifier dans la portée (ou l’objet) où elle a été définie à l’origine. Je mets " statique " entre guillemets, car Python n’a pas vraiment de variables statiques au sens de C ++ et de Java.

Le didacticiel Python contient des informations spécifiques sur les variables ou les méthodes statiques. des informations pertinentes sur les les classes et les objets de classe .

@Steve Johnson a également répondu aux méthodes statiques, également documentées dans la section "Fonctions intégrées". dans la référence de la bibliothèque Python.

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid a également mentionné classmethod, qui est similaire à staticmethod. Le premier argument d'une méthode de classe est l'objet class. Exemple:

class Test(object):
    i = 3 # class (or static) variable
    @classmethod
    def g(cls, arg):
        # here we can use 'cls' instead of the class name (Test)
        if arg > cls.i:
            cls.i = arg # would the the same as  Test.i = arg1

 Représentation illustrée de l'exemple ci-dessus

Méthodes statiques et de classe

Comme les autres réponses l'ont noté, les décorateurs intégrés permettent de mettre en œuvre des méthodes statiques et de classe:

class Test(object):

    # regular instance method:
    def MyMethod(self):
        pass

    # class method:
    @classmethod
    def MyClassMethod(klass):
        pass

    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

Comme d'habitude, le premier argument de MyMethod () est lié à l'objet d'instance de la classe. En revanche, le premier argument de MyClassMethod () est lié ??à l'objet de classe lui-même (par exemple, dans ce cas, Test ). Pour MyStaticMethod () , aucun des arguments n'est lié et il est facultatif de ne pas en avoir.

"Variables statiques"

Cependant, la mise en oeuvre de " variables statiques " (eh bien, les variables statiques mutables , de toute façon, si ce n’est pas une contradiction dans les 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érez:

class Test(object):
    i = 3  # This is a class attribute

x = Test()
x.i = 12   # Attempt to change the value of the class attribute using x instance
assert x.i == Test.i  # ERROR
assert Test.i == 3    # Test.i was not affected
assert x.i == 12      # x.i is a different object than Test.i

Cela est dû au fait que la ligne xi = 12 a ajouté un nouvel attribut d'instance i à x au lieu de modifier la valeur du Testez l'attribut i .

Le comportement de variable statique attendu partiel , 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 une propriété:

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

    @i.setter
    def i(self,val):
        type(self)._i = val

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting and setting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    def set_i(self,val):
        type(self)._i = val

    i = property(get_i, set_i)

Maintenant, vous pouvez faire:

x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i  # no error
assert x2.i == 50    # the property is synced

La variable statique restera désormais synchronisée entre toutes les instances de classe .

(NOTE: Autrement dit, à moins qu'une instance de classe ne 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, i n'est toujours pas une "variable statique"; c'est une propriété , qui est un type spécial de descripteur. Cependant, le comportement de la propriété est maintenant équivalent à une variable statique (modifiable) synchronisée sur toutes les instances de la classe.

Immutables "Variables statiques"

Pour un comportement de variable statique immuable, omettez simplement le setter property :

class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    i = property(get_i)

Essayer maintenant de définir l'attribut i de l'instance retournera une AttributeError :

x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR

Il faut être conscient de

Notez que les méthodes ci-dessus ne fonctionnent qu'avec les instances de votre classe. Elles ne fonctionneront pas si vous utilisez la classe elle-même . Ainsi, par exemple:

x = Test()
assert x.i == Test.i  # ERROR

# x.i and Test.i are two different objects:
type(Test.i)  # class 'property'
type(x.i)     # class 'int'

La ligne assert Test.i == xi génère une erreur car l'attribut i de Test et x sont deux objets différents.

Beaucoup de gens trouveront cela surprenant. Cependant, cela ne devrait pas l'être. Si nous revenons en arrière et inspectons notre définition de classe Test (la deuxième version), nous prenons note de cette ligne:

    i = property(get_i) 

Clairement, le membre i de Test doit être un objet property , qui est le type d'objet renvoyé de la propriété . fonction .

Si vous estimez que ce qui précède est source de confusion, vous y réfléchissez probablement toujours du point de vue d’autres langages (par exemple, Java ou c ++). Vous devriez aller étudier l’objet property , sur l’ordre dans lequel les attributs Python sont renvoyés, le protocole de descripteur et l’ordre de résolution de la méthode (MRO).

Je présente une solution à la question ci-dessus 'gotcha' ci-dessous; Cependant, je suggérerais - de manière énergique - de ne pas essayer de faire quelque chose comme ce qui suit avant de comprendre au moins pourquoi assert Test.i = x.i provoque une erreur.

REAL, ACTUAL Variables statiques - Test.i == x.i

Je présente la solution (Python 3) ci-dessous à titre d'information uniquement. Je ne le considère pas comme une "bonne solution". Je doute que l'émulation du comportement de variable statique d'autres langages en Python soit réellement nécessaire. Cependant, que cela soit vraiment utile ou non, les informations ci-dessous devraient vous aider à mieux comprendre le fonctionnement de Python.

MISE À JOUR: cette tentative est vraiment horrible ; si vous insistez pour faire quelque chose comme ceci (conseil: veuillez ne pas; Python est un langage très élégant et le laisser se transformer en un autre langage n'est tout simplement pas nécessaire), utilisez le code La réponse d'Ethan Furman à la place.

Emulation du comportement des 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:

type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'

Cependant, vous pouvez définir votre propre métaclasse comme ceci:

class MyMeta(type): pass

Et appliquez-le à votre propre classe comme ceci (uniquement pour Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Ci-dessous, une métaclasse que j'ai créée et qui tente d'émuler la "variable statique". comportement d'autres langues. Cela 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'attribut StaticVarMeta.statics . Toutes les demandes d'attributs sont initialement tentées pour être résolues en utilisant un ordre de résolution de substitution. J'ai surnommé cela "l'ordre de résolution statique" ou "SRO". Pour ce faire, recherchez 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 se basera sur le comportement par défaut de l'attribut get / set / delete (c'est-à-dire "MRO").

from functools import wraps

class StaticVarsMeta(type):
    '''A metaclass for creating classes that emulate the "static variable" behavior
    of other languages. I do not advise actually using this for anything!!!

    Behavior is intended to be similar to classes that use __slots__. However, "normal"
    attributes and __statics___ can coexist (unlike with __slots__). 

    Example usage: 

        class MyBaseClass(metaclass = StaticVarsMeta):
            __statics__ = {'a','b','c'}
            i = 0  # regular attribute
            a = 1  # static var defined (optional)

        class MyParentClass(MyBaseClass):
            __statics__ = {'d','e','f'}
            j = 2              # regular attribute
            d, e, f = 3, 4, 5  # Static vars
            a, b, c = 6, 7, 8  # Static vars (inherited from MyBaseClass, defined/re-defined here)

        class MyChildClass(MyParentClass):
            __statics__ = {'a','b','c'}
            j = 2  # regular attribute (redefines j from MyParentClass)
            d, e, f = 9, 10, 11   # Static vars (inherited from MyParentClass, redefined here)
            a, b, c = 12, 13, 14  # Static vars (overriding previous definition in MyParentClass here)'''
    statics = {}
    def __new__(mcls, name, bases, namespace):
        # Get the class object
        cls = super().__new__(mcls, name, bases, namespace)
        # Establish the "statics resolution order"
        cls.__sro__ = tuple(c for c in cls.__mro__ if isinstance(c,mcls))

        # Replace class getter, setter, and deleter for instance attributes
        cls.__getattribute__ = StaticVarsMeta.__inst_getattribute__(cls, cls.__getattribute__)
        cls.__setattr__ = StaticVarsMeta.__inst_setattr__(cls, cls.__setattr__)
        cls.__delattr__ = StaticVarsMeta.__inst_delattr__(cls, cls.__delattr__)
        # Store the list of static variables for the class object
        # This list is permanent and cannot be changed, similar to __slots__
        try:
            mcls.statics[cls] = getattr(cls,'__statics__')
        except AttributeError:
            mcls.statics[cls] = namespace['__statics__'] = set() # No static vars provided
        # Check and make sure the statics var names are strings
        if any(not isinstance(static,str) for static in mcls.statics[cls]):
            typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[True].__name__
            raise TypeError('__statics__ items must be strings, not {0}'.format(typ))
        # Move any previously existing, not overridden statics to the static var parent class(es)
        if len(cls.__sro__) > 1:
            for attr,value in namespace.items():
                if attr not in StaticVarsMeta.statics[cls] and attr != ['__statics__']:
                    for c in cls.__sro__[1:]:
                        if attr in StaticVarsMeta.statics[c]:
                            setattr(c,attr,value)
                            delattr(cls,attr)
        return cls
    def __inst_getattribute__(self, orig_getattribute):
        '''Replaces the class __getattribute__'''
        @wraps(orig_getattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                return StaticVarsMeta.__getstatic__(type(self),attr)
            else:
                return orig_getattribute(self, attr)
        return wrapper
    def __inst_setattr__(self, orig_setattribute):
        '''Replaces the class __setattr__'''
        @wraps(orig_setattribute)
        def wrapper(self, attr, value):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__setstatic__(type(self),attr, value)
            else:
                orig_setattribute(self, attr, value)
        return wrapper
    def __inst_delattr__(self, orig_delattribute):
        '''Replaces the class __delattr__'''
        @wraps(orig_delattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__delstatic__(type(self),attr)
            else:
                orig_delattribute(self, attr)
        return wrapper
    def __getstatic__(cls,attr):
        '''Static variable getter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    return getattr(c,attr)
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __setstatic__(cls,attr,value):
        '''Static variable setter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                setattr(c,attr,value)
                break
    def __delstatic__(cls,attr):
        '''Static variable deleter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    delattr(c,attr)
                    break
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __delattr__(cls,attr):
        '''Prevent __sro__ attribute from deletion'''
        if attr == '__sro__':
            raise AttributeError('readonly attribute')
        super().__delattr__(attr)
    def is_static(cls,attr):
        '''Returns True if an attribute is a static variable of any class in the __sro__'''
        if any(attr in StaticVarsMeta.statics[c] for c in cls.__sro__):
            return True
        return False

Vous pouvez également ajouter des variables de classe à des classes à la volée

>>> class X:
...     pass
... 
>>> X.bar = 0
>>> x = X()
>>> x.bar
0
>>> x.foo
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: X instance has no attribute 'foo'
>>> X.foo = 1
>>> x.foo
1

Et les instances de classe peuvent modifier les variables de classe

class X:
  l = []
  def __init__(self):
    self.l.append(1)

print X().l
print X().l

>python test.py
[1]
[1, 1]

Personnellement, j’utiliserais 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.

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 

ou utilisez un décorateur

class myObj(object):
   @classmethod
   def myMethod(cls)

Pour les propriétés statiques .. Il est temps de rechercher une définition python .. variable peut toujours changer. En outre, il existe des attributs de classe et des attributs d'instance. Rien ne ressemble vraiment aux attributs statiques au sens de java & amp; c ++

Pourquoi utiliser la méthode statique au sens pythonique, si elle n’a aucune relation avec la classe! Si j'étais vous, j'utiliserais classmethod ou définirais la méthode indépendamment de la classe.

Remarque spéciale sur les propriétés statiques & amp; propriétés d'instance, présentées dans l'exemple ci-dessous:

class my_cls:
  my_prop = 0

#static property
print my_cls.my_prop  #--> 0

#assign value to static property
my_cls.my_prop = 1 
print my_cls.my_prop  #--> 1

#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1

#instance property is different from static property 
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop  #--> 1
print my_inst.my_prop #--> 2

Cela signifie qu'avant d'affecter la valeur à la propriété d'instance, si nous essayons d'accéder à la propriété par 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 .

Les méthodes statiques en python sont appelées classmethod . Regardez le code suivant

class MyClass:

    def myInstanceMethod(self):
        print 'output from an instance method'

    @classmethod
    def myStaticMethod(cls):
        print 'output from a static method'

>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]

>>> MyClass.myStaticMethod()
output from a static method

Notez que lorsque nous appelons la méthode myInstanceMethod , nous obtenons une erreur. Cela est dû au fait que cette méthode doit être appelée sur une instance de cette classe. La méthode myStaticMethod est définie en tant que méthode de classe à l'aide du décorateur @classmethod .

Juste pour le plaisir et les fous rires, nous pourrions appeler myInstanceMethod sur la classe en transmettant une instance de la classe, comme suit:

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method

Lorsque vous définissez une variable membre en dehors de toute méthode membre, la variable peut être statique ou non statique en fonction de son expression.

  • CLASSNAME.var est une variable statique
  • INSTANCENAME.var n'est pas une variable statique.
  • self.var dans la classe n'est pas une variable statique.
  • la variable à l'intérieur de la fonction membre de la classe n'est pas définie.

Par exemple:

#!/usr/bin/python

class A:
    var=1

    def printvar(self):
        print "self.var is %d" % self.var
        print "A.var is %d" % A.var


    a = A()
    a.var = 2
    a.printvar()

    A.var = 3
    a.printvar()

Les résultats sont

self.var is 2
A.var is 1
self.var is 2
A.var is 3

Vous pouvez également imposer à une classe d'être statique à l'aide d'une métaclasse.

class StaticClassError(Exception):
    pass


class StaticClass:
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kw):
        raise StaticClassError("%s is a static class and cannot be initiated."
                                % cls)

class MyClass(StaticClass):
    a = 1
    b = 3

    @staticmethod
    def add(x, y):
        return x+y

Ensuite, chaque fois que vous tentez d'initialiser MyClass par erreur, vous obtenez une erreur StaticClassError.

Il est possible d'avoir des variables de classe static , mais cela ne vaut probablement pas la peine.

Voici une démonstration de concept écrite en Python 3. Si un ou plusieurs des détails exacts sont faux, le code peut être modifié pour correspondre exactement à ce que vous entendez par une variable statique :

class Static:
    def __init__(self, value, doc=None):
        self.deleted = False
        self.value = value
        self.__doc__ = doc
    def __get__(self, inst, cls=None):
        if self.deleted:
            raise AttributeError('Attribute not set')
        return self.value
    def __set__(self, inst, value):
        self.deleted = False
        self.value = value
    def __delete__(self, inst):
        self.deleted = True

class StaticType(type):
    def __delattr__(cls, name):
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__delete__(name)
        else:
            super(StaticType, cls).__delattr__(name)
    def __getattribute__(cls, *args):
        obj = super(StaticType, cls).__getattribute__(*args)
        if isinstance(obj, Static):
            obj = obj.__get__(cls, cls.__class__)
        return obj
    def __setattr__(cls, name, val):
        # check if object already exists
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__set__(name, val)
        else:
            super(StaticType, cls).__setattr__(name, val)

et en cours d'utilisation:

class MyStatic(metaclass=StaticType):
    """
    Testing static vars
    """
    a = Static(9)
    b = Static(12)
    c = 3

class YourStatic(MyStatic):
    d = Static('woo hoo')
    e = Static('doo wop')

et quelques tests:

ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
    try:
        getattr(inst, 'b')
    except AttributeError:
        pass
    else:
        print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19

ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a

Un point très intéressant sur la recherche d'attribut de Python est qu'il peut être utilisé pour créer un virtual variables ":

class A(object):

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!

Normalement, il n’ya aucune assignation à ces derniers après leur création. Notez que la recherche utilise self car, bien que label soit statique dans le sens où il n'est pas associé à une instance particulière , la valeur dépend toujours de la (classe de) l'instance.

En ce qui concerne cette answer , pour une variable statique constante , vous pouvez utiliser descripteur. Voici un exemple:

class ConstantAttribute(object):
    '''You can initialize my value but not change it.'''
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        pass


class Demo(object):
    x = ConstantAttribute(10)


class SubDemo(Demo):
    x = 10


demo = Demo()
subdemo = SubDemo()
# should not change
demo.x = 100
# should change
subdemo.x = 100
print "small demo", demo.x
print "small subdemo", subdemo.x
print "big demo", Demo.x
print "big subdemo", SubDemo.x

entraînant ...

small demo 10
small subdemo 100
big demo 10
big subdemo 10

Vous pouvez toujours lever une exception si ignorer discrètement la valeur du paramètre ( pass ci-dessus) n'est pas votre affaire. Si vous recherchez une variable de classe statique de style Java, C ++:

class StaticAttribute(object):
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        self.value = val

Consultez cette réponse et la documentation officielle HOWTO pour plus d'informations sur les descripteurs.

Absolument Oui,   Python par lui-même n'a explicitement aucun membre de données statique, mais nous pouvons le faire en le faisant

class A:
    counter =0
    def callme (self):
        A.counter +=1
    def getcount (self):
        return self.counter  
>>> x=A()
>>> y=A()
>>> print(x.getcount())
>>> print(y.getcount())
>>> x.callme() 
>>> print(x.getcount())
>>> print(y.getcount())

sortie

0
0
1
1

explication

here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"

Pour éviter toute confusion potentielle, j'aimerais mettre en contraste variables statiques et objets immuables.

Certains types d'objet primitifs tels que les entiers, les flottants, les chaînes et les touples sont immuables en Python. Cela signifie que l'objet auquel un nom donné fait référence ne peut pas changer s'il fait partie de 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é.

Rendre une variable statique va encore plus loin en interdisant au nom de la variable de pointer sur un objet autre que celui sur lequel elle 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 oeuvre de la statique en Python).

Le meilleur moyen que j’ai trouvé est d’utiliser une autre classe. Vous pouvez créer un objet puis l’utiliser sur d’autres objets.

class staticFlag:
    def __init__(self):
        self.__success = False
    def isSuccess(self):
        return self.__success
    def succeed(self):
        self.__success = True

class tryIt:
    def __init__(self, staticFlag):
        self.isSuccess = staticFlag.isSuccess
        self.succeed = staticFlag.succeed

tryArr = []
flag = staticFlag()
for i in range(10):
    tryArr.append(tryIt(flag))
    if i == 5:
        tryArr[i].succeed()
    print tryArr[i].isSuccess()

Avec l'exemple ci-dessus, j'ai créé une classe nommée staticFlag .

Cette classe doit présenter la var statique __ success (Var statique privée).

La classe

tryIt représente la classe normale à utiliser.

Maintenant, j'ai créé un objet pour un drapeau ( staticFlag ). Cet indicateur sera envoyé comme référence à tous les objets normaux.

Tous ces objets sont ajoutés à la liste tryArr .

Ce script Résultats:

False
False
False
False
False
True
True
True
True
True

Oui, définitivement possible d'écrire des variables et méthodes statiques en python.

Variables statiques: Les variables déclarées au niveau de la classe sont appelées variables statiques auxquelles on peut accéder directement à l'aide du nom de la classe.

    >>> class A:
        ...my_var = "shagun"

    >>> print(A.my_var)
        shagun

Variables d'instance: Les variables liées et auxquelles on accède par instance d'une classe sont des variables d'instance.

   >>> a = A()
   >>> a.my_var = "pruthi"
   >>> print(A.my_var,a.my_var)
       shagun pruthi

Méthodes statiques: Comme pour les variables, vous pouvez accéder directement aux méthodes statiques à l'aide de la classe Nom. 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.

    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ... 
   >>> A.my_static_method()
   Yippey!!

Variables statiques dans la fabrique de classes python3.6

Pour ceux qui utilisent une fabrique de classes avec python3.6 et les versions ultérieures, utilisez le mot clé nonlocal pour l'ajouter à la portée / au contexte de la classe en cours de création, de la manière suivante:

>>> def SomeFactory(some_var=None):
...     class SomeClass(object):
...         nonlocal some_var
...         def print():
...             print(some_var)
...     return SomeClass
... 
>>> SomeFactory(some_var="hello world").print()
hello world

Créez simplement une classe contenant n'importe quelle variable ou types d'objets. Accéder à ces variables en utilisant class nom comme ci-dessous:


    class StaticVariable:
        myvar1 = 1
        myvar2 = 2


    StaticVariable.myvar1 = StaticVariable.myvar1 +1
    StaticVariable.myvar2 = StaticVariable.myvar2 +1

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top