it-swarm-eu.dev

Jsou možné statické proměnné třídy?

Je možné mít v pythonu proměnné statické třídy nebo metody? Jaká syntaxe je k tomu nutná?

1695
Andrew Walker

Proměnné deklarované uvnitř definice třídy, ale nikoli uvnitř metody, jsou třídy nebo statické proměnné:

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

Jako @ millerdev poukazuje na to, to vytváří proměnnou i na úrovni třídy, ale to je odlišné od proměnné i na úrovni instance, takže byste mohli mít

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

To je odlišné od C++ a Java, ale ne tak odlišné od C #, kde statický člen nelze přistupovat pomocí odkazu na instanci.

Viz co má Python tutoriál říci na téma tříd a třídních objektů .

@Steve Johnson již zodpověděl statické metody , také zdokumentované v "Built-in Functions" v Python Library Reference .

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

@ beidy doporučuje classmethod s přes statickou metodu, protože metoda pak dostává typ třídy jako první argument, ale stále jsem trochu fuzzy o výhodách tohoto přístupu přes statickou metodu. Pokud jste taky, pak to asi nezáleží.

1672
Blair Conrad

@Blair Conrad řekl statické proměnné deklarované uvnitř definice třídy, ale ne uvnitř metody jsou třídy nebo "statické" proměnné:

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

Je tu pár věcí. Pokračujeme z výše uvedeného příkladu:

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

Všimněte si, jak se proměnná instance t.i dostala mimo synchronizaci s proměnnou "statické" třídy, když byl atribut i nastaven přímo na t. Je to proto, že i bylo znovu svázáno v oboru názvů t, který je odlišný od oboru názvů Test. Pokud chcete změnit hodnotu "statické" proměnné, musíte ji změnit v rámci rozsahu (nebo objektu), kde byl původně definován. Dal jsem "statické" do uvozovek, protože Python ve skutečnosti nemá statické proměnné v tom smyslu, že C++ a Java.

Ačkoli to neříká nic konkrétního o statických proměnných nebo metodách, Python tutorial má nějaké relevantní informace o třídách a objektech třídy .

@Steve Johnson také odpověděl na statické metody, také zdokumentované v "Built-in Functions" v Python Library Reference.

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

@ také také zmiňovaná metoda, která je podobná statické metodě. Prvním argumentem třídy je objekt třídy. Příklad:

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

 Pictorial Representation Of Above Example

558
millerdev

Metody statiky a třídy

Jak poznamenala jiná odpověď, statické a třídní metody lze snadno provést pomocí vestavěných dekoratérů:

class Test(object):

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

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

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

Jako obvykle je první argument MyMethod() vázán na objekt třídy instance. Naproti tomu první argument MyClassMethod() je vázán na objekt třídy sám (např. V tomto případě Test). Pro MyStaticMethod(), žádný z argumentů není vázán, a mít argumenty vůbec je nepovinný.

"Statické proměnné"

Nicméně implementace "statických proměnných" (dobře, mutable statických proměnných, stejně, pokud to není rozpor v termínech ...) není tak přímočará. Jak Millerdev poukázal ve své odpovědi , problémem je, že atributy třídy Python nejsou skutečně "statické proměnné". Zvážit:

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

Je to proto, že řádek x.i = 12 přidal nový atribut i do x namísto změny hodnoty atributu Test class i.

Částečné očekávané chování statické proměnné, tj. Synchronizace atributu mezi více instancemi (ale ne se samotnou třídou; viz "gotcha" níže), lze dosáhnout otočením atributu třídy do nemovitosti:

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)

Nyní můžete udělat:

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

Statická proměnná nyní zůstane v synchronizaci mezi všemi instancemi tříd.

(Poznámka: Pokud se instanci třídy nerozhodnou definovat vlastní verzi _i! Pokud se ale někdo rozhodne, že to provede, zaslouží si to, co dostanou, ne ???)

Všimněte si, že technicky řečeno, i stále není 'statickou proměnnou'; je to property, což je speciální typ deskriptoru. Chování property je však nyní ekvivalentní (proměnné) statické proměnné synchronizované ve všech instancích třídy.

Neměnné "statické proměnné"

Pro neměnné chování statických proměnných jednoduše vynechejte parametr property setter:

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)

Při pokusu o nastavení atributu i instance se vrátí AttributeError:

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

Jeden Gotcha být vědom

Všimněte si, že výše uvedené metody fungují pouze s instance vaší třídy - budou ne work při použití třídy samotné. Tak například:

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'

