it-swarm-id.com

Apakah variabel kelas statis mungkin?

Apakah mungkin untuk memiliki variabel kelas statis atau metode dalam python? Sintaks apa yang diperlukan untuk melakukan ini?

1695
Andrew Walker

Variabel yang dideklarasikan di dalam definisi kelas, tetapi tidak di dalam metode adalah variabel kelas atau statis:

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

Seperti @ millerdev tunjukkan, ini menciptakan variabel i tingkat-kelas, tetapi ini berbeda dari variabel i tingkat-tingkat apa pun, sehingga Anda dapat memiliki

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

Ini berbeda dari C++ dan Java, tetapi tidak begitu berbeda dari C #, di mana anggota statis tidak dapat diakses menggunakan referensi ke instance.

Lihat apa yang dikatakan tutorial Python tentang subjek kelas dan objek kelas .

@Steve Johnson telah menjawab mengenai metode statis , juga didokumentasikan di bawah "Fungsi Bawaan" di Referensi Pustaka Python .

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

@beidy merekomendasikan classmethod s lebih dari staticmethod, karena metode ini kemudian menerima tipe kelas sebagai argumen pertama, tapi saya masih agak kabur tentang kelebihan pendekatan ini atas staticmethod. Jika Anda juga, maka itu mungkin tidak masalah.

1672
Blair Conrad

@ Blair Conrad mengatakan variabel statis dideklarasikan di dalam definisi kelas, tetapi tidak di dalam metode adalah variabel kelas atau "statis":

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

Ada beberapa gotcha di sini. Melanjutkan dari contoh di atas:

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

Perhatikan bagaimana variabel instan t.i keluar dari sinkronisasi dengan variabel kelas "statis" ketika atribut i disetel langsung pada t. Ini karena i diikat kembali di dalam namespace t, yang berbeda dari namespace Test. Jika Anda ingin mengubah nilai variabel "statis", Anda harus mengubahnya dalam ruang lingkup (atau objek) di mana ia awalnya didefinisikan. Saya menaruh "statis" dalam tanda kutip karena Python tidak benar-benar memiliki variabel statis dalam arti bahwa C++ dan Java lakukan.

Meskipun tidak mengatakan sesuatu yang spesifik tentang variabel statis atau metode, tutorial Python tutorial memiliki beberapa informasi yang relevan pada kelas dan objek kelas .

@Steve Johnson juga menjawab mengenai metode statis, juga didokumentasikan dalam "Fungsi Bawaan" di Referensi Pustaka Python.

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

@beid juga menyebutkan classmethod, yang mirip dengan staticmethod. Argumen pertama classmethod adalah objek kelas. Contoh:

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

Metode Statis dan Kelas

Seperti yang dicatat oleh jawaban lain, metode statis dan kelas mudah dilakukan dengan menggunakan dekorator bawaan:

class Test(object):

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

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

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

Seperti biasa, argumen pertama ke MyMethod() terikat ke objek instance kelas. Sebaliknya, argumen pertama ke MyClassMethod() adalah terikat pada objek kelas itu sendiri (mis., Dalam kasus ini, Test). Untuk MyStaticMethod(), tidak ada argumen yang terikat, dan memiliki argumen sama sekali adalah opsional.

"Variabel Statis"

Namun, menerapkan "variabel statis" (well, bisa berubah variabel statis, jika tidak ada kontradiksi dalam istilah ...) tidak lurus ke depan. Sebagai millerdev ditunjukkan dalam jawabannya , masalahnya adalah atribut kelas Python bukan benar-benar "variabel statis". Pertimbangkan:

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

Ini karena baris x.i = 12 telah menambahkan atribut instance baru i ke x alih-alih mengubah nilai atribut Test class i.

Sebagian perilaku variabel statis yang diharapkan, yaitu, sinkronisasi atribut antara beberapa instance (tapi not dengan kelas itu sendiri; lihat "gotcha" di bawah), dapat dicapai dengan memutar atribut kelas menjadi properti:

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)

Sekarang Anda bisa melakukannya:

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

Variabel statis sekarang akan tetap sinkron antara semua instance kelas.

(CATATAN: Yaitu, kecuali sebuah instance kelas memutuskan untuk mendefinisikan versinya sendiri _i! Tetapi jika seseorang memutuskan untuk melakukan ITU, mereka pantas mendapatkan apa yang mereka dapatkan, bukankah begitu ???)

Perhatikan bahwa secara teknis, i masih sama sekali bukan 'variabel statis'; ini adalah property, yang merupakan tipe deskriptor khusus. Namun, perilaku property sekarang setara dengan variabel statis (dapat diubah) yang disinkronkan di semua instance kelas.

"Variabel Statis" yang Tidak Berubah

Untuk perilaku variabel statis yang tidak dapat diubah, cukup hapus setter property:

class Test(object):

    _i = 3

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

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

class Test(object):

    _i = 3

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

    i = property(get_i)

Sekarang mencoba untuk mengatur atribut i instance akan mengembalikan AttributeError:

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

