Zijn statische klassenvariabelen mogelijk in Python?

Is het mogelijk om statische klassenvariabelen of -methoden in Python te hebben? Welke syntaxis is hiervoor nodig?


Antwoord 1, autoriteit 100%

Variabelen die binnen de klassedefinitie zijn gedeclareerd, maar niet binnen een methode, zijn klasse- of statische variabelen:

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

Zoals @millerdevaangeeft, creëert dit een klasse- level ivariabele, maar dit verschilt van elke ivariabele op instantieniveau, dus je zou kunnen hebben

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

Dit is anders dan C++ en Java, maar niet zo verschillend van C#, waar een statisch lid niet kan worden benaderd met een verwijzing naar een instantie.

Bekijk wat de Python-tutorial te zeggen heeft over klassen en klasse-objecten.

@Steve Johnson heeft al geantwoord met betrekking tot statische methoden, ook gedocumenteerd onder “Built-in Functions” in de Python Library Reference.

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

@beidy beveelt classmethods aan boven staticmethod, als de methode dan ontvangt het klassetype als het eerste argument, maar ik ben nog steeds een beetje vaag over de voordelen van deze benadering ten opzichte van de statische methode. Als jij dat ook bent, maakt het waarschijnlijk niet uit.


Antwoord 2, autoriteit 32%

@Blair Conrad zei dat statische variabelen die binnen de klassendefinitie zijn gedeclareerd, maar niet binnen een methode, klasse- of “statische” variabelen zijn:

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

Er zijn hier een paar problemen. Voortbordurend op het bovenstaande voorbeeld:

>>> 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__
{}

Merk op hoe de instantievariabele t.iniet meer synchroon liep met de klassevariabele “static” toen het kenmerk irechtstreeks op twerd ingesteld . Dit komt omdat iopnieuw is gebonden binnen de t-naamruimte, die verschilt van de Test-naamruimte. Als u de waarde van een “statische” variabele wilt wijzigen, moet u deze wijzigen binnen het bereik (of object) waar deze oorspronkelijk is gedefinieerd. Ik plaats “statisch” tussen aanhalingstekens omdat Python niet echt statische variabelen heeft in de zin van C++ en Java.

Hoewel het niets specifieks zegt over statische variabelen of methoden, heeft de Python-zelfstudieenkele relevante informatie over klassen en klasseobjecten.

@Steve Johnson antwoordde ook met betrekking tot statische methoden, ook gedocumenteerd onder “Ingebouwde functies” in de Python Library Reference.

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

@beid noemde ook classmethod, die vergelijkbaar is met staticmethod. Het eerste argument van een klassenmethode is het klasseobject. Voorbeeld:

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 be the same as Test.i = arg1

Geïllustreerde weergave van bovenstaand voorbeeld


Antwoord 3, autoriteit 11%

Statische en klassemethoden

Zoals de andere antwoorden al hebben opgemerkt, kunnen statische en klassenmethoden eenvoudig worden bereikt met behulp van de ingebouwde decorateurs:

class Test(object):
    # regular instance method:
    def MyMethod(self):
        pass
    # class method:
    @classmethod
    def MyClassMethod(klass):
        pass
    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

Zoals gewoonlijk is het eerste argument van MyMethod()gebonden aan het instantieobject van de klasse. Daarentegen is het eerste argument voor MyClassMethod()gebonden aan het klasseobject zelf(bijvoorbeeld in dit geval Test). Voor MyStaticMethod()is geen van de argumenten gebonden, en het hebben van argumenten is optioneel.

“Statische variabelen”

Echter, het implementeren van “statische variabelen” (nou ja, veranderlijkestatische variabelen, als dat geen contradictio in terminis is…) is niet zo eenvoudig. Zoals millerdev opmerkte in zijn antwoord, is het probleem dat de klasseattributen van Python niet echt “statische variabelen” zijn. Overweeg:

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

Dit komt omdat de regel x.i = 12een nieuw instantiekenmerk iheeft toegevoegd aan xin plaats van de waarde van de Testklasse ikenmerk.

Gedeeltelijkverwacht gedrag van statische variabelen, dwz synchronisatie van het attribuut tussen meerdere instanties (maar nietmet de klasse zelf; zie “gotcha” hieronder), kan worden bereikt door het class attribuut in een eigenschap te veranderen:

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)

