it-swarm-eu.dev

Sind statische Klassenvariablen in Python möglich?

Ist es möglich, statische Klassenvariablen oder Methoden in Python zu haben? Welche Syntax ist dafür erforderlich?

1765
Andrew Walker

Variablen, die in der Klassendefinition, aber nicht in einer Methode deklariert sind, sind Klassen- oder statische Variablen:

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

Wie @ millerdev zeigt, wird eine i -Variable auf Klassenebene erstellt, die sich jedoch von allen i -Variablen auf Instanzebene unterscheidet

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

Dies unterscheidet sich von C++ und Java, aber nicht so sehr von C #, wo auf ein statisches Element nicht über einen Verweis auf eine Instanz zugegriffen werden kann.

Siehe was das Tutorial Python zum Thema Klassen und Klassenobjekte zu sagen hat .

@Steve Johnson hat bereits zu statische Methoden geantwortet, auch dokumentiert unter "Built-in Functions" in der Python Library Reference .

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

@beidy empfiehlt classmethod s gegenüber staticmethod, da die Methode dann den Klassentyp als erstes Argument erhält, aber ich bin immer noch ein wenig verwirrt über die Vorteile dieses Ansatzes gegenüber staticmethod. Wenn Sie auch sind, dann ist es wahrscheinlich egal.

1738
Blair Conrad

@Blair Conrad sagte, dass statische Variablen, die in der Klassendefinition deklariert sind, aber nicht in einer Methode, Klassen- oder "statische" Variablen sind:

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

Es gibt ein paar Fallstricke hier. Weiter wie im obigen Beispiel:

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

Beachten Sie, dass die Instanzvariable t.i nicht mehr mit der "statischen" Klassenvariablen synchronisiert war, als das Attribut i direkt auf t gesetzt wurde. Dies liegt daran, dass i innerhalb des t-Namespace neu gebunden wurde, der sich vom Test-Namespace unterscheidet. Wenn Sie den Wert einer "statischen" Variablen ändern möchten, müssen Sie ihn in dem Bereich (oder Objekt) ändern, in dem er ursprünglich definiert wurde. Ich habe "static" in Anführungszeichen gesetzt, weil Python nicht wirklich statische Variablen in dem Sinne hat, wie es C++ und Java tun.

Das Python-Tutorial enthält einige relevante Informationen zu Klassen und Klassenobjekte , obwohl es keine spezifischen Informationen zu statischen Variablen oder Methoden enthält.

@Steve Johnson antwortete auch bezüglich statischer Methoden, die ebenfalls unter "Built-in Functions" in der Python Library Reference dokumentiert sind.

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

@beid erwähnte auch classmethod, ähnlich staticmethod. Das erste Argument einer Klassenmethode ist das Klassenobjekt. Beispiel:

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

574
millerdev

Statische und Klassenmethoden

Wie die anderen Antworten bereits angemerkt haben, können statische Methoden und Klassenmethoden mit den eingebauten Dekoratoren leicht ausgeführt werden:

class Test(object):

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

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

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

Wie üblich ist das erste Argument für MyMethod() an das Klasseninstanzobjekt gebunden. Im Gegensatz dazu ist das erste Argument für MyClassMethod()an das Klassenobjekt selbst gebunden (z. B. in diesem Fall Test). Für MyStaticMethod() ist keines der Argumente gebunden, und es ist optional, überhaupt Argumente zu haben.

Statische Variablen

Das Implementieren von "statischen Variablen" (naja, veränderlich statische Variablen, falls dies kein Widerspruch ist ...) ist jedoch nicht so einfach. Wie millerdev in seiner Antwort hervorgehoben , besteht das Problem darin, dass Pythons Klassenattribute keine echten "statischen Variablen" sind. Erwägen:

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

Dies liegt daran, dass die Zeile x.i = 12 ein neues Instanzattribut i zu x hinzugefügt hat, anstatt den Wert des Attributs Test class i zu ändern.

Partial erwartetes Verhalten statischer Variablen, dh Synchronisation des Attributs zwischen mehreren Instanzen (aber nicht mit der Klasse selbst; siehe " "gotcha" weiter unten) kann erreicht werden, indem das class-Attribut in eine Eigenschaft umgewandelt wird:

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)

