Czy statyczne zmienne klas są możliwe w Pythonie?

Czy możliwe jest posiadanie statycznych zmiennych klas lub metod w Pythonie? Jaka składnia jest wymagana, aby to zrobić?

Author: Georgy, 2008-09-16

22 answers

Zmienne zadeklarowane wewnątrz definicji klasy, ale nie wewnątrz metody są zmiennymi klasy lub statycznymi:

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

Jak wskazuje @ millerdev , tworzy to zmienną na poziomie klasy i, ale różni się to od każdej zmiennej na poziomie instancji i, więc możesz mieć

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

To różni się od C++ i Javy, ale nie tak bardzo od C#, gdzie statyczny członek nie może być dostępny za pomocą odniesienia do instancji.

Zobacz co ma zrobić samouczek Pythona powiedzieć na temat klas i obiektów klas .

@ Steve Johnson już odpowiedział na temat metod statycznych , udokumentowanych również Pod "wbudowane funkcje" w referencji Biblioteki Pythona .

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

@ beidy zalecaclassmethod s nad staticmethod, ponieważ metoda otrzymuje typ klasy jako pierwszy argument, ale nadal jestem trochę niejasny co do zalet tego podejścia nad staticmethod. Jeśli ty też, to prawdopodobnie nie Materia.

 2013
Author: Blair Conrad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-16 06:06:59

@Blair Conrad powiedział, że zmienne statyczne zadeklarowane wewnątrz definicji klasy, ale nie wewnątrz metody są zmiennymi klasy lub "statycznymi":

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

Jest tu kilka gotcha ' s. Kontynuując z powyższego przykładu:

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

Zwróć uwagę, jak zmienna instancji t.i została zsynchronizowana ze zmienną klasy "static", gdy atrybut i został ustawiony bezpośrednio na t. Jest to spowodowane tym, że i została ponownie powiązana z przestrzenią nazw t, która różni się od przestrzeni nazw Test. Jeśli chcesz zmienić wartość zmiennej "statycznej", musisz zmienić ją w zakresie (lub obiekcie), w którym została pierwotnie zdefiniowana. Wstawiam" static " w cudzysłowie, ponieważ Python tak naprawdę nie ma zmiennych statycznych w tym sensie, co robią C++ i Java.

Chociaż nie mówi nic konkretnego o zmiennych statycznych lub metodach, samouczek Pythona zawiera kilka istotnych informacji o klasach i obiektach klas .

@Steve Johnson odpowiedział również w sprawie metody statyczne, udokumentowane również pod "wbudowanymi funkcjami" W referencji Biblioteki Pythona.

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

@beid wspomniał również o classmethod, która jest podobna do staticmethod. Pierwszym argumentem classmethod jest obiekt class. Przykład:

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

Obrazkowe Przedstawienie Powyższego Przykładu

 655
Author: millerdev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-11 06:06:58

Metody statyczne i klasowe

Jak zauważyły inne odpowiedzi, metody statyczne i klasowe są łatwo realizowane za pomocą wbudowanych dekoratorów:]}
class Test(object):

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

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

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

Jak zwykle, pierwszy argument {[12] } jest związany z obiektem instancji klasy. W przeciwieństwie do tego, pierwszy argument MyClassMethod() jest powiązany z samym obiektem klasy (np. w tym przypadku Test). Dla MyStaticMethod() żaden z argumentów nie jest związany, a posiadanie argumentów w ogóle jest opcjonalne.

"Static Zmienne "

Jednak implementowanie "zmiennych statycznych" (cóż, zmiennych statycznych, jeśli nie jest to sprzeczność w kategoriach...) nie jest tak prosta. Jak zauważył millerdev w swojej odpowiedzi , problem polega na tym, że atrybuty klas Pythona nie są naprawdę "zmiennymi statycznymi". Rozważyć:

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

Dzieje się tak dlatego, że linia {[16] } dodała nowy atrybut instancji i do x zamiast zmieniać wartość klasy Test i atrybut.

częściowe oczekiwane zachowanie zmiennej statycznej, tj. synchronizacja atrybutu między wieloma instancjami (ale Nie z samą klasą; patrz "gotcha" poniżej), może być osiągnięte poprzez przekształcenie atrybutu klasy w właściwość:

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)

Teraz możesz zrobić:

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

Zmienna statyczna pozostanie zsynchronizowana pomiędzy wszystkimi instancjami klasy .

(uwaga: to znaczy, chyba że instancja klasy zdecyduje się zdefiniować własną wersję _i! Ale jeśli ktoś zdecyduje się to zrobić, zasługuje na to, co dostanie, prawda???)