Nu kunt u het volgende doen:

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

De statische variabele blijft nu synchroon tussen alle klasseninstanties.

(OPMERKING: Dat wil zeggen, tenzij een klasse-instantie besluit om zijn eigen versie van _ite definiëren! Maar als iemand besluit DAT te doen, verdienen ze wat ze krijgen, nietwaar??? )

Merk op dat technisch gezien inog steeds helemaal geen ‘statische variabele’ is; het is een property, wat een speciaal type descriptor is. Het gedrag van propertyis nu echter gelijk aan een (veranderlijke) statische variabele die is gesynchroniseerd met alle klasseninstanties.

Onveranderlijke “statische variabelen”

Voor onveranderlijk gedrag van statische variabelen, laat u gewoon de propertysetter weg:

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)

Als u nu probeert om het kenmerk iinstantie in te stellen, wordt een AttributeErrorgeretourneerd:

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

Eén Gotcha om op te letten

Houd er rekening mee dat de bovenstaande methoden alleen werken met instantiesvan uw klasse – ze zullen nietwerken bij gebruik van de klasse zelf. Dus bijvoorbeeld:

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'

De regel assert Test.i == x.iproduceert een fout, omdat het iattribuut van Testen xzijn twee verschillende objecten.

Veel mensen zullen dit verrassend vinden. Het zou echter niet zo moeten zijn. Als we teruggaan en onze klassedefinitie Test(de tweede versie) inspecteren, merken we deze regel op:

   i = property(get_i) 

Het is duidelijk dat het lid ivan Testeen property-object moet zijn, wat het type object is dat wordt geretourneerd door de propertyfunctie.

Als u het bovenstaande verwarrend vindt, denkt u er waarschijnlijk nog steeds over vanuit het perspectief van andere talen (bijv. Java of c++). Je zou het object propertymoeten gaan bestuderen, over de volgorde waarin Python-attributen worden geretourneerd, het descriptorprotocol en de methoderesolutievolgorde (MRO).

Ik presenteer hieronder een oplossing voor de bovenstaande ‘gotcha’; ik zou echter – met klem – willen voorstellen dat je niet zoiets als het volgende probeert te doen totdat je – op zijn minst – grondig begrijpt waarom assert Test.i = x.ieen fout veroorzaakt.

WERKELIJK, WERKELIJKStatische variabelen – Test.i == x.i

Ik presenteer de (Python 3) oplossing hieronder alleen voor informatieve doeleinden. Ik onderschrijf het niet als een “goede oplossing”. Ik heb mijn twijfels of het emuleren van het statische variabele gedrag van andere talen in Python ooit echt nodig is. Ongeacht of het echt nuttig is, het onderstaande zou echter moeten helpen om beter te begrijpen hoe Python werkt.

UPDATE: deze poging is echt behoorlijk afschuwelijk; als je erop staat om zoiets als dit te doen (hint: alsjeblieft niet; Python is een zeer elegante taal en het is niet nodig om het te gedragen als een andere taal is gewoon niet nodig), gebruik dan de code in Ethan Furman’s antwoordin plaats daarvan.

Het gedrag van statische variabelen van andere talen emuleren met behulp van een metaklasse

Een metaklasse is de klasse van een klasse. De standaard metaklasse voor alle klassen in Python (d.w.z. de klassen “nieuwe stijl” na Python 2.3 geloof ik) is type. Bijvoorbeeld:

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

U kunt echter uw eigen metaklasse als volgt definiëren:

class MyMeta(type): pass

En pas het als volgt toe op je eigen klas (alleen Python 3):

class MyClass(metaclass = MyMeta):
    pass
type(MyClass)  # class MyMeta

Hieronder staat een metaklasse die ik heb gemaakt en die probeert het gedrag van “statische variabelen” van andere talen te emuleren. Het werkt in principe door de standaard getter, setter en deleter te vervangen door versies die controleren of het gevraagde attribuut een “statische variabele” is.