Satu Gotcha menjadi Sadar

Perhatikan bahwa metode di atas hanya berfungsi dengan instance dari kelas Anda - mereka akan tidak bekerja saat menggunakan kelas itu sendiri. Jadi misalnya:

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'

Baris assert Test.i == x.i menghasilkan kesalahan, karena atribut i dari Test dan x adalah dua objek yang berbeda.

Banyak orang akan menganggap ini mengejutkan. Namun, seharusnya tidak demikian. Jika kita kembali dan memeriksa definisi kelas Test kita (versi kedua), kita perhatikan baris ini:

    i = property(get_i) 

Jelas, anggota i dari Test harus berupa objek property, yang merupakan jenis objek yang dikembalikan dari fungsi property.

Jika Anda merasa bingung di atas, kemungkinan besar Anda masih memikirkannya dari perspektif bahasa lain (mis. Java atau c ++). Anda harus mempelajari objek property, tentang urutan pengembalian atribut Python, protokol deskriptor, dan urutan resolusi metode (MRO).

Saya menyajikan solusi untuk 'gotcha' di atas di bawah ini; namun saya akan menyarankan - sangat - bahwa Anda tidak mencoba melakukan sesuatu seperti berikut sampai - minimal - Anda benar-benar mengerti mengapa assert Test.i = x.i menyebabkan kesalahan.

REAL, ACTUAL Variabel Statis - Test.i == x.i

Saya menyajikan solusi (Python 3) di bawah ini hanya untuk tujuan informasi. Saya tidak mendukungnya sebagai "solusi yang baik". Saya ragu apakah meniru perilaku variabel statis bahasa lain di Python benar-benar diperlukan. Namun, terlepas dari apakah itu benar-benar berguna, di bawah ini akan membantu pemahaman lebih lanjut tentang cara kerja Python.

UPDATE: upaya ini benar-benar sangat mengerikan ; jika Anda bersikeras melakukan sesuatu seperti ini (petunjuk: tolong jangan; Python adalah bahasa yang sangat elegan dan menganggapnya seperti bahasa lain tidak diperlukan), gunakan kode dalam jawaban Ethan Furman sebagai gantinya .

Meniru perilaku variabel statis dari bahasa lain menggunakan metaclass

Metaclass adalah kelas dari suatu kelas. Metaclass default untuk semua kelas di Python (mis., Kelas "gaya baru" memposting Python 2.3 saya percaya) adalah type. Sebagai contoh:

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

Namun, Anda dapat mendefinisikan metaclass Anda sendiri seperti ini:

class MyMeta(type): pass

Dan terapkan ke kelas Anda sendiri seperti ini (hanya Python 3):

class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

Di bawah ini adalah metaclass yang saya buat yang mencoba meniru perilaku "variabel statis" dari bahasa lain. Ini pada dasarnya bekerja dengan mengganti pengambil default, setter, dan deleter dengan versi yang memeriksa untuk melihat apakah atribut yang diminta adalah "variabel statis".

Katalog "variabel statis" disimpan dalam atribut StaticVarMeta.statics. Semua permintaan atribut pada awalnya berusaha untuk diselesaikan menggunakan urutan resolusi pengganti. Saya telah menjuluki ini "urutan resolusi statis", atau "SRO". Ini dilakukan dengan mencari atribut yang diminta di set "variabel statis" untuk kelas yang diberikan (atau kelas induknya). Jika atribut tidak muncul di "SRO", kelas akan kembali pada atribut default dapatkan/set/hapus perilaku (mis., "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

Anda juga dapat menambahkan variabel kelas ke kelas on the fly

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

Dan instance kelas dapat mengubah variabel kelas

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

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

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

Secara pribadi saya akan menggunakan classmethod setiap kali saya membutuhkan metode statis. Terutama karena saya mendapatkan kelas sebagai argumen.

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

atau menggunakan dekorator

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

Untuk properti statis .. Saatnya Anda mencari beberapa definisi python .. variabel selalu dapat berubah. Ada dua jenis dari mereka bisa berubah dan tidak berubah .. Juga, ada atribut kelas dan atribut contoh .. Tidak ada yang benar-benar seperti atribut statis dalam arti Java & c ++

Mengapa menggunakan metode statis dalam arti Pythonic, jika tidak memiliki hubungan apa pun dengan kelas! Jika saya jadi Anda, saya akan menggunakan metode classmet atau mendefinisikan metode independen dari kelas.

15
emb

Metode statis dalam python disebut classmethod s. Lihatlah kode berikut

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

Perhatikan bahwa ketika kita memanggil metode myInstanceMethod , kita mendapatkan kesalahan. Ini karena membutuhkan metode yang dipanggil pada turunan dari kelas ini. Metode myStaticMethod diatur sebagai metode kelas menggunakan dekorator @classmethod .

Hanya untuk iseng dan cekikikan, kita bisa memanggil myInstanceMethod di kelas dengan mengirimkan instance kelas, seperti:

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

Satu hal khusus yang perlu diperhatikan tentang properti statis & properti instan, ditunjukkan dalam contoh di bawah ini:

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

Ini berarti sebelum menetapkan nilai ke properti instance, jika kami mencoba mengakses properti melalui instance, nilai statis digunakan. Setiap properti yang dideklarasikan dalam kelas python selalu memiliki slot statis di memori .

13
jondinham

Ketika mendefinisikan beberapa variabel anggota di luar metode anggota, variabel dapat berupa statis atau non-statis tergantung pada bagaimana variabel tersebut diekspresikan.

  • CLASSNAME.var adalah variabel statis
  • INSTANCENAME.var bukan variabel statis.
  • kelas self.var di dalam bukanlah variabel statis.
  • var di dalam fungsi anggota kelas tidak didefinisikan.

Sebagai contoh:

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

Hasilnya

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

Dimungkinkan untuk memiliki variabel kelas static, tetapi mungkin tidak sepadan dengan usaha.

Berikut adalah bukti konsep yang ditulis dalam Python 3 - jika ada detail yang salah, kode dapat diubah agar sesuai dengan apa pun yang Anda maksud dengan 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)

