etc./StackOverFlow

Python에서 정적 클래스 변수가 가능합니까?

청렴결백한 만능 재주꾼 2021. 11. 30. 23:59
반응형

질문자 :Andrew Walker


Python에서 정적 클래스 변수 또는 메서드를 가질 수 있습니까? 이를 수행하려면 어떤 구문이 필요합니까?



클래스 정의 내에서 선언되었지만 메서드 내에서 선언되지 않은 변수는 클래스 또는 정적 변수입니다.

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

@ millerdev가 지적했듯이 이것은 클래스 수준 i 변수를 생성하지만 이것은 모든 인스턴스 수준 i 변수와 구별되므로 다음을 가질 수 있습니다.

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

이는 C++ 및 Java와 다르지만 인스턴스에 대한 참조를 사용하여 정적 멤버에 액세스할 수 없는 C#과 크게 다르지 않습니다.

클래스 및 클래스 개체에 대한 Python 자습서의 내용을 참조하십시오.

@Steve Johnson은 Python Library Reference의 "Built-in Functions"에 문서화된 정적 메서드 에 대해 이미 답변했습니다.

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

@beidy 는 메서드가 첫 번째 인수로 클래스 유형을 수신하므로 staticmethod보다 classmethod 를 권장하지만 여전히 staticmethod에 비해 이 접근 방식의 이점이 약간 모호합니다. 당신도 그렇다면 그것은 아마도 중요하지 않을 것입니다.


Blair Conrad

@Blair Conrad는 클래스 정의 내부에 선언된 정적 변수는 메서드 내부가 아닌 클래스 또는 "정적" 변수라고 말했습니다.

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

여기에 몇 가지 문제가 있습니다. 위의 예에서 계속:

 >>> t = Test() >>> ti # "static" variable accessed via instance 3 >>> ti = 5 # but if we assign to the instance ... >>> Test.i # we have not changed the "static" variable 3 >>> ti # we have overwritten Test.i on t by creating a new attribute ti 5 >>> Test.i = 6 # to change the "static" variable we do it by assigning to the class >>> ti 5 >>> Test.i 6 >>> u = Test() >>> ui 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__ {}

i t 직접 설정 ti 가 "정적" 클래스 변수와 어떻게 동기화되지 않았는지 주목하십시오. i Test 네임스페이스와 구별되는 t 네임스페이스 내에서 다시 바인딩되었기 때문입니다. "정적" 변수의 값을 변경하려면 원래 정의된 범위(또는 개체) 내에서 변경해야 합니다. Python에는 C++ 및 Java와 같은 정적 변수가 없기 때문에 "정적"을 따옴표로 묶었습니다.

정적 변수나 메서드에 대해 구체적으로 말하지는 않지만 Python 자습서 에는 클래스 및 클래스 개체 에 대한 몇 가지 관련 정보가 있습니다.

@Steve Johnson은 또한 Python 라이브러리 참조의 "내장 함수"에 문서화된 정적 메서드에 대해서도 답변했습니다.

 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

위 예의 그림 표현


millerdev

정적 및 클래스 메서드

다른 답변에서 언급했듯이 정적 및 클래스 메서드는 내장 데코레이터를 사용하여 쉽게 수행할 수 있습니다.

 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 가 그의 답변에서 지적했듯이 문제는 Python의 클래스 속성이 진정한 "정적 변수"가 아니라는 것입니다. 고려하다:

 class Test(object): i = 3 # This is a class attribute x = Test() xi = 12 # Attempt to change the value of the class attribute using x instance assert xi == Test.i # ERROR assert Test.i == 3 # Test.i was not affected assert xi == 12 # xi is a different object than Test.i

xi = 12 Test 클래스 i 속성의 값을 변경하는 대신 x 새 인스턴스 속성 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 xi == 3 # success xi = 12 # ERROR

한 가지 알아둬야 할 문제

위의 방법은 클래스의 인스턴스 에서만 작동합니다. 클래스 자체를 사용할 때는 작동 하지 않습니다. 예를 들면 다음과 같습니다.

 x = Test() assert xi == Test.i # ERROR # xi and Test.i are two different objects: type(Test.i) # class 'property' type(xi) # class 'int'