Zauważ, że technicznie rzecz biorąc, i w ogóle nie jest 'zmienną statyczną'; jest to property, który jest specjalnym typem deskryptora. Jednak zachowanie property jest teraz równoważne zmiennej statycznej synchronizowanej we wszystkich instancjach klasy.

Niezmienne "Zmienne Statyczne"

Dla niezmiennego zachowania zmiennej statycznej, po prostu pomiń setterproperty:

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)

Teraz próba ustawienia instancji i atrybutu zwróci AttributeError:

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

One Gotcha to be Aware of

Zauważ, że powyższe metody działają tylko z instancjami twojej klasy - będą, a nie działaćpodczas używania samej klasy . Tak na przykład:

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'

Linia assert Test.i == x.i generuje błąd, ponieważ i atrybut Test i x są dwoma różnymi obiektami.

Wiele osób uzna to za zaskakujące. Jednak to nie powinno być. Jeśli wrócimy i sprawdzimy naszą Test definicję klasy (druga wersja), przyjrzymy się tej linii:
    i = property(get_i) 

Oczywiście, element i z Test musi być obiektem property, który jest typem obiektu zwracanego z funkcji property.

Jeśli uważasz powyższe za mylące, najprawdopodobniej nadal myślisz o tym z perspektywy innych języków (np. Java lub c++). Powinieneś przestudiować obiekt property, o kolejności w jakiej atrybuty Pythona zwracane są, protokół deskryptora oraz metoda resolution order (MRO).

Przedstawiam rozwiązanie powyższego "mam cię" poniżej; jednak sugerowałbym-usilnie - abyś nie próbował robić czegoś takiego jak poniżej, dopóki-przynajmniej-nie zrozumiesz dokładnie, dlaczego {38]} powoduje błąd.

rzeczywiste, rzeczywiste zmienne statyczne - Test.i == x.i

Poniżej przedstawiam rozwiązanie (Python 3) wyłącznie w celach informacyjnych. Nie popieram tego jako " dobrego rozwiązanie". Mam wątpliwości, czy emulowanie zachowania zmiennych statycznych innych języków w Pythonie jest kiedykolwiek konieczne. Jednakże, niezależnie od tego, czy jest on rzeczywiście użyteczny, poniższe informacje powinny pomóc w dalszym zrozumieniu, jak działa Python.

UPDATE: this attempt is really pretty awful ; if you present to do something like this (hint: please don ' t; Python is a very elegant language and shoe-horning it into behind like another language is just not konieczne), zamiast tego użyj kodu w odpowiedzi Ethana Furmana.

Emulowanie zachowania zmiennych statycznych innych języków przy użyciu metaklasy

Metaklasa jest klasą klasy. Domyślną metaklasą dla wszystkich klas w Pythonie (tj. klas" nowego stylu " po Pythonie 2.3, jak sądzę) jest type. Na przykład:

type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'
Możesz jednak zdefiniować swoją metaklasę w następujący sposób:]}
class MyMeta(type): pass

I zastosuj go do własnej klasy w ten sposób (Python 3 tylko):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Poniżej znajduje się metaklasa, którą stworzyłem, która próbuje naśladować zachowanie "zmiennych statycznych" innych języków. Zasadniczo działa poprzez zastąpienie domyślnego gettera, settera i deletera wersjami, które sprawdzają, czy żądany atrybut jest "zmienną statyczną".