Řádek assert Test.i == x.i vytvoří chybu, protože atribut iTest a x jsou dva různé objekty.

Mnoho lidí to překvapí. Nemělo by to však být. Pokud se vrátíme a zkontrolujeme definici třídy Test (druhá verze), vezmeme na vědomí tento řádek:

    i = property(get_i) 

Člen iTest musí být jednoznačně objekt property, což je typ objektu vráceného z funkce property.

Pokud zjistíte výše zmatené, budete s největší pravděpodobností stále přemýšlet o tom z pohledu jiných jazyků (např. Java nebo c ++). Měli byste jít studovat objekt property, o pořadí, ve kterém jsou vráceny atributy Pythonu, protokolu deskriptoru a pořadí rozlišení metody (MRO).

Předkládám řešení výše uvedené „gotcha“; doporučil bych však - usilovně - aby jste se nepokoušeli dělat něco podobného, ​​dokud - minimálně - důkladně pochopíte, proč assert Test.i = x.i způsobuje chybu.

REAL, ACTUAL Statické proměnné - Test.i == x.i

Řešení (Python 3) prezentuji pouze pro informační účely. Nepodporuji to jako „dobré řešení“. Mám pochybnosti o tom, zda emulace statického proměnného chování jiných jazyků v jazyce Python je skutečně nezbytná. Nicméně, bez ohledu na to, zda je to skutečně užitečné, níže by mělo pomoci další pochopení toho, jak funguje Python.

UPDATE: tento pokus je opravdu dost hrozný ; pokud trváte na tom, že něco takového děláte (nápověda: prosím, ne; Python je velmi elegantní jazyk a to, jak se chovat jako jiný jazyk, není nutné), použijte kód v Ethan Furman odpověď místo .

Emulace chování statických proměnných jiných jazyků pomocí metaklasy

Metaclass je třída třídy. Výchozí metaclass pro všechny třídy v Pythonu (tj. Třídy "nového stylu" po Pythonu 2.3 věřím) je type. Například:

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

Můžete však definovat vlastní metaclass takto:

class MyMeta(type): pass

A aplikujte je na tuto vlastní třídu (pouze Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Níže je uvedena metaklasta, kterou jsem vytvořil a která se pokouší emulovat chování statických proměnných v jiných jazycích. V podstatě funguje tak, že nahrazuje výchozí getter, setter a deleter s verzemi, které kontrolují, zda požadovaný atribut je "statická proměnná".

Katalog "statických proměnných" je uložen v atributu StaticVarMeta.statics. Všechny požadavky na atributy se zpočátku pokoušejí vyřešit pomocí příkazu náhradního rozlišení. Zaznamenal jsem to "statické rozlišení" nebo "SRO". To se provádí hledáním požadovaného atributu v sadě "statických proměnných" pro danou třídu (nebo její nadřazené třídy). Pokud se atribut neobjeví v "SRO", třída se vrátí zpět na výchozí chování atributu 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.__+ " 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.__+ " 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
165
Rick Teachey

Proměnné třídy můžete také přidávat do tříd za běhu

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

Instance třídy mohou měnit proměnné třídy

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

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

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

Osobně bych použil třídu vždy, když bych potřeboval statickou metodu. Hlavně proto, že třídu dostávám jako argument.

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

nebo použít dekoratér

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

Pro statické vlastnosti .. Jeho čas vyhledání nějaké python definice .. proměnná může vždy změnit. Existují dva typy, které jsou proměnlivé a neměnné. Také existují atributy třídy a atributy instancí. Nic takového jako statické atributy ve smyslu Java & c ++

Proč používat statickou metodu ve smyslu Pythonic, pokud nemá vztah k třídě! Kdybych byl tebou, buď bych použil metodu nebo definoval metodu nezávislou na třídě.

15
emb

Statické metody v pythonu se nazývají classmethod s. Podívejte se na následující kód

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

Všimněte si, že když zavoláme metodu myInstanceMethod , dostaneme chybu. Je to proto, že vyžaduje, aby tato metoda byla volána na instanci této třídy. Metoda myStaticMethod je nastavena jako classmethod pomocí decorator @classmethod .

Jen pro kopy a chichotání bychom mohli zavolat myInstanceMethod ve třídě tak, že projdeme instanci třídy, jako je tato:

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

Zvláštní pozornost je třeba věnovat statickým vlastnostem a vlastnostem instance, které jsou uvedeny v následujícím příkladu:

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

To znamená před přiřazením hodnoty vlastnosti instance, pokud se pokusíme o přístup k instanci vlastnosti, použije se statická hodnota. Každá vlastnost deklarovaná ve třídě python má vždy statický slot v paměti .

13
jondinham

Pokud definujete některou proměnnou člena mimo libovolnou metodu členu, proměnná může být buď statická, nebo statická v závislosti na tom, jak je proměnná vyjádřena.

  • CLASSNAME.var je statická proměnná
  • INSTANCENAME.var není statická proměnná.
  • vnitřní třída self.var není statická proměnná.
  • var uvnitř funkce člena třídy není definován.

Například:

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

Výsledky jsou

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

Je možné mít static proměnné třídy, ale pravděpodobně nestojí za námahu.

Zde je důkaz o koncepci napsaný v jazyce Python 3 - pokud jsou některé z přesných údajů chybné, kód může být upraven tak, aby odpovídal cokoliv, co tím myslíš 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)