assert Test.i == xi 행은 Test i 속성과 x 가 두 개의 다른 객체이기 때문에 오류를 생성합니다.

많은 사람들이 이것을 놀랍게 생각할 것입니다. 그러나 그렇게해서는 안됩니다. 돌아가서 Test 클래스 정의(두 번째 버전)를 검사하면 다음 행을 기록합니다.

 i = property(get_i)

Test 의 멤버 i property 함수에서 반환된 개체 유형인 property 개체여야 합니다.

위의 내용이 혼란스럽다면 여전히 다른 언어(예: Java 또는 C++)의 관점에서 생각하고 있을 가능성이 큽니다. Python 속성이 반환되는 순서, 설명자 프로토콜 및 MRO(메서드 확인 순서)에 대해 property 개체를 연구해야 합니다.

나는 아래에 위의 'gotcha'에 대한 해결책을 제시합니다. assert Test.i = xi 가 오류를 일으키는 이유를 완전히 이해할 때까지 다음과 같은 일을 시도하지 않을 것을 강력히 제안합니다.

실제, 실제 정적 변수 - Test.i == xi

아래의 (Python 3) 솔루션은 정보 제공 목적으로만 제공됩니다. 나는 그것을 "좋은 해결책"으로 지지하지 않는다. Python에서 다른 언어의 정적 변수 동작을 에뮬레이트하는 것이 실제로 필요한지 여부에 대해 의구심이 있습니다. 그러나 실제로 유용한지 여부에 관계없이 아래 내용은 Python이 작동하는 방식을 더 잘 이해하는 데 도움이 될 것입니다.

업데이트: 이 시도 는 정말 끔찍합니다 . 이와 같은 일을 고집하는 경우(힌트: 하지 마십시오. Python은 매우 우아한 언어이며 다른 언어처럼 행동하도록 구두 뿔을 만들 필요가 없습니다) Ethan Furman의 답변 에 있는 코드를 대신 사용하십시오.

메타클래스를 사용하여 다른 언어의 정적 변수 동작 에뮬레이션

메타 클래스는 클래스의 클래스입니다. 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"라고 불렀습니다. 이것은 주어진 클래스(또는 그 상위 클래스)에 대한 "정적 변수" 세트에서 요청된 속성을 찾아 수행됩니다. 속성이 "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

Rick supports Monica

즉석에서 클래스에 클래스 변수를 추가할 수도 있습니다.

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

Gregory

개인적으로 정적 메서드가 필요할 때마다 클래스 메서드를 사용합니다. 주로 클래스를 인수로 받기 때문입니다.

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

또는 데코레이터를 사용

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

정적 속성의 경우 .. 일부 python 정의를 조회할 때입니다. 변수는 항상 변경될 수 있습니다. 변경 가능한 것과 변경할 수 없는 두 가지 유형이 있습니다. 또한 클래스 속성과 인스턴스 속성이 있습니다. java 및 C++의 의미에서 정적 속성과 같은 것은 없습니다.

클래스와 아무 관련이 없다면 왜 파이썬적인 의미에서 정적 메서드를 사용합니까! 내가 당신이라면 classmethod를 사용하거나 클래스와 독립적인 방법을 정의할 것입니다.


emb

아래 예에 표시된 정적 속성 및 인스턴스 속성에 대해 주의해야 할 한 가지 특별한 사항은 다음과 같습니다.

 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 클래스에 선언된 각 속성은 항상 메모리에 정적 슬롯을 갖습니다 .


jondinham

파이썬의 정적 메소드를 classmethod 라고 합니다. 다음 코드를 살펴보십시오.

 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

willurd

멤버 메소드 외부에 일부 멤버 변수를 정의할 때 변수가 표현되는 방식에 따라 변수는 정적이거나 비정적일 수 있습니다.

  • CLASSNAME.var는 정적 변수입니다.
  • INSTANCENAME.var는 정적 변수가 아닙니다.
  • 클래스 내부의 self.var는 정적 변수가 아닙니다.
  • 클래스 멤버 함수 내부의 var가 정의되어 있지 않습니다.