Katalog "zmiennych statycznych" jest przechowywany w atrybucie StaticVarMeta.statics. Wszystkie żądania atrybutów są początkowo próbowane zostać rozwiązane przy użyciu zastępczej kolejności rozstrzygania. Dubbingowałem to "statyczny porządek rozdzielczości" lub "SRO". Odbywa się to poprzez wyszukanie żądanego atrybutu w zbiorze "zmiennych statycznych" dla danej klasy (lub jej klas nadrzędnych). Jeśli atrybut nie pojawi się w "SRO", Klasa powróci do domyślnego atrybutu get/set/delete (tj. "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
 216
Author: Rick supports Monica,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-08 16:12:57

Możesz również dodawać zmienne klas do klas w locie

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

I instancje klasy mogą zmieniać zmienne klasy

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

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

>python test.py
[1]
[1, 1]
 36
Author: Gregory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-24 17:43:30

Osobiście używałem classmethod, gdy potrzebowałem statycznej metody. Głównie dlatego, że traktuję klasę jako argument.

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

Lub użyć dekoratora

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

Dla właściwości statycznych.. Czas poszukać definicji Pythona.. zmienna zawsze może się zmieniać. Istnieją dwa ich typy mutowalne i niezmienne.. Istnieją również atrybuty klas i atrybuty instancji.. Nie ma to jak statyczne atrybuty w sensie java & c++

Po co stosować metodę statyczną w zmysł pythoniczny, jeśli nie ma żadnego związku z klasą! Na Twoim miejscu albo użyłbym classmethod, albo zdefiniowałbym metodę niezależną od klasy.

 21
Author: emb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 23:29:49

Należy zwrócić szczególną uwagę na właściwości statyczne i właściwości instancji, pokazane w poniższym przykładzie:

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

Oznacza to, że przed przypisaniem wartości do właściwości instance, jeśli spróbujemy uzyskać dostęp do właściwości thru ' instance, zostanie użyta wartość statyczna. Każda właściwość zadeklarowana w klasie Pythona ma zawsze statyczny slot w pamięci .

 18
Author: jondinham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-08 06:06:05

Statyczne metody w Pythonie nazywane są classmethod s. spójrz na następujący kod

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

Zauważ, że gdy wywołujemy metodę myInstanceMethod , otrzymujemy błąd. Dzieje się tak, ponieważ wymaga, aby metoda była wywoływana na instancji tej klasy. Metoda myStaticMethod {[8] } jest ustawiana jako classmethod za pomocą dekoratora @classmethod .

Po prostu dla zabawy, możemy zadzwonić do myInstanceMethod na zajęcia, przechodząc w przypadku klasy, jak tak:
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
 18
Author: willurd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-12 10:23:57

Gdy zdefiniujemy jakąś zmienną składową poza dowolną metodą składową, zmienna może być statyczna lub niestatyczna w zależności od sposobu wyrażenia zmiennej.

  • Nazwa klasy.var jest zmienną statyczną
  • INSTANCENAME.var nie jest zmienną statyczną.
  • siebie.var wewnątrz klasy nie jest zmienną statyczną.
  • var wewnątrz funkcji członka klasy nie jest zdefiniowany.

Na przykład:

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

Wyniki są

self.var is 2
A.var is 1
self.var is 2
A.var is 3
 13
Author: user2209576,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 11:37:36

Możliwe jest posiadanie zmiennych klasy static, ale prawdopodobnie nie jest to warte wysiłku.

Oto proof-of-concept napisany w Pythonie 3 -- jeśli któreś z dokładnych szczegółów jest błędne, kod można zmodyfikować tak, aby pasował do tego, co masz na myśli przez 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)

I w użyciu:

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

I kilka testów:

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
 11
Author: Ethan Furman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-25 09:02:25

Możesz również wymusić statyczną klasę używając 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

Wtedy, gdy przez przypadek spróbujesz zainicjować MyClass , otrzymasz StaticClassError.

 9
Author: Bartosz Ptaszynski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-20 12:06:23

Bardzo interesującą kwestią dotyczącą wyszukiwania atrybutów Pythona jest to, że można go użyć do tworzenia"wirtualnych zmiennych":

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!

Normalnie nie ma żadnych przypisań do nich po ich utworzeniu. Zauważ, że wyszukiwanie używa self, ponieważ chociaż label jest statyczne w tym sensie, że nie jest powiązane z konkretną instancją, wartość nadal zależy od (klasy) instancji.

 9
Author: Davis Herring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-17 17:19:31

Tak, zdecydowanie możliwe jest pisanie statycznych zmiennych i metod w Pythonie.

Zmienne Statyczne: Zmienna zadeklarowana na poziomie klasy nazywa się zmienną statyczną, do której można uzyskać dostęp bezpośrednio przy użyciu nazwy klasy.

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

    >>> print(A.my_var)
        shagun

Zmienne instancji: zmienne, które są powiązane i dostępne przez instancję klasy są zmiennymi instancji.

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

Statyczne metody: podobnie jak zmienne, statyczne metody mogą być dostępne bezpośrednio przy użyciu nazwy klasy. Nie ma potrzeby. aby utworzyć instancję.

Ale pamiętaj, że statyczna metoda nie może wywołać niestatycznej metody w Pythonie.

    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ... 
   >>> A.my_static_method()
   Yippey!!
 8
Author: Shagun Pruthi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-14 08:01:42

W odniesieniu do tej Odpowiedzi, dla stałej zmiennej statycznej, możesz użyć deskryptora. Oto przykład:

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

W wyniku czego ...

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

Możesz zawsze wywołać wyjątek, jeśli po cichu ignorujesz ustawienie wartości (pass powyżej). Jeśli szukasz statycznej zmiennej klasy w stylu C++, Java:

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
Aby uzyskać więcej informacji na temat deskryptorów, zajrzyj do tej odpowiedzi oraz do oficjalnych dokumentów HOWTO.
 7
Author: Yann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:14