Jetzt können Sie Folgendes tun:

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

Die statische Variable bleibt nun synchron zwischen allen Klasseninstanzen.

(ANMERKUNG: Das heißt, es sei denn, eine Klasseninstanz definiert ihre eigene Version von _i! Aber wenn sich jemand dafür entscheidet, verdienen sie das, was sie bekommen, nicht wahr ???)

Beachten Sie, dass i technisch gesehen immer noch keine 'statische Variable' ist. es ist ein property, ein spezieller Deskriptortyp. Das Verhalten von property entspricht jetzt jedoch einer (veränderlichen) statischen Variablen, die über alle Klasseninstanzen hinweg synchronisiert wird.

Unveränderliche "statische Variablen"

Lassen Sie für unveränderliches Verhalten statischer Variablen einfach den property -Setter 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)

Wenn Sie nun versuchen, das Instanzattribut i festzulegen, wird AttributeError zurückgegeben:

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

Ein Gotcha, dessen man sich bewusst sein muss

Beachten Sie, dass die obigen Methoden nur mit Instanzen Ihrer Klasse funktionieren - sie funktionieren nicht wenn Sie die Klasse verwenden selbst. Also zum Beispiel:

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'

Die Zeile assert Test.i == x.i erzeugt einen Fehler, weil das i -Attribut von Test und x zwei verschiedene Objekte sind.

Viele Leute werden dies überraschend finden. Es sollte jedoch nicht sein. Wenn wir zurückgehen und unsere Klassendefinition Test (die zweite Version) überprüfen, nehmen wir folgende Zeile zur Kenntnis:

    i = property(get_i) 

Es ist klar, dass das Mitglied i von Test ein property Objekt sein muss. Dies ist der Objekttyp, der von der Funktion property zurückgegeben wird.

Wenn Sie dies verwirrend finden, denken Sie höchstwahrscheinlich immer noch aus der Perspektive anderer Sprachen (z. B. Java oder c ++) darüber nach. Sie sollten das Objekt property in der Reihenfolge untersuchen, in der Python Attribute zurückgegeben werden, das Deskriptorprotokoll und die Reihenfolge der Methodenauflösung (MRO).

Ich präsentiere eine Lösung für das obige 'Gotcha' unten; Ich würde jedoch - mit Nachdruck - vorschlagen, dass Sie nicht versuchen, etwas wie das Folgende zu tun, bis Sie - zumindest - gründlich verstehen, warum assert Test.i = x.i einen Fehler verursacht.

REAL, ACTUAL Statische Variablen - Test.i == x.i

Ich präsentiere die (Python 3) -Lösung unten nur zu Informationszwecken. Ich unterstütze es nicht als "gute Lösung". Ich habe meine Zweifel, ob es jemals wirklich notwendig ist, das Verhalten statischer Variablen anderer Sprachen in Python zu emulieren. Unabhängig davon, ob dies tatsächlich nützlich ist, soll das Folgende das Verständnis der Funktionsweise von Python verbessern.

UPDATE: dieser Versuch ist wirklich ziemlich schrecklich ; Wenn Sie darauf bestehen, so etwas zu tun (Hinweis: Bitte nicht; Python ist eine sehr elegante Sprache, und Sie müssen sich so verhalten, als ob eine andere Sprache einfach nicht erforderlich wäre), verwenden Sie den Code in - Ethan Furmans Antwort stattdessen.

Emulieren des Verhaltens statischer Variablen anderer Sprachen mithilfe einer Metaklasse

Eine Metaklasse ist die Klasse einer Klasse. Die Standard-Metaklasse für alle Klassen in Python (d. H. Die Klassen "neuen Stils" nach Python 2.3, glaube ich) ist type. Zum Beispiel:

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

Sie können jedoch Ihre eigene Metaklasse wie folgt definieren:

class MyMeta(type): pass