예를 들어:

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

user2209576

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

Ethan Furman

메타클래스를 사용하여 클래스를 정적으로 강제할 수도 있습니다.

 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가 발생합니다.


Bartosz Ptaszynski

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!

일반적으로 생성된 후에는 할당되지 않습니다. label 은 특정 인스턴스와 연결되지 않는다는 의미에서 정적이지만 값은 여전히 (클래스) 인스턴스에 의존하기 때문에 조회는 self


Davis Herring

예, 파이썬에서 정적 변수와 메서드를 작성할 수 있습니다.

정적 변수 : 클래스 수준에서 선언된 변수를 정적 변수라고 하며 클래스 이름을 사용하여 직접 액세스할 수 있습니다.

 >>> 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 클래스를 사용하여 직접 액세스할 수 있습니다. 인스턴스를 생성할 필요가 없습니다.

그러나 정적 메서드는 파이썬에서 비정적 메서드를 호출할 수 없습니다.

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

Shagun Pruthi

이 답변 과 관련하여 상수 정적 변수에 대해 설명자를 사용할 수 있습니다. 다음은 예입니다.

 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를 참조하세요.


Yann

절대적으로 예, 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"

Mari Selvan

잠재적인 혼동을 피하기 위해 정적 변수와 불변 객체를 대조하고 싶습니다.

정수, 부동 소수점, 문자열 및 튜플과 같은 일부 기본 객체 유형은 Python에서 변경할 수 없습니다. 이것은 주어진 이름으로 참조되는 객체가 앞서 언급한 객체 유형 중 하나인 경우 변경할 수 없음을 의미합니다. 이름은 다른 개체에 다시 할당할 수 있지만 개체 자체는 변경할 수 없습니다.

변수를 정적으로 만드는 것은 변수 이름이 현재 가리키고 있는 객체가 아닌 다른 객체를 가리키도록 허용하지 않음으로써 한 단계 더 나아갑니다. (참고: 이것은 일반적인 소프트웨어 개념이며 Python에만 국한되지 않습니다. Python에서 정적 구현에 대한 정보는 다른 사람의 게시물을 참조하십시오.)


Ross

내가 찾은 가장 좋은 방법은 다른 클래스를 사용하는 것입니다. 개체를 만든 다음 다른 개체에서 사용할 수 있습니다.

 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 라는 클래스를 만들었습니다.

이 클래스는 정적 var __success (개인 정적 변수)를 제공해야 합니다.

tryIt 클래스는 우리가 사용해야 하는 일반 클래스를 나타냅니다.

이제 하나의 플래그( staticFlag )에 대한 객체를 만들었습니다. 이 플래그는 모든 일반 개체에 대한 참조로 전송됩니다.

이 모든 객체가 tryArr 목록에 추가되고 있습니다.


이 스크립트 결과:

 False False False False False True True True True True

Tomer Zait

클래스 팩토리 python3.6의 정적 변수

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

jmunsch

그래서 이것은 아마도 해킹일 수 있지만, 저는 python 3에서 일종의 모순인 정적 객체를 얻기 위해 eval(str)

일부 인수를 저장하는 정적 메서드와 생성자로 정의된 class 개체만 있는 Records.py 파일이 있습니다. 그런 다음 다른 .py 파일에서 import Records 오지만 각 개체를 동적으로 선택한 다음 읽고 있는 데이터 유형에 따라 요청 시 인스턴스화해야 합니다.

따라서 object_name = 'RecordOne' 또는 클래스 이름이 있는 곳에서 cur_type = eval(object_name) 호출한 다음 인스턴스화하기 위해 cur_inst = cur_type(args) cur_type.getName() 에서 정적 메서드를 호출할 수 있습니다. , 추상 기본 클래스 구현이나 목표가 무엇이든 같습니다. 그러나 백엔드에서는 아마도 파이썬에서 인스턴스화되고 eval이 객체를 반환하기 때문에 실제로 정적이 아닙니다.


Christopher Hoffman