dan digunakan:

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

dan beberapa tes:

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

Anda juga bisa memaksakan kelas menjadi statis menggunakan 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

Kemudian setiap kali secara tidak sengaja Anda mencoba menginisialisasi MyClass Anda akan mendapatkan StaticClassError.

6

Satu hal yang sangat menarik tentang pencarian atribut Python adalah dapat digunakan untuk membuat " virtual variabel":

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!

Biasanya tidak ada tugas untuk ini setelah dibuat. Perhatikan bahwa pencarian menggunakan self karena, meskipun label bersifat statis dalam arti tidak dikaitkan dengan instance khusus , nilai masih bergantung pada instance (class of).

5
Davis Herring

Benar-benar Ya, Python dengan sendirinya tidak memiliki anggota data statis secara eksplisit, tetapi Kami dapat melakukannya dengan melakukannya

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

keluaran

0
0
1
1

penjelasan

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

Sehubungan dengan ini answer , untuk variabel constant static, Anda dapat menggunakan deskriptor. Ini sebuah contoh:

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

yang menghasilkan ...

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

Anda selalu dapat mengajukan pengecualian jika mengabaikan nilai pengaturan (pass di atas) dengan diam-diam bukan pilihan Anda. Jika Anda mencari C++, variabel kelas statis gaya 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

Lihat jawaban ini dan dokumen resmi HOWTO untuk informasi lebih lanjut tentang deskriptor.

4
Yann

Cara terbaik yang saya temukan adalah menggunakan kelas lain. Anda dapat membuat objek dan kemudian menggunakannya pada objek lain.

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

Dengan contoh di atas, saya membuat kelas bernama staticFlag.

Kelas ini harus menyajikan static var __success (Private Static Var).

Kelas tryIt mewakili kelas reguler yang perlu kita gunakan.

Sekarang saya membuat objek untuk satu flag (staticFlag). Bendera ini akan dikirim sebagai referensi ke semua objek biasa.

Semua objek ini ditambahkan ke daftar tryArr.


Hasil Skrip Ini:

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

Untuk menghindari kemungkinan kebingungan, saya ingin membandingkan variabel statis dan objek yang tidak dapat diubah.

Beberapa tipe objek primitif seperti integer, float, string, dan touple tidak berubah dalam Python. Ini berarti bahwa objek yang dirujuk oleh nama yang diberikan tidak dapat berubah jika itu salah satu dari jenis objek yang disebutkan di atas. Nama dapat dipindahkan ke objek yang berbeda, tetapi objek itu sendiri tidak dapat diubah.

Membuat variabel statis mengambil langkah ini lebih jauh dengan melarang nama variabel untuk menunjuk ke objek apa pun kecuali yang ditunjuknya saat ini. (Catatan: ini adalah konsep perangkat lunak umum dan tidak khusus untuk Python; silakan lihat posting orang lain untuk informasi tentang penerapan statika dalam Python).

3
Ross

Ya, sangat mungkin untuk menulis variabel dan metode statis dengan python.

Variabel Statis: Variabel yang dideklarasikan di tingkat kelas disebut variabel statis yang dapat diakses langsung menggunakan nama kelas.

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

    >>> print(A.my_var)
        shagun

Variabel Instance: Variabel yang terkait dan diakses oleh instance dari kelas adalah variabel instan.

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

Metode Statis: Mirip dengan variabel, metode statis dapat diakses langsung menggunakan Nama kelas. Tidak perlu membuat instance.

Namun perlu diingat, metode statis tidak dapat memanggil metode non-statis dengan python.

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

Variabel statis di Kelas pabrik python3.6

Bagi siapa pun yang menggunakan pabrik kelas dengan python3.6 dan ke atas gunakan kata kunci nonlocal untuk menambahkannya ke ruang lingkup/konteks kelas yang dibuat seperti:

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