Een catalogus van de “statische variabelen” wordt opgeslagen in het kenmerk StaticVarMeta.statics. Er wordt in eerste instantie geprobeerd om alle attribuutverzoeken op te lossen met behulp van een vervangende oplossingsvolgorde. Ik heb dit de “statische resolutievolgorde” of “SRO” genoemd. Dit wordt gedaan door te zoeken naar het gevraagde attribuut in de set van “statische variabelen” voor een bepaalde klasse (of zijn bovenliggende klassen). Als het attribuut niet voorkomt in de “SRO”, zal de klasse terugvallen op het standaardattribuut get/set/delete-gedrag (d.w.z. “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

Antwoord 4, autoriteit 2%

Je kunt ook meteen klassevariabelen aan klassen toevoegen

>>> 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

En klasse-instanties kunnen klassevariabelen wijzigen

class X:
  l = []
  def __init__(self):
    self.l.append(1)
print X().l
print X().l
>python test.py
[1]
[1, 1]

Antwoord 5

Persoonlijk zou ik een klassenmethode gebruiken wanneer ik een statische methode nodig had. Vooral omdat ik de klas als argument krijg.

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

of gebruik een decorateur

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

Voor statische eigenschappen.. Het wordt tijd dat je een python-definitie opzoekt.. variabele kan altijd veranderen. Er zijn twee soorten veranderlijk en onveranderlijk.. Er zijn ook klasseattributen en instantieattributen.. Er gaat niets boven statische attributen in de zin van java & c++

Waarom een ​​statische methode in pythonische zin gebruiken, als deze geen enkele relatie heeft met de klasse! Als ik jou was, zou ik ofwel classmethod gebruiken of de methode onafhankelijk van de klasse definiëren.


Antwoord 6

Een speciaal ding om op te merken over statische eigenschappen & instantie-eigenschappen, weergegeven in het onderstaande voorbeeld:

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

Dit betekent dat voordat we de waarde aan de instantie-eigenschap toewijzen, als we proberen toegang te krijgen tot de eigenschap via de instantie, de statische waarde wordt gebruikt. Elke eigenschap die in de python-klasse is gedeclareerd, heeft altijd een statisch slot in het geheugen.


Antwoord 7

Statische methoden in python worden classmethods genoemd. Bekijk de volgende code

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

Merk op dat wanneer we de methode myInstanceMethodaanroepen, we een foutmelding krijgen. Dit komt omdat het vereist dat die methode wordt aangeroepen op een instantie van deze klasse. De methode myStaticMethodwordt ingesteld als een klassenmethode met behulp van de decorator@classmethod.

Voor de grap en het gegiechel kunnen we myInstanceMethodin de klas aanroepen door een instantie van de klas door te geven, zoals:

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

Antwoord 8

Wanneer u een lidvariabele definieert buiten een lidmethode, kan de variabele statisch of niet-statisch zijn, afhankelijk van hoe de variabele wordt uitgedrukt.

  • CLASSNAME.var is een statische variabele
  • INSTANCENAME.var is geen statische variabele.
  • self.var binnen klasse is geen statische variabele.
  • var binnen de klasselidfunctie is niet gedefinieerd.

Bijvoorbeeld:

#!/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()

De resultaten zijn

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

Antwoord 9

Het is mogelijk om staticklassevariabelen te hebben, maar waarschijnlijk niet de moeite waard.

Hier is een proof-of-concept geschreven in Python 3 — als een van de exacte details onjuist is, kan de code worden aangepast om overeen te komen met zowat alles wat je bedoelt met een static variable:


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)

en in gebruik:

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')

en enkele 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

Antwoord 10

Je zou een klasse ook kunnen afdwingen om statisch te zijn met behulp van metaclass.

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

Als je dan per ongeluk MyClassprobeert te initialiseren, krijg je een StaticClassError.


Antwoord 11

Een zeer interessant punt over het opzoeken van attributen in Python is dat het kan worden gebruikt om “virtuelete maken variabelen”:

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!

Normaal gesproken zijn er geen toewijzingen aan deze nadat ze zijn gemaakt. Merk op dat de lookup selfgebruikt omdat, hoewel labelstatisch is in de zin dat het niet geassocieerd is met een bepaaldexemplaar, de waarde nog steeds afhangt van de (klasse van de) instantie.


Antwoord 12

Ja, het is zeker mogelijk om statische variabelen en methoden in python te schrijven.

Statische variabelen :
Variabelen die op klasseniveau worden gedeclareerd, worden statische variabelen genoemd die direct toegankelijk zijn via de klassenaam.

   >>> class A:
        ...my_var = "shagun"
    >>> print(A.my_var)
        shagun

