Чи можна мати змінні чи методи статичного класу в Python? Який синтаксис потрібен для цього?
Чи можна мати змінні чи методи статичного класу в Python? Який синтаксис потрібен для цього?
Відповіді:
Змінні, оголошені всередині визначення класу, але не всередині методу, є змінними класу або статичними:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
Як зазначає @ millerdev , це створює i
змінну рівня класу , але це відрізняється від будь-якої i
змінної рівня екземпляра , тому ви могли мати
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
Це відрізняється від C ++ та Java, але не настільки відрізняється від C #, де статичний член не може отримати доступ, використовуючи посилання на екземпляр.
Подивіться, що підручник Python має сказати на предмет класів та об’єктів класу .
@Steve Johnson вже відповів про статичні методи , також задокументовані в розділі "Вбудовані функції" в бібліотеці Python Reference .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy рекомендує classmethod s над staticmethod, оскільки метод отримує тип класу в якості першого аргументу, але я все ще трохи нечіткий щодо переваг цього підходу перед статичним методом. Якщо ти теж, то, мабуть, це не має значення.
const.py
з , PI = 3.14
і ви можете імпортувати його всюди. from const import PI
i = 3
це НЕ змінної статична, вона є атрибутом класу, і так як він відрізняється від атрибута примірника рівня i
він НЕ поводиться як статичні змінні в інших мовах. Див відповідь millerdev в , відповідь Yann, і моя відповідь нижче.
i
(статична змінна) буде в пам'яті, навіть якщо я створять сотні екземплярів цього класу?
@Blair Conrad зазначив, що статичні змінні, оголошені всередині визначення класу, але не всередині методу, є змінними класу або "статичні":
>>> class Test(object):
... i = 3
...
>>> Test.i
3
Тут є кілька готчей. Продовжуючи з наведеного вище прикладу:
>>> 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__
{}
Зауважте, як змінна екземпляра t.i
вийшла із синхронізації зі змінною класу "статична", коли атрибут i
був встановлений безпосередньо на t
. Це відбувається тому, що він i
був повторно пов'язаний у t
просторі імен, що відрізняється від Test
простору імен. Якщо ви хочете змінити значення "статичної" змінної, ви повинні змінити її в межах (або об'єкта), де воно було визначено спочатку. Я ставлю "статичні" в лапки, тому що Python насправді не має статичних змінних у тому сенсі, як це роблять C ++ та Java.
Хоча в ньому не сказано нічого конкретного щодо статичних змінних чи методів, у підручнику Python є відповідна інформація про класи та об’єкти класу .
@Steve Johnson також відповів щодо статичних методів, також задокументованих у розділі "Вбудовані функції" у бібліотеці Python Reference.
class Test(object):
@staticmethod
def f(arg1, arg2, ...):
...
@beid також згадав classmethod, який схожий на staticmethod. Перший аргумент classmethod - це об'єкт класу. Приклад:
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
. Тепер ви можете зробити x = Test()
, x.i = 12
, assert x.i == Test.i
.
Як зазначалося в інших відповідях, статичні та класичні методи легко виконуються за допомогою вбудованих декораторів:
class Test(object):
# regular instance method:
def MyMethod(self):
pass
# class method:
@classmethod
def MyClassMethod(klass):
pass
# static method:
@staticmethod
def MyStaticMethod():
pass
Як завжди, перший аргумент до MyMethod()
прив'язується до об'єкта екземпляра класу. На противагу цьому , перший аргумент MyClassMethod()
буде пов'язаний з самим об'єктом класу (наприклад, в даному випадку Test
). Бо MyStaticMethod()
жоден аргумент не пов'язаний, і аргументи взагалі не є обов'язковими.
Однак реалізація "статичних змінних" (ну, мінливих статичних змінних, у будь-якому випадку, якщо це не є суперечливістю в термінах ...) не настільки прямо. Як зазначив у своїй відповіді Міллердев , проблема полягає в тому, що атрибути класу Python не є справді "статичними змінними". Поміркуйте:
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
Це відбувається тому , що лінія x.i = 12
доданий новий атрибут реалізації , i
щоб x
замість зміни значення Test
класу i
атрибута.
Часткове очікуване поведінка статичної змінної, тобто синхронізація атрибута між декількома екземплярами (але не з самим класом; див. "Gotcha" нижче), може бути досягнута, перетворивши атрибут класу у властивість:
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)
Тепер ви можете зробити:
x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i # no error
assert x2.i == 50 # the property is synced
Статична змінна тепер залишатиметься синхронізованою між усіма екземплярами класу .
(ПРИМІТКА. Тобто, якщо екземпляр класу не вирішить визначити свою власну версію _i
! Але якщо хтось вирішить зробити ТОМ, вони заслуговують на те, що отримують, чи не ???)
Зауважте, що технічно кажучи, i
це все ще не є "статичною змінною" взагалі; це - property
специфічний тип дескриптора. Однак property
поведінка зараз еквівалентна (мутаційній) статичній змінній, синхронізованій у всіх екземплярах класу.
Для незмінної поведінки статичної змінної просто опустіть 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)
Тепер при спробі встановити i
атрибут примірника повернеться AttributeError
:
x = Test()
assert x.i == 3 # success
x.i = 12 # ERROR
Зауважте, що вищезазначені методи працюють лише з екземплярами вашого класу - вони не працюватимуть при використанні самого класу . Так, наприклад:
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'
Рядок assert Test.i == x.i
створює помилку, оскільки i
атрибут Test
і x
є двома різними об'єктами.
Багато людей вважають це дивним. Однак цього бути не повинно. Якщо ми повернемось назад і вивчимо Test
визначення нашого класу (друга версія), ми врахуємо цей рядок:
i = property(get_i)
Очевидно, що елемент i
з Test
повинна бути property
об'єктом, який є тип об'єкта , що повертається з property
функції.
Якщо ви вважаєте, що вищезгадане заплутане, ви, швидше за все, все ще думаєте про це з точки зору інших мов (наприклад, Java або c ++). Вам слід вивчити property
об'єкт, про порядок повернення атрибутів Python, протокол дескриптора та порядок роздільної здатності методу (MRO).
Я представляю рішення вищезгаданої 'gotcha' нижче; однак я б наголосив - наполегливо - щоб ви не намагалися зробити щось подібне до того моменту, поки, як мінімум, - ви досконало не зрозумієте, чому assert Test.i = x.i
викликає помилку.
Test.i == x.i
Я представляю рішення (Python 3) нижче для інформаційних цілей. Я не схвалюю це як "гарне рішення". У мене є сумніви в тому, чи насправді необхідна емуляція поведінки статичних змінних інших мов на Python. Однак, незалежно від того, чи є він насправді корисним, наведене нижче має допомогти в подальшому розумінні того, як працює Python.
ОНОВЛЕННЯ: ця спроба дійсно дуже жахлива ; якщо ви наполягаєте на тому, щоб робити щось подібне (натяк: будь ласка, не варто; Python - це дуже елегантна мова, і взуття, яка веде себе так, як інша мова, просто не потрібна), використовуйте код замість відповіді Ітана Фурмана .
Емуляція статичної змінної поведінки інших мов за допомогою метакласу
Метаклас - це клас класу. Метаклас за замовчуванням для всіх класів в Python (тобто, класи "нового стилю" після Python 2.3, я вважаю) є type
. Наприклад:
type(int) # class 'type'
type(str) # class 'type'
class Test(): pass
type(Test) # class 'type'
Однак ви можете визначити власний метаклас так:
class MyMeta(type): pass
І застосуйте його до власного класу на зразок цього (лише для Python 3):
class MyClass(metaclass = MyMeta):
pass
type(MyClass) # class MyMeta
Нижче - створений мною метаклас, який намагається імітувати поведінку "статичної змінної" інших мов. В основному це працює, замінюючи getter, setter та deleter за замовчуванням на версії, які перевіряють, чи запитуваний атрибут є "статичною змінною".
Каталог "статичних змінних" зберігається в StaticVarMeta.statics
атрибуті. Усі запити атрибутів спочатку намагаються вирішити за допомогою порядку заміщення рішення. Я назвав це "наказом статичної роздільної здатності", або "СРО". Це робиться шляхом пошуку запитуваного атрибута в наборі "статичних змінних" для даного класу (або його батьківських класів). Якщо атрибут не відображається в "SRO", клас повернеться до атрибуту за замовчуванням поведінка get / set / delete (тобто "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
(перед тим, як використовувати його для інстанції екземплярів), як те, що знаходиться в області метапрограмування? Наприклад, ви змінюєте поведінку класу, роблячи Test.i = 0
(тут ви просто знищуєте об'єкт властивості повністю). Я здогадуюсь, що "механізм властивості" запускається лише при доступі до властивостей в екземплярах класу (якщо, можливо, ви не змінюєте основну поведінку, використовуючи мета-клас як проміжний). Btw, будь ласка, закінчіть цю відповідь :-)
Ви також можете додати змінні класу до класів на ходу
>>> 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
І екземпляри класу можуть змінювати змінні класу
class X:
l = []
def __init__(self):
self.l.append(1)
print X().l
print X().l
>python test.py
[1]
[1, 1]
Особисто я б використовував класний метод, коли мені потрібен був статичний метод. Головним чином тому, що я отримую клас як аргумент.
class myObj(object):
def myMethod(cls)
...
myMethod = classmethod(myMethod)
або використовувати декоратор
class myObj(object):
@classmethod
def myMethod(cls)
Для статичних властивостей .. Його час шукати певне визначення пітона .. змінна завжди може змінюватися. Існує два типи їх змінних та незмінних. Також є атрибути класу та атрибути екземплярів. Нічого, як статичні атрибути у значенні java & c ++
Навіщо використовувати статичний метод у пітонічному сенсі, якщо він не має жодного відношення до класу! Якби я був ти, я б або застосував classmethod або визначив метод, незалежний від класу.
Особливу увагу, що стосується статичних властивостей та властивостей екземпляра, показано у прикладі нижче:
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
Це означає, що перед призначенням значення властивості екземпляра, якщо ми намагаємося отримати доступ до властивості через екземпляр, використовується статичне значення. Кожна властивість, задекларована в класі python, завжди має статичний слот у пам'яті .
Статичні методи в python називаються classmethod s. Погляньте на наступний код
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
Зауважте, що коли ми називаємо метод myInstanceMethod , ми отримуємо помилку. Це тому, що вимагає виклику цього методу в екземплярі цього класу. Метод myStaticMethod встановлюється як класний метод за допомогою декоратора @classmethod .
Тільки для ударів і хихикань ми могли б викликати myInstanceMethod в класі, передавши екземпляр класу, як:
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
@staticmethod
; @classmethod
(очевидно) для методів класу (які в першу чергу призначені для використання в якості альтернативних конструкторів, але можуть служити в дрібнику як статичні методи, які трапляються, щоб отримати посилання на клас, через який вони були викликані).
Коли визначають деяку змінну-члена поза будь-яким методом-члена, змінна може бути статичною або нестатичною залежно від способу вираження змінної.
Наприклад:
#!/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()
Результати є
self.var is 2
A.var is 1
self.var is 2
A.var is 3
Можна мати static
змінні класу, але, мабуть, не варто докладати зусиль.
Ось доказ концепції написаний на Python 3 - якщо будь-яка з точних деталей помилкова, код можна налаштувати так, щоб він відповідав майже тому, що ви маєте на увазі 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)
і використовується:
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')
і деякі тести:
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
Ви також можете примусити клас бути статичним за допомогою метакласу.
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
Тоді, коли ви випадково намагаєтеся ініціалізувати MyClass, ви отримаєте StaticClassError.
__new__
батьків ...
Один дуже цікавий момент пошуку атрибутів Python - це те, що його можна використовувати для створення " віртуальних змінних":
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!
Зазвичай після їх створення немає жодних призначень. Зауважте, що пошук використовується self
тому, що, хоча він label
є статичним, тобто не асоціюється з певним екземпляром, значення все ще залежить від (класу) екземпляра.
Що стосується цієї відповіді , для постійної статичної змінної можна використовувати дескриптор. Ось приклад:
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
в результаті чого ...
small demo 10
small subdemo 100
big demo 10
big subdemo 10
Ви завжди можете створити виняток, якщо тихо ігнорування встановленого значення ( pass
вище) не є вашою справою. Якщо ви шукаєте 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
Перегляньте цю відповідь та офіційні документи HOWTO для отримання додаткової інформації про дескриптори.
@property
, що те саме, що використовувати дескриптор, але це набагато менше коду.
Абсолютно Так, Python сам по собі не має явного статичного члена даних, але ми можемо зробити це
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())
вихід
0
0
1
1
пояснення
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
Так, напевно можна записати статичні змінні та методи в python.
Статичні змінні: Змінна, оголошена на рівні класу, називається статичною змінною, до якої можна отримати доступ безпосередньо за допомогою імені класу.
>>> class A:
...my_var = "shagun"
>>> print(A.my_var)
shagun
Змінні екземпляри: Змінні, які пов'язані між собою та доступ до них за допомогою екземпляра класу, - це змінні екземпляри.
>>> a = A()
>>> a.my_var = "pruthi"
>>> print(A.my_var,a.my_var)
shagun pruthi
Статичні методи: Подібно до змінних, до статичних методів можна отримати доступ безпосередньо з використанням класу Name. Не потрібно створювати екземпляр.
Але майте на увазі, статичний метод не може викликати нестатичний метод у python.
>>> class A:
... @staticmethod
... def my_static_method():
... print("Yippey!!")
...
>>> A.my_static_method()
Yippey!!
Щоб уникнути будь-якої потенційної плутанини, я хотів би протиставити статичні змінні та незмінні об’єкти.
Деякі примітивні типи об'єктів, такі як цілі числа, поплавці, рядки та тюлі, незмінні в Python. Це означає, що об'єкт, на який посилається дане ім'я, не може змінюватися, якщо він є одним із вищезазначених типів об'єкта. Ім’я можна перепризначити іншому об'єкту, але сам об'єкт може не змінюватися.
Здійснення статичної змінної робить цей крок далі, забороняючи ім'я змінної вказувати на будь-який об'єкт, окрім того, на який він в даний час вказує. (Примітка. Це загальна концепція програмного забезпечення, яка не є специфічною для Python; будь ласка, дивіться публікації інших щодо інформації про реалізацію статики в Python).
Найкращий спосіб, який я знайшов, - це використовувати інший клас. Ви можете створити об’єкт, а потім використовувати його на інших об'єктах.
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()
На прикладі, наведеному вище, я склав клас з назвою staticFlag
.
Цей клас повинен представляти статичну змінну __success
(Private Static Var).
tryIt
клас представляв звичайний клас, який нам потрібно використовувати.
Тепер я зробив об’єкт для одного прапора ( staticFlag
). Цей прапор буде надісланий як посилання на всі звичайні об'єкти.
Усі ці об’єкти додаються до списку tryArr
.
Результати цього сценарію:
False
False
False
False
False
True
True
True
True
True
Для всіх, хто використовує фабрику класів з python3.6 і вище, використовуйте nonlocal
ключове слово, щоб додати його до області / контексту класу, який створюється так:
>>> 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')
є False
. я сумніваюся, це те, що хтось має на увазі під статичною змінною взагалі.
some_var
незмінне і статично визначене, чи ні? Що має зовнішній доступ до отримання доступу до змінної, статичної чи ні? У мене зараз так багато питань. хотілося б почути деякі відповіді, коли знайдете час.
some_var
вище це зовсім не член класу. У Python до всіх членів класу можна звернутися поза класом.
nonlocal
Keywoard «врізається» обсяг змінної. Область визначення тіла класу не залежить від сфери, в якій він опиняється, коли ви говорите nonlocal some_var
, що це просто створення не локальної (читайте: НЕ в області визначення класу) імені посилання на інший названий об'єкт. Тому він не приєднується до визначення класу, оскільки він не входить в область тіла класу.
Отже, це, мабуть, хак, але я використовував eval(str)
для отримання статичного об'єкта, свого роду протиріччя, у python 3.
Існує файл Records.py, в якому немає нічого, крім class
об'єктів, визначених статичними методами та конструкторами, які зберігають деякі аргументи. Потім з іншого .py-файлу, import Records
але мені потрібно динамічно вибирати кожен об'єкт, а потім інстанціювати його на вимогу відповідно до типу даних, що читаються.
Отже, куди object_name = 'RecordOne'
або ім'я класу, я закликаю, cur_type = eval(object_name)
а потім інстанціювати це ви робите. cur_inst = cur_type(args)
Однак перед тим, як інстанціювати, ви можете зателефонувати статичним методам, cur_type.getName()
наприклад, на зразок абстрактної реалізації базового класу або будь-якої мети. Однак у бекенді він, ймовірно, інстанціюється в python і не є справді статичним, тому що eval повертає об'єкт .... який повинен бути інстанційним .... що дає статичну поведінку.
Ви можете використовувати список або словник, щоб отримати "статичну поведінку" між екземплярами.
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
Якщо ви намагаєтеся поділитись статичною змінною, наприклад, збільшивши її в інших примірниках, щось подібне до цього сценарію працює добре:
# -*- 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
над@staticmethod
AFAIK полягають у тому, що ви завжди отримуєте ім'я класу, на який посилався метод, навіть якщо це підклас. Статичному методу не вистачає цієї інформації, тому він не може викликати переохоплений метод, наприклад.