__init__() 을 정의하는 데 사용되는 클래스 수준 이름을 제공합니다. @dataclass 에서 클래스 수준 변수를 typing.ClassVar 유형 힌트를 사용해야 합니다. ClassVar 유형의 매개변수는 클래스 수준 변수의 유형을 정의합니다.

 from typing import ClassVar from dataclasses import dataclass @dataclass class Test: i: ClassVar[int] = 10 x: int y: int def __repr__(self): return f"Test({self.x=}, {self.y=}, {Test.i=})"

사용 예:

 > test1 = Test(5, 6) > test2 = Test(10, 11) > test1 Test(self.x=5, self.y=6, Test.i=10) > test2 Test(self.x=10, self.y=11, Test.i=10)

Vlad Bezden

목록이나 사전을 사용하여 인스턴스 간에 "정적 동작"을 얻을 수 있습니다.

 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

Jay

예를 들어 정적 변수를 공유하려는 경우 다른 인스턴스에서 증가시키면 다음 스크립트와 같이 잘 작동합니다.

 # -*- 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)

Winter Squad

Object 데이터 유형을 사용하면 가능합니다. bool , int , float 또는 str bahaviour 와 같은 기본 유형에서는 다른 OOP 언어와 다릅니다. 상속된 클래스에는 정적 속성이 존재하지 않기 때문입니다. 속성이 상속된 클래스에 존재하지 않으면 Python은 상위 클래스에서 속성을 찾기 시작합니다. 상위 클래스에서 발견되면 해당 값이 반환됩니다. 상속된 클래스의 값을 변경하기로 결정하면 런타임에 정적 속성이 생성됩니다. 상속된 정적 속성을 읽을 때 그 값은 이미 정의되어 있기 때문에 반환됩니다. 개체(목록, 사전)는 참조로 작동하므로 정적 속성으로 사용하고 상속하는 것이 안전합니다. 속성 값을 변경할 때 개체 주소는 변경되지 않습니다.

정수 데이터 유형의 예:

 class A: static = 1 class B(A): pass print(f"int {A.static}") # get 1 correctly print(f"int {B.static}") # get 1 correctly A.static = 5 print(f"int {A.static}") # get 5 correctly print(f"int {B.static}") # get 5 correctly B.static = 6 print(f"int {A.static}") # expected 6, but get 5 incorrectly print(f"int {B.static}") # get 6 correctly A.static = 7 print(f"int {A.static}") # get 7 correctly print(f"int {B.static}") # get unchanged 6

refdatatypes 라이브러리 기반 솔루션:

 from refdatatypes.refint import RefInt class AAA: static = RefInt(1) class BBB(AAA): pass print(f"refint {AAA.static.value}") # get 1 correctly print(f"refint {BBB.static.value}") # get 1 correctly AAA.static.value = 5 print(f"refint {AAA.static.value}") # get 5 correctly print(f"refint {BBB.static.value}") # get 5 correctly BBB.static.value = 6 print(f"refint {AAA.static.value}") # get 6 correctly print(f"refint {BBB.static.value}") # get 6 correctly AAA.static.value = 7 print(f"refint {AAA.static.value}") # get 7 correctly print(f"refint {BBB.static.value}") # get 7 correctly

alda78

이런 식으로 정적 변수는 사용자 정의 클래스가 존재하고 키워드 self를 따라야 하는 정적 변수를 정의할 때 생성됩니다.

 class Student: the correct way of static declaration i = 10 incorrect self.i = 10

ganja

@staticmethod 와 달리 클래스 변수는 클래스의 정적 메소드이며 모든 인스턴스와 공유됩니다.

이제 다음과 같이 액세스할 수 있습니다.

 instance = MyClass() print(instance.i)

또는

 print(MyClass.i)

이 변수에 값을 할당해야 합니다.

난 노력했다

 class MyClass: i: str

하나의 메서드 호출에 값을 할당하면 작동하지 않고 오류가 발생합니다.

 i is not attribute of MyClass

Sunil Garg

출처 : http:www.stackoverflow.com/questions/68645/are-static-class-variables-possible-in-python

반응형