Instantievariabelen:Variabelen die gerelateerd zijn aan en toegankelijk zijn per instantie van een klasse, zijn instantievariabelen.

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

Statische methoden:Net als bij variabelen, kunnen statische methoden direct worden benaderd met behulp van klassenaam. U hoeft geen instantie te maken.

Maar houd er rekening mee dat een statische methode geen niet-statische methode in python kan aanroepen.

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

Antwoord 13

Met betrekking tot deze answerkunt u voor een constantestatische variabele een descriptor. Hier is een voorbeeld:

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

resulterend in …

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

Je kunt altijd een uitzondering maken als het stilletjes negeren van de instellingswaarde (passhierboven) niet jouw ding is. Als u op zoek bent naar een statische klassevariabele in C++, Java-stijl:

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

Bekijk dit antwoorden de officiële documenten HOWTOvoor meer informatie over descriptors.


Antwoord 14

Absoluut Ja,
Python op zichzelf heeft geen expliciete statische gegevens, maar we kunnen dit wel hebben

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())

uitvoer

0
0
1
1

uitleg

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

Antwoord 15

Om mogelijke verwarring te voorkomen, zou ik statische variabelen en onveranderlijke objecten willen contrasteren.

Sommige primitieve objecttypes zoals integers, floats, strings en touples zijn onveranderlijk in Python. Dit betekent dat het object waarnaar wordt verwezen met een bepaalde naam niet kan veranderen als het een van de bovengenoemde objecttypen is. De naam kan opnieuw worden toegewezen aan een ander object, maar het object zelf mag niet worden gewijzigd.

Het statisch maken van een variabele gaat nog een stap verder door de variabelenaam niet toe te staan ​​naar een ander object te verwijzen dan dat waarnaar het momenteel verwijst. (Opmerking: dit is een algemeen softwareconcept en niet specifiek voor Python; zie de berichten van anderen voor informatie over het implementeren van statica in Python).


Antwoord 16

De beste manier die ik heb gevonden is om een ​​andere klasse te gebruiken. U kunt een object maken en het vervolgens op andere objecten gebruiken.

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()

Met het bovenstaande voorbeeld heb ik een klasse gemaakt met de naam staticFlag.

Deze klasse zou de statische var __success(Private Static Var) moeten presenteren.

tryItklasse vertegenwoordigde de reguliere klasse die we moeten gebruiken.

Nu heb ik een object gemaakt voor één vlag (staticFlag). Deze vlag wordt verzonden als referentie naar alle reguliere objecten.

Al deze objecten worden toegevoegd aan de lijst tryArr.


Dit script resulteert:

False
False
False
False
False
True
True
True
True
True

Antwoord 17

Statische variabelen in klasse fabriek python3.6

Voor iedereen die een klassenfabriek gebruikt met python3.6en hoger, gebruik het sleutelwoord nonlocalom het toe te voegen aan het bereik / de context van de klasse die wordt gemaakt, zoals:

>>> 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

Antwoord 18

Dit is dus waarschijnlijk een hack, maar ik heb eval(str)gebruikt om een ​​statisch object te verkrijgen, een soort tegenstrijdigheid, in python 3.

Er is een Records.py-bestand dat niets anders heeft dan class-objecten die zijn gedefinieerd met statische methoden en constructors die enkele argumenten opslaan. Vervolgens import Records, maar ik moet elk object dynamisch selecteren en vervolgens op verzoek instantiëren op basis van het type gegevens dat wordt ingelezen.

Dus waar object_name = 'RecordOne'of de klassenaam, noem ik cur_type = eval(object_name)en om het te instantiëren doe je cur_inst = cur_type(args)
Voordat u echter een instantie maakt, kunt u statische methoden aanroepen van bijvoorbeeld cur_type.getName(), een soort abstracte basisklasse-implementatie of wat het doel ook is. In de backend is het echter waarschijnlijk geïnstantieerd in python en is het niet echt statisch, omdat eval een object retourneert….dat moet zijn geïnstantieerd….dat geeft statisch gedrag.


Antwoord 19