a v používání:

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

a některé testy:

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
6
Ethan Furman

Můžete také vynutit třídu, která má být statická pomocí metaklass.

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

Pak kdykoliv náhodou se pokusíte inicializovat MyClass dostanete StaticClassError.

6
Bartosz Ptaszynski

Velmi zajímavým bodem o vyhledávání atributů Pythonu je, že může být použit k vytvoření " virtual variable":

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!

Za normálních okolností nejsou po vytvoření vytvořeny žádné úkoly. Všimněte si, že vyhledávání používá self, protože i když label je statické ve smyslu, že není spojeno s konkrétní instance, hodnota stále závisí na instanci (třídy).

5
Davis Herring

Absolutně Ano, Python sám o sobě nemá žádný statický člen dat, ale můžeme tak učinit

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

výstup

0
0
1
1

vysvětlení

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

Pokud jde o tuto odpověď , pro proměnnou constant static, můžete použít deskriptor. Zde je příklad:

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

což má za následek ...

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

Výjimku můžete vždy vyvolat, pokud tichá ignorace hodnoty nastavení (pass výše) není vaše věc. Pokud hledáte proměnnou statické třídy ve 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

Podívejte se na tuto odpověď a oficiální dokumenty HOWTO pro více informací o deskriptorech.

4
Yann

Nejlepší způsob, jak jsem zjistil, je použít jinou třídu. Můžete vytvořit objekt a použít jej na jiné objekty.

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

S výše uvedeným příkladem jsem vytvořil třídu s názvem staticFlag.

Tato třída by měla prezentovat statický var __success (Private Static Var).

Třída tryIt reprezentovala běžnou třídu, kterou potřebujeme použít.

Nyní jsem vytvořil objekt pro jednu vlajku (staticFlag). Tento příznak bude odeslán jako odkaz na všechny běžné objekty.

Všechny tyto objekty jsou přidány do seznamu tryArr.


Výsledky tohoto skriptu:

False
False
False
False
False
True
True
True
True
True
3
Tomer Zait

Aby se zabránilo jakémukoliv zmatku, chtěla bych kontrastovat statické proměnné a neměnné objekty.

Některé primitivní typy objektů, jako jsou celá čísla, plováky, řetězce a dotyky, jsou v Pythonu neměnné. To znamená, že objekt, na který odkazuje dané jméno, se nemůže změnit, pokud je jedním z výše uvedených typů objektů. Název může být přiřazen jinému objektu, ale samotný objekt nesmí být změněn.

Provádění proměnné statické trvá tento krok dále tím, že nepovolí název proměnné, aby ukazoval na libovolný objekt, ale na to, na který momentálně odkazuje. (Poznámka: toto je obecný koncept softwaru a není specifický pro Python; informace o implementaci statiky v Pythonu naleznete v příspěvcích jiných uživatelů).

3
Ross

Ano, určitě je možné psát statické proměnné a metody v pythonu.

Statické proměnné: Proměnná deklarovaná na úrovni třídy se nazývá statická proměnná, ke které lze přistupovat přímo pomocí názvu třídy.

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

    >>> print(A.my_var)
        shagun

Proměnné instance: Proměnné, které jsou příbuzné a přistupují k instanci třídy, jsou proměnné instance.

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

Statické metody: Podobně jako u proměnných lze přistupovat ke statickým metodám přímo pomocí třídy Name. Není třeba vytvářet instanci.

Ale mějte na paměti, že statická metoda nemůže volat nestatickou metodu v pythonu.

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

Statické proměnné v továrně třídy python3.6

Pro kohokoliv, kdo používá továrnu třídy s python3.6 a nahoru, použijte klíčové slovo nonlocal pro přidání do rozsahu/kontextu vytvořené třídy:

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