Und wenden Sie es auf Ihre eigene Klasse wie folgt an (nur Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Unten ist eine von mir erstellte Metaklasse, die versucht, das Verhalten "statischer Variablen" anderer Sprachen zu emulieren. Grundsätzlich wird der Standard-Getter, Setter und Deleter durch Versionen ersetzt, die prüfen, ob es sich bei dem angeforderten Attribut um eine "statische Variable" handelt.

Ein Katalog der "statischen Variablen" ist im Attribut StaticVarMeta.statics gespeichert. Zunächst wird versucht, alle Attributanforderungen mithilfe einer Ersatzauflösungsreihenfolge aufzulösen. Ich habe dies die "statische Auflösungsreihenfolge" oder "SRO" genannt. Suchen Sie dazu nach dem angeforderten Attribut in der Gruppe der "statischen Variablen" für eine bestimmte Klasse (oder deren übergeordnete Klassen). Wenn das Attribut nicht in der "SRO" erscheint, greift die Klasse auf das Standard-Attribut "get/set/delete" (d. H. "MRO") zurück.

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
175
Rick Teachey

Sie können Klassenvariablen auch spontan zu Klassen hinzufügen

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

Und Klasseninstanzen können Klassenvariablen ändern

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

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

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

Persönlich würde ich eine Klassenmethode verwenden, wenn ich eine statische Methode brauchte. Hauptsächlich weil ich die Klasse als Argument bekomme.

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

oder benutze einen Dekorateur

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

Für statische Eigenschaften. Es ist an der Zeit, dass Sie eine python -Definitionsvariable nachschlagen. Die Variable kann sich immer ändern. Es gibt zwei Typen von ihnen, die veränderlich und unveränderlich sind. Außerdem gibt es Klassenattribute und Instanzattribute. Nichts Vergleichbares zu statischen Attributen im Sinne von Java & c ++

Warum statische Methoden im pythonischen Sinne verwenden, wenn sie keinerlei Beziehung zur Klasse haben? Wenn ich Sie wäre, würde ich entweder Klassenmethode verwenden oder die Methode unabhängig von der Klasse definieren.

15
emb

Statische Methoden in python heißen Klassenmethode s. Schauen Sie sich den folgenden Code an

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

Beachten Sie, dass beim Aufrufen der Methode myInstanceMethod eine Fehlermeldung angezeigt wird. Dies liegt daran, dass die Methode für eine Instanz dieser Klasse aufgerufen werden muss. Die Methode myStaticMethod wird mit decorator @ classmethod als Klassenmethode festgelegt.

Nur für Kicks und Gekicher könnten wir myInstanceMethod für die Klasse aufrufen, indem wir eine Instanz der Klasse übergeben, wie folgt:

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

Eine besondere Anmerkung zu statischen Eigenschaften und Instanzeigenschaften, die im folgenden Beispiel gezeigt wird:

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

Dies bedeutet, dass vor dem Zuweisen des Werts zur Instanzeigenschaft der statische Wert verwendet wird, wenn versucht wird, über die Instanz auf die Eigenschaft zuzugreifen. Jede in der Klasse python deklarierte Eigenschaft hat immer einen statischen Speicherplatz.

13
jondinham

Wenn Sie eine Mitgliedervariable außerhalb einer Mitgliedermethode definieren, kann die Variable entweder statisch oder nicht statisch sein, je nachdem, wie die Variable ausgedrückt wird.

  • CLASSNAME.var ist eine statische Variable
  • INSTANCENAME.var ist keine statische Variable.
  • self.var innerhalb der Klasse ist keine statische Variable.
  • var innerhalb der Klassenmitgliedsfunktion ist nicht definiert.

Zum Beispiel:

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

Die Ergebnisse sind

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

Es ist möglich, static Klassenvariablen zu haben, aber der Aufwand lohnt sich wahrscheinlich nicht.

Hier ist ein Proof-of-Concept, der in Python 3 geschrieben wurde. Wenn einige der genauen Details falsch sind, kann der Code so angepasst werden, dass er genau mit dem übereinstimmt, was Sie mit static variable meinen:


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)

und in Gebrauch:

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

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

Sie können eine Klasse auch mithilfe von Metaklassen als statisch erzwingen.

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