@dataclass-definities bieden namen op klasseniveau die worden gebruikt om de instantievariabelen en de initialisatiemethode __init__()te definiëren. Als u een variabele op klasseniveau in @dataclasswilt, moet u typing.ClassVartyp hint. De parameters van het type ClassVarbepalen het type van de variabele op klasseniveau.

from typing import ClassVar
from dataclasses import dataclass
@dataclass
class Test:
    i: ClassVar[int] = 10
    x: int
    y: int
    def __repr__(self):
        return f"Test({self.x=}, {self.y=}, {Test.i=})"

Gebruiksvoorbeelden:

> test1 = Test(5, 6)
> test2 = Test(10, 11)
> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)

Antwoord 20

U kunt een lijst of een woordenboek gebruiken om “statisch gedrag” tussen instanties te krijgen.

class Fud:
     class_vars = {'origin_open':False}
     def __init__(self, origin = True):
         self.origin = origin
         self.opened = True
         if origin:
             self.class_vars['origin_open'] = True
     def make_another_fud(self):
         ''' Generating another Fud() from the origin instance '''
         return Fud(False)
     def close(self):
         self.opened = False
         if self.origin:
             self.class_vars['origin_open'] = False
fud1 = Fud()
fud2 = fud1.make_another_fud()
print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True
fud1.close()
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False

Antwoord 21

Als u probeert een statische variabele te delen om deze bijvoorbeeld over andere instanties te vergroten, werkt zoiets als dit script prima:

# -*- coding: utf-8 -*-
class Worker:
    id = 1
    def __init__(self):
        self.name = ''
        self.document = ''
        self.id = Worker.id
        Worker.id += 1
    def __str__(self):
        return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')
class Workers:
    def __init__(self):
        self.list = []
    def add(self, name, doc):
        worker = Worker()
        worker.name = name
        worker.document = doc
        self.list.append(worker)
if __name__ == "__main__":
    workers = Workers()
    for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
        workers.add(item[0], item[1])
    for worker in workers.list:
        print(worker)
    print("next id: %i" % Worker.id)

Antwoord 22

Zet het zo: de statische variabele wordt gemaakt wanneer een door de gebruiker gedefinieerde klasse ontstaat en definieert een statische variabele die het trefwoord zelf moet volgen,

class Student:
    the correct way of static declaration
    i = 10
    incorrect
    self.i = 10

Antwoord 23

Niet zoals de @staticmethod, maar klassevariabelen zijn een statische klassemethode en worden gedeeld met alle instanties.

Je hebt er nu toegang toe

instance = MyClass()
print(instance.i)

of

print(MyClass.i)

u moet de waarde aan deze variabelen toewijzen

Ik probeerde

class MyClass:
  i: str

en het toewijzen van de waarde in één methodeaanroep, in dat geval zal het niet werken en zal er een fout optreden

i is not attribute of MyClass

Antwoord 24

Met Object datatypes is het mogelijk. Maar met primitieve typen zoals int, boolenz. is het gedrag anders dan bij andere OOP.

Voorbeeld:

class A:
    static = 1
class B(A):
    pass
print(f"int {A.static}")  # get 1 correctly
print(f"int {B.static}")  # get 1 correctly
A.static = 5
print(f"int {A.static}")  # get 5 correctly
print(f"int {B.static}")  # get 5 correctly
B.static = 6
print(f"int {A.static}")  # expected 6, but get 5 incorrectly
print(f"int {B.static}")  # get 6 correctly
A.static = 7
print(f"int {A.static}")  # get 7 correctly
print(f"int {B.static}")  # get unchanged 6

Oplossing gebaseerd op refdatatypesbibliotheek:

from refdatatypes.refint import RefInt
class AAA:
    static = RefInt(1)
class BBB(AAA):
    pass
print(f"refint {AAA.static.value}")  # get 1 correctly
print(f"refint {BBB.static.value}")  # get 1 correctly
AAA.static.value = 5
print(f"refint {AAA.static.value}")  # get 5 correctly
print(f"refint {BBB.static.value}")  # get 5 correctly
BBB.static.value = 6
print(f"refint {AAA.static.value}")  # get 6 correctly
print(f"refint {BBB.static.value}")  # get 6 correctly
AAA.static.value = 7
print(f"refint {AAA.static.value}")  # get 7 correctly
print(f"refint {BBB.static.value}")  # get 7 correctly

Other episodes