Absolutnie Tak., Python sam w sobie nie ma żadnego statycznego członka danych jawnie, ale możemy mieć w ten sposób

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

Wyjście

0
0
1
1

Wyjaśnienie

here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
 7
Author: Mari Selvan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-22 13:01:13

Aby uniknąć potencjalnych nieporozumień, chciałbym kontrastować zmienne statyczne i Obiekty niezmienne.

Niektóre prymitywne typy obiektów, takie jak liczby całkowite, pływaki, ciągi i touple, są niezmienne w Pythonie. Oznacza to, że obiekt, do którego odnosi się dana nazwa, nie może się zmienić, jeśli należy do jednego z wyżej wymienionych typów obiektów. Nazwę można przypisać do innego obiektu, ale sam obiekt nie może zostać zmieniony.

Zrobienie zmiennej statycznej prowadzi to o krok dalej poprzez wyłączenie nazwy zmiennej wskazującej na dowolny obiekt poza tym, do którego aktualnie wskazuje. (Uwaga: jest to ogólna koncepcja oprogramowania, a nie specyficzna dla Pythona; Zobacz posty innych, aby uzyskać informacje na temat implementacji statyki w Pythonie).

 5
Author: Ross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 04:01:08

Najlepszy sposób, jaki znalazłem, to użycie innej klasy. Obiekt można utworzyć, a następnie użyć go na innych obiektach.

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

Z powyższego przykładu stworzyłem klasę o nazwie staticFlag.

Klasa ta powinna prezentować statyczny var __success (prywatny statyczny Var).

tryIt klasa reprezentuje zwykłą klasę, której musimy użyć.

Teraz zrobiłem obiekt dla jednej flagi (staticFlag). Ta flaga zostanie wysłana jako odniesienie do wszystkich zwykłych obiektów.

Wszystkie te obiekty są dodawane do lista tryArr.


Wyniki Tego Skryptu:

False
False
False
False
False
True
True
True
True
True
 5
Author: Tomer Zait,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-19 23:42:58

Zmienne statyczne w klasie factory python3. 6

Dla każdego, kto używa fabryki klasy z python3.6 i w górę, Użyj słowa kluczowego nonlocal, aby dodać go do zakresu / kontekstu tworzonej klasy w ten sposób:

>>> 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
 2
Author: jmunsch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Więc to prawdopodobnie hack, ale używałem eval(str), aby uzyskać statyczny obiekt, rodzaj sprzeczności, w Pythonie 3.

Istnieje Records.py plik zawierający tylko {[1] } obiekty zdefiniowane za pomocą statycznych metod i konstruktorów, które zapisują niektóre argumenty. Następnie z innego pliku. py i import Records ale muszę dynamicznie zaznaczać każdy obiekt, a następnie tworzyć instancje na żądanie zgodnie z typem odczytywanych danych.

Więc gdzie object_name = 'RecordOne' lub nazwa klasy, wywołuję cur_type = eval(object_name) i wtedy aby utworzyć instancję to robisz cur_inst = cur_type(args) Jednak zanim utworzysz instancję, możesz wywołać statyczne metody z cur_type.getName(), na przykład, coś w rodzaju abstrakcyjnej implementacji klasy bazowej lub cokolwiek jest celem. Jednak w backendzie, prawdopodobnie jest to instancja w Pythonie i nie jest naprawdę statyczny, ponieważ eval zwraca obiekt....które musiały zostać utworzone....to daje statyczne zachowanie.

 2
Author: Christopher Hoffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-07 12:34:27

Możesz użyć listy lub słownika, aby uzyskać "statyczne zachowanie" między instancjami.

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
 1
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-03 18:27:09

Jeśli próbujesz udostępnić zmienną statyczną, na przykład zwiększając ją między innymi instancjami, coś takiego jak ten skrypt działa dobrze:

# -*- 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)
 1
Author: Winter Squad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-14 19:39:42

Ująć to w ten sposób zmienna statyczna jest tworzona, gdy istnieje zdefiniowana przez użytkownika Klasa A, A zdefiniowana zmienna statyczna powinna podążać za słowem kluczowym self,

class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10
 0
Author: ganja,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-17 19:36:14

@ dataclass definicje zawierają nazwy poziomów klas, które są używane do definiowania zmiennych instancji i metody inicjalizacji, __init__(). Jeśli chcesz mieć zmienną na poziomie klasy w @dataclass powinieneś użyć typing.ClassVar wpisz podpowiedź. Parametry typu ClassVar definiują typ zmiennej na poziomie klasy.

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=})"

Przykłady użycia:

> 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)
 0
Author: Vlad Bezden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-27 12:00:07