Apakah mungkin untuk memiliki variabel atau metode kelas statis di Python? Sintaks apa yang diperlukan untuk melakukan ini?
Apakah mungkin untuk memiliki variabel atau metode kelas statis di Python? Sintaks apa yang diperlukan untuk melakukan ini?
Jawaban:
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 yang ditunjukkan oleh @ millerdev , ini menciptakan i
variabel level kelas , tetapi ini berbeda dari i
variabel level instance mana 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 dalam "Fungsi Bawaan " di Referensi Pustaka Python .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy merekomendasikan classmethod s over staticmethod, karena metode ini kemudian menerima tipe class sebagai argumen pertama, tapi saya masih sedikit kabur tentang kelebihan pendekatan ini atas staticmethod. Jika Anda juga, maka itu mungkin tidak masalah.
const.py
dengan beberapa PI = 3.14
dan Anda dapat mengimpornya di mana saja. from const import PI
i = 3
ini bukan variabel statis, itu adalah atribut kelas, dan karena ia berbeda dari atribut tingkat instancei
ia tidak berperilaku seperti variabel statis dalam bahasa lain. Lihat jawaban millerdev ini , jawaban Yann ini , dan jawaban saya di bawah ini.
i
(variabel statis) akan berada di memori bahkan jika saya membuat ratusan instance dari kelas ini?
@ 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 t
. Ini karena i
terikat kembali di dalam t
namespace, yang berbeda dari Test
namespace. 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 atau metode statis, tutorial Python memiliki beberapa informasi yang relevan tentang 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 be the same as Test.i = arg1
class Test(object):
, _i = 3
, @property
, def i(self)
, return type(self)._i
, @i.setter
, def i(self,val):
, type(self)._i = val
. Sekarang Anda dapat melakukan x = Test()
, x.i = 12
, assert x.i == Test.i
.
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 MyMethod()
terikat ke objek instance kelas. Sebaliknya, argumen pertama untuk MyClassMethod()
yang terikat ke objek kelas itu sendiri (misalnya, dalam kasus ini, Test
). Sebab MyStaticMethod()
, tidak ada argumen yang terikat, dan memiliki argumen sama sekali adalah opsional.
Namun, menerapkan "variabel statis" (yah, variabel statis yang dapat berubah , bagaimanapun, jika itu bukan kontradiksi dalam istilah ...) tidak semudah itu. Seperti yang ditunjukkan millerdev dalam jawabannya , masalahnya adalah atribut kelas Python tidak benar-benar "variabel statis". Mempertimbangkan:
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
untuk x
bukannya mengubah nilai Test
kelasi
atribut .
Perilaku variabel statis parsial yang diharapkan, yaitu, sinkronisasi atribut antara beberapa instance (tetapi tidak dengan kelas itu sendiri; lihat "gotcha" di bawah), dapat dicapai dengan mengubah 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 instance kelas memutuskan untuk mendefinisikan versinya sendiri _i
! Tetapi jika seseorang memutuskan untuk melakukan ITU, mereka layak mendapatkan apa yang mereka dapatkan, bukankah begitu ???)
Perhatikan bahwa secara teknis, i
masih bukan 'variabel statis' sama sekali; itu adalah property
, yang merupakan tipe deskriptor khusus. Namun demikianproperty
perilaku sekarang setara dengan variabel statis (dapat diubah) disinkronkan di semua instance kelas.
Untuk perilaku variabel statis yang tidak dapat diubah, cukup abaikan 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)
Sekarang mencoba untuk mengatur i
atribut instance akan mengembalikan AttributeError
:
x = Test()
assert x.i == 3 # success
x.i = 12 # ERROR
Perhatikan bahwa metode di atas hanya berfungsi dengan instance kelas Anda - mereka tidak akan berfungsi 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'
Garis assert Test.i == x.i
menghasilkan kesalahan, karena i
atribut Test
dan x
dua objek berbeda.
Banyak orang akan menganggap ini mengejutkan. Namun, seharusnya tidak demikian. Jika kita kembali dan memeriksa Test
definisi kelas kita (versi kedua), kita perhatikan baris ini:
i = property(get_i)
Jelas, anggota i
dari Test
keharusan menjadi property
objek, yang merupakan jenis objek kembali dari property
fungsi.
Jika Anda menemukan hal di atas membingungkan, kemungkinan besar Anda masih memikirkannya dari perspektif bahasa lain (mis. Java atau c ++). Anda harus belajarproperty
objek tersebut, 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.
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 sangat mengerikan ; jika Anda bersikeras melakukan sesuatu seperti ini (petunjuk: tolong jangan; Python adalah bahasa yang sangat elegan dan menganggapnya seperti bahasa lain tidak perlu), gunakan kode dalam jawaban Ethan Furman sebagai gantinya.
Meniru perilaku variabel statis dari bahasa lain menggunakan metaclass
Metaclass adalah kelas suatu kelas. Metaclass default untuk semua kelas di Python (yaitu, 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 StaticVarMeta.statics
atribut. Semua permintaan atribut pada awalnya dicoba untuk diselesaikan menggunakan urutan resolusi pengganti. Saya telah menjuluki ini "urutan resolusi statis", atau "SRO". Ini dilakukan dengan mencari atribut yang diminta dalam set "variabel statis" untuk kelas tertentu (atau kelas induknya). Jika atribut tidak muncul di "SRO", kelas akan kembali pada atribut default dapatkan / atur / hapus perilaku (yaitu, "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
Test
(sebelum menggunakannya untuk instance instantiating) sebagai berada di domain meta-programming? Misalnya, Anda mengubah perilaku kelas dengan melakukan Test.i = 0
(di sini Anda hanya menghancurkan objek properti sepenuhnya). Saya kira "mekanisme properti" hanya menendang pada akses-properti pada instance kelas (kecuali jika Anda mengubah perilaku mendasar menggunakan meta-class sebagai perantara, mungkin). Btw, tolong selesaikan jawaban ini :-)
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]
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.
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 .
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 ditetapkan 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
@staticmethod
; @classmethod
adalah (jelas) untuk metode kelas (yang terutama dimaksudkan untuk digunakan sebagai konstruktor alternatif, tetapi dapat berfungsi dalam keadaan darurat sebagai metode statis yang kebetulan menerima referensi ke kelas yang mereka dipanggil melalui).
Ketika mendefinisikan beberapa variabel anggota di luar metode anggota, variabel dapat berupa statis atau non-statis tergantung pada bagaimana variabel tersebut diekspresikan.
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
Dimungkinkan untuk memiliki static
variabel kelas, 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
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.
__new__
tuanya ...
Satu hal yang sangat menarik tentang pencarian atribut Python adalah ia dapat digunakan untuk membuat " variabel virtual ":
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
statis dalam arti tidak dikaitkan dengan contoh tertentu , nilainya masih tergantung pada instance (kelas dari).
Sehubungan dengan jawaban ini , untuk variabel statis konstan , 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 (di pass
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
Lihatlah jawaban ini dan dokumen resmi HOWTO untuk informasi lebih lanjut tentang deskriptor.
@property
, yang sama dengan menggunakan deskriptor, tetapi kode ini jauh lebih sedikit.
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"
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 secara 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!!
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 saat ini ditunjuknya. (Catatan: ini adalah konsep perangkat lunak umum dan tidak khusus untuk Python; silakan lihat posting orang lain untuk informasi tentang penerapan statika dalam Python).
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 var statis __success
(Private Static Var).
tryIt
kelas 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 sedang ditambahkan ke daftar tryArr
.
Hasil Skrip Ini:
False
False
False
False
False
True
True
True
True
True
Bagi siapa pun yang menggunakan pabrik kelas dengan python3.6 dan lebih tinggi gunakan nonlocal
kata kunci untuk menambahkannya ke lingkup / konteks kelas yang sedang 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
hasattr(SomeClass, 'x')
adalah False
. saya ragu ini yang orang maksud dengan variabel statis sama sekali.
some_var
berubah, dan didefinisikan secara statis, atau bukan? Apa yang harus dilakukan oleh akses pengambil luar dengan variabel yang statis atau tidak? Saya punya banyak pertanyaan sekarang. akan senang mendengar beberapa jawaban ketika Anda mendapatkan waktu.
some_var
atas bukan anggota kelas sama sekali. Dalam Python semua anggota kelas dapat diakses dari luar kelas.
nonlocal
keywoard "benjolan" ruang lingkup variabel. Lingkup definisi badan kelas tidak tergantung pada ruang lingkup yang ditemukannya sendiri ketika Anda mengatakan nonlocal some_var
, itu hanya membuat referensi nama non-lokal (baca: BUKAN dalam lingkup definisi kelas) ke objek bernama lain. Oleh karena itu tidak melekat pada definisi kelas karena tidak ada dalam ruang lingkup kelas.
Jadi ini mungkin hack, tapi saya sudah menggunakan eval(str)
untuk mendapatkan objek statis, semacam kontradiksi, dengan python 3.
Ada file Records.py yang hanya memiliki class
objek yang ditentukan dengan metode statis dan konstruktor yang menyimpan beberapa argumen. Kemudian dari file .py lain Iimport Records
tetapi saya perlu secara dinamis memilih setiap objek dan kemudian instantiate sesuai permintaan sesuai dengan jenis data yang sedang dibaca.
Jadi di mana object_name = 'RecordOne'
atau nama kelas, saya panggil cur_type = eval(object_name)
dan kemudian untuk instantiate Anda lakukan cur_inst = cur_type(args)
Namun sebelum Anda instantiate Anda dapat memanggil metode statis dari cur_type.getName()
misalnya, jenis seperti implementasi kelas dasar abstrak atau apa pun tujuannya. Namun di backend, mungkin instantiated dengan python dan tidak benar-benar statis, karena eval mengembalikan objek .... yang pasti instantiated .... yang memberikan perilaku seperti statis.
Anda dapat menggunakan daftar atau kamus untuk mendapatkan "perilaku statis" di antara instance.
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
Jika Anda mencoba untuk membagikan variabel statis untuk, dengan contoh, meningkatkannya di contoh lain, sesuatu seperti skrip ini berfungsi dengan baik:
# -*- 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)
@classmethod
lebih@staticmethod
AFAIK adalah bahwa Anda selalu mendapatkan nama kelas metode ini dipanggil pada, bahkan jika itu subclass. Metode statis tidak memiliki informasi ini, jadi tidak dapat memanggil metode yang diganti, misalnya.