답변:
클래스 정의 내부에 선언되었지만 메소드 내부에는 선언되지 않은 변수는 클래스 또는 정적 변수입니다.
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
@ millerdev가 지적했듯이 클래스 수준 i
변수를 만들지 만 인스턴스 수준 i
변수와는 다르므로
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
이는 C ++ 및 Java와 다르지만 인스턴스 참조를 사용하여 정적 멤버에 액세스 할 수없는 C #과는 다릅니다.
클래스와 클래스 객체의 주제에 대해 파이썬 튜토리얼이 무엇을 말하는지 보십시오 .
@ 스티브 존슨은 이미 관한 응답 한 정적 방법 도 아래 문서화, 파이썬 라이브러리 참조에서 "내장 기능" .
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy는 권장 classmethod 방법은 다음 첫 번째 인수로 클래스 유형을 수신 할 때, StaticMethod를 통해들,하지만, 난 여전히 StaticMethod를 통해이 방법의 장점에 약간 퍼지입니다. 당신이 너무 있다면, 아마도 중요하지 않을 것입니다.
const.py
가지고 PI = 3.14
있으면 어디서나 가져올 수 있습니다. from const import PI
i = 3
입니다 되지 는 클래스 속성이며, 인스턴스 레벨 속성 별개이기 때문에, 정적 변수 i
는 않습니다 하지 다른 언어 정적 변수처럼 동작합니다. 참조 millerdev의 대답 , 얀의 대답 , 그리고 내 대답은 아래를.
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
내에서 리 바인드 되었기 때문 입니다. "정적"변수의 값을 변경하려면 원래 정의 된 범위 (또는 오브젝트) 내에서 변경해야합니다. 파이썬에는 C ++과 Java가하는 의미에서 정적 변수가 없기 때문에 "정적"을 따옴표로 묶습니다.t
Test
정적 변수 또는 메소드에 대해서는 구체적으로 언급하지 않지만 Python 자습서 에는 클래스 및 클래스 객체 에 대한 관련 정보가 있습니다 .
@Steve Johnson은 또한 Python Library Reference의 "Built-in Functions"에 문서화 된 정적 메소드에 대해서도 답변했습니다.
class Test(object):
@staticmethod
def f(arg1, arg2, ...):
...
@beid는 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()
, 인수 아무도 구속하지 않고, 전혀 인수를 가지는 것은 선택 사항입니다된다.
그러나 "정적 변수"(잘 변하기 쉬운 가변 변수)를 구현 하는 것은 그리 간단하지 않습니다. millerdev 가 그의 답변에서 지적했듯이 , 문제는 파이썬의 클래스 속성이 실제로 "정적 변수"가 아니라는 것입니다. 치다:
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
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)
이제 인스턴스 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
파이썬 속성이 리턴되는 순서, 디스크립터 프로토콜 및 메소드 분석 순서 (MRO)에 대한 오브젝트를 연구해야합니다 .
아래의 위의 'gotcha'에 대한 해결책을 제시합니다. 그러나 나는 최소한 assert Test.i = x.i
오류가 발생하는 이유를 완전히 이해할 때까지 다음과 같은 일을 시도하지 말 것을 강력하게 제안 합니다.
Test.i == x.i
정보 제공 목적으로 만 (Python 3) 솔루션을 제시합니다. 나는 그것을 "좋은 해결책"으로 보증하지 않습니다. 파이썬에서 다른 언어의 정적 변수 동작을 에뮬레이트하는 것이 실제로 필요한지에 대한 의문이 있습니다. 그러나 실제로 유용한 지 여부에 관계없이 아래는 Python의 작동 방식을 이해하는 데 도움이됩니다.
업데이트 :이 시도 는 정말 끔찍합니다 . 이 같은 일을 주장하는 경우 (힌트 : 제발하지 마십시오; 파이썬은 매우 우아한 언어이며 다른 언어처럼 행동하도록 구두를 휘두르는 것은 필요하지 않습니다) 대신 Ethan Furman의 답변에 코드를 사용하십시오 .
메타 클래스를 사용하여 다른 언어의 정적 변수 동작 에뮬레이션
메타 클래스는 클래스의 클래스입니다. 파이썬의 모든 클래스에 대한 기본 메타 클래스 (즉, 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"라고 불렀다. 이것은 주어진 클래스 (또는 그 상위 클래스)에 대한 "정적 변수"세트에서 요청 된 속성을 찾아서 수행됩니다. 속성이 "SRO"에 나타나지 않으면 클래스는 기본 속성 가져 오기 / 설정 / 삭제 동작 (예 : "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 클래스에서 선언 된 각 속성에는 항상 메모리에 정적 슬롯이 있습니다.
파이썬의 정적 메소드를 클래스 메소드라고 합니다. 다음 코드를 살펴보십시오
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__
부모의 호출을 위해 super ()를 사용하지 않기를 바란다 ...
파이썬의 속성 조회에 대한 한 가지 흥미로운 점은 " 가상 변수" 를 만드는 데 사용될 수 있다는 것입니다 .
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
@property
기술자를 사용하는 것과 동일하다,하지만 훨씬 덜 코드입니다.
물론 그렇습니다. 파이썬 자체에는 명시 적으로 정적 데이터 멤버가 없지만 그렇게 할 수 있습니다.
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"
그렇습니다. 정적 변수와 메소드를 파이썬으로 작성할 수 있습니다.
정적 변수 : 클래스 수준에서 선언 된 변수를 정적 변수라고하며 클래스 이름을 사용하여 직접 액세스 할 수 있습니다.
>>> 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
정적 메소드 : 변수와 유사하게 정적 메소드는 클래스 이름을 사용하여 직접 액세스 할 수 있습니다. 인스턴스를 만들 필요가 없습니다.
그러나 정적 메소드는 파이썬에서 비 정적 메소드를 호출 할 수 없습니다.
>>> 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
class는 우리가 사용해야하는 정규 클래스를 나타냅니다.
이제 하나의 플래그 ( 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
불변이고 정적으로 정의되어 있습니까? 외부 getter 액세스는 변수가 정적인지 아닌지와 관련이 있습니까? 나는 지금 너무 많은 질문이 있습니다. 당신이 시간을 얻을 때 답변을 듣고 싶어요.
some_var
위의 반원이 아니다. 파이썬에서는 모든 클래스 멤버가 클래스 외부에서 액세스 할 수 있습니다.
nonlocal
keywoard 변수의 범위를 "범프". 클래스 본문 정의의 범위는 사용자가 말할 때 즉 nonlocal some_var
, 다른 명명 된 객체에 대한 로컬이 아닌 (읽기 : 클래스 정의 범위에 없음) 이름 참조를 작성하는 범위와 독립적입니다 . 따라서 클래스 본문 범위에 없기 때문에 클래스 정의에 연결되지 않습니다.
그래서 이것은 아마도 해킹 일 것입니다. 그러나 eval(str)
파이썬 3에서 정적 객체, 일종의 모순을 얻는 데 사용 했습니다.
class
정적 메소드 및 일부 인수를 저장하는 생성자로 정의 된 오브젝트 만있는 Records.py 파일이 있습니다 . 그런 다음 다른 .py 파일 import Records
에서 각 객체를 동적으로 선택한 다음 읽고있는 데이터 유형에 따라 필요에 따라 인스턴스화해야합니다.
어디서 object_name = 'RecordOne'
또는 클래스 이름을 호출 cur_type = eval(object_name)
하고 인스턴스화하기 위해 인스턴스화 cur_inst = cur_type(args)
하기 전에 인스턴스화하기 전에 cur_type.getName()
추상 기본 클래스 구현 또는 목표와 같은 정적 메소드를 호출 할 수 있습니다 . 그러나 백엔드에서는 아마도 파이썬으로 인스턴스화되고 실제로 정적이 아닙니다 .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은 항상 서브 클래스의 경우에도, 메소드가 호출 된 클래스의 이름을 얻을 수 있다는 것입니다. 정적 메서드에는이 정보가 없기 때문에 예를 들어 재정의 된 메서드를 호출 할 수 없습니다.