Wenn Sie dann versehentlich versuchen, MyClass zu initialisieren, erhalten Sie einen StaticClassError.

6

Ein sehr interessanter Punkt bei Pythons Attributsuche ist, dass damit " virtual variables" erstellt werden können:

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!

Normalerweise gibt es keine Zuordnungen zu diesen, nachdem sie erstellt wurden. Beachten Sie, dass bei der Suche self verwendet wird, da label zwar statisch ist, jedoch nicht mit einer bestimmten Instanz verknüpft ist. Der Wert hängt immer noch von der (Klasse der) Instanz ab.

5
Davis Herring

Absolut ja, Python selbst hat kein explizites statisches Datenelement, aber wir können dies tun

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

ausgabe

0
0
1
1

erläuterung

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

In Bezug auf diese Antwort können Sie für eine konstante statische Variable einen Deskriptor verwenden. Hier ist ein Beispiel:

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

ergebend ...

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

Sie können immer eine Ausnahme auslösen, wenn es nicht Ihre Sache ist, den Einstellungswert (pass oben) stillschweigend zu ignorieren. Wenn Sie nach einer statischen Klassenvariablen im Stil von C++Java suchen:

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

Schauen Sie sich diese Antwort und die offiziellen Dokumente HOWTO an, um weitere Informationen zu Deskriptoren zu erhalten.

4
Yann

Der beste Weg, den ich gefunden habe, ist, eine andere Klasse zu verwenden. Sie können ein Objekt erstellen und es dann für andere Objekte verwenden.

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

Mit dem obigen Beispiel habe ich eine Klasse namens staticFlag erstellt.

Diese Klasse sollte die statische Variable __success (Private Static Var) darstellen.

tryIt class repräsentiert die reguläre Klasse, die wir verwenden müssen.

Jetzt habe ich ein Objekt für eine Flagge erstellt (staticFlag). Dieses Flag wird als Referenz für alle regulären Objekte gesendet.

Alle diese Objekte werden der Liste tryArr hinzugefügt.


Dieses Skript führt zu:

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

Um mögliche Verwirrungen zu vermeiden, möchte ich statische Variablen und unveränderliche Objekte gegenüberstellen.

Einige primitive Objekttypen wie Ganzzahlen, Gleitkommazahlen, Zeichenfolgen und Tupel sind in Python unveränderlich. Dies bedeutet, dass sich das Objekt, auf das mit einem bestimmten Namen verwiesen wird, nicht ändern kann, wenn es sich um einen der oben genannten Objekttypen handelt. Der Name kann einem anderen Objekt zugewiesen werden, das Objekt selbst darf jedoch nicht geändert werden.

Indem Sie eine Variable statisch machen, gehen Sie noch einen Schritt weiter, indem Sie nicht zulassen, dass der Variablenname auf ein Objekt verweist, das jedoch aktuell darauf verweist. (Hinweis: Dies ist ein allgemeines Softwarekonzept und nicht spezifisch für Python. Informationen zum Implementieren von Statics in Python finden Sie in den Posts anderer.).

3
Ross

Ja, es ist definitiv möglich, statische Variablen und Methoden in Python zu schreiben.

Static Variables: Auf Klassenebene deklarierte Variablen werden als statische Variablen bezeichnet, auf die direkt über den Klassennamen zugegriffen werden kann.

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

    >>> print(A.my_var)
        shagun

Instanzvariablen: Variablen, auf die die Instanz einer Klasse zugreift, sind Instanzvariablen.

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

Static Methods: Ähnlich wie bei Variablen kann auf statische Methoden direkt über den Klassennamen zugegriffen werden. Es muss keine Instanz erstellt werden.

Beachten Sie jedoch, dass eine statische Methode in Python keine nicht statische Methode aufrufen kann.

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

Statische Variablen in der Klassenfactory python3.6

Wenn Sie eine Klassenfactory mit python3.6 und up verwenden, verwenden Sie das Schlüsselwort nonlocal, um es dem Bereich/Kontext der zu erstellenden Klasse wie folgt hinzuzufügen:

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