programing

Python의 정적 클래스 변수 및 메서드

javaba 2022. 11. 26. 22:00
반응형

Python의 정적 클래스 변수 및 메서드

Python에서 정적 클래스 변수 또는 메서드를 만드는 방법은 무엇입니까?

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

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

@millerdev가 지적한 바와 같이 클래스 레벨이 작성됩니다.i은, 인스턴스 레벨의 「인스턴스 레벨」, 「인스턴스 레벨의」, 「인스턴스 레벨의 「인스턴스 레벨의 「인스턴스 레벨」이 .ivariable을 하면, 「」, 「」, 「」, 「」, 「」, 「」, 「」

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

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

Python 튜토리얼에서 클래스클래스 객체에 대해 설명하는 내용을 확인하십시오.

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

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

@beidy는 static 메서드보다 클래스 메서드를 권장합니다.이 메서드는 클래스 타입을 첫 번째 인수로 받기 때문입니다.

@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 "static" 아트리뷰트가 "static"일 때 .i 설정했습니다.t은 ★★★★★★에 의한 것입니다.i was was was was was 。t네임스페이스'와는)Test범위(또는) 에서 변경해야 합니다.Python C++ Java는 "static"으로 지정합니다.

Python 튜토리얼에는 정적 변수나 메서드에 대한 구체적인 정보가 포함되어 있지 않지만 클래스클래스 객체에 대한 정보가 포함되어 있습니다.

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

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

@beid는 static 메서드와 유사한 class method도 언급했습니다.classmethod의 첫 번째 인수는 class 객체입니다.예:

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

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

    # class method:
    @classmethod
    def my_class_method(cls):
        pass

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

첫 는 " " " 입니다.my_method()는 클래스 인스턴스 객체에 바인드됩니다.첫 '''는 '''입니다'''는my_class_method()는 클래스 오브젝트 자체에 바인드 됩니다(예를 들어 이 경우,Test의 경우my_static_method()인수는 모두 바인드되지 않으며 인수를 갖는 것은 임의입니다.

"고정 변수"

그러나 "static variables"(어쨌든 가변 정적 변수)를 구현하는 것은 그렇게 간단하지 않습니다.millerdev가 그의 답변에서 지적했듯이, 문제는 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는 새로운 속성 "Atribut"을 했습니다.i로로 합니다.xTest ★★★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

이제 static 변수는 모든 클래스 인스턴스 간에 동기화된 상태로 유지됩니다.

: 즉 인 버전을 한 (': ', '는')_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는 Attribute를 합니다.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) 

는 ★★★★★★★★★★★★★★★★★★★★★★」iTest이여야 합니다.property입니다.property★★★★★★ 。

위의 내용을 혼동할 경우 다른 언어(Java 또는 c++ 등)의 관점에서 생각할 수 있습니다..propertyPython - Python, MRO(Method Resolution Order)입니다.

에 대한 을 아래에합니다. 이 적어도 'gotcha'가 왜 'gotcha'인지 충분히 이해할 말 합니다.하지만, 적어도 그 이유를 완전히 이해할 때까지는 다음과 같은 것을 시도하지 말 것을 강력히 제안합니다.assert Test.i = x.i에러가 발생합니다.

REAL, REAL 정적 변수 -Test.i == x.i

아래 (Python 3) 솔루션을 참고용으로만 제시합니다.나는 그것을 "좋은 해결책"으로 지지하지 않는다.Python에서 다른 언어의 정적 변수 동작을 모방할 필요가 있는지 의문입니다.그러나 실제로 도움이 되는지 여부에 관계없이 아래는 Python의 작동 방식을 더 잘 이해하는 데 도움이 될 것입니다.

업데이트: 이 시도는 정말 끔찍하다. 만약 당신이 이런 것을 고집한다면(힌트: 제발 하지 마세요; Python은 매우 우아한 언어이며 다른 언어가 필요하지 않은 것처럼 행동하도록 신발에 호킹하는 것은) 대신 Ethan Furman의 대답에 있는 코드를 사용하십시오.

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

이치노Python의(즉, Python 2.3 의 "style"는 Python입니다.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

다음은 다른 언어의 "static variable" 동작을 에뮬레이트하기 위해 작성한 메타클래스입니다.기본적으로 기본 getter, setter 및 deleter를 요청된 속성이 "static variable"인지 확인하는 버전으로 바꿈으로써 작동합니다.

variable 는 "static variable됩니다.StaticVarMeta.statics여하 all 순서를 .모든 Atribute 요구는 처음에 대체 해결 순서를 사용하여 해결하려고 시도됩니다.SRO, SRO, SRO, SRO, SRO를 사용합니다.이것은 특정 클래스(또는 그 부모 클래스)에 대한 "static variables" 세트에서 요청된 속성을 검색함으로써 수행됩니다.「SRO」는, get/set/delete(「MRO」, 「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

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

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

정적 속성의 경우...Python의 정의를 찾아보세요.변수는 언제든지 변경할 수 있습니다.변이와 불변의 두 가지 유형이 있습니다.또한 클래스 애트리뷰트와 인스턴스 애트리뷰트가 있습니다.java와 c++의 의미에서 정적 속성만큼 좋은 것은 없다.

클래스와 전혀 관계가 없는데 왜 정적인 방법을 사용하는가!나 같으면 클래스 메서드를 사용하거나 클래스에서 독립된 메서드를 정의하겠습니다.

스태틱 속성 및 인스턴스 속성에 대해 다음 예시와 같이 주의할 점이 있습니다.

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

즉, 인스턴스 속성에 값을 할당하기 전에 속성 thru' 인스턴스에 액세스하려고 하면 정적 값이 사용됩니다.python 클래스에서 선언된 각 속성은 항상 메모리에 정적 슬롯을 가집니다.

python의 정적 메서드를 class 메서드라고 합니다.다음 코드를 참조하십시오.

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

it 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

멤버 메서드 외부에서 일부 멤버 변수를 정의하는 경우 변수는 변수의 표현 방법에 따라 스태틱 또는 비 스태틱 중 하나입니다.

  • CLASSNAME.var는 정적 변수입니다.
  • INSTANCENAME.var는 정적 변수가 아닙니다.
  • self.var inside 클래스는 스태틱 변수가 아닙니다.
  • 클래스 멤버 함수 내의 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

@ 및 하기 위해 @dataclass "는 클래스 수준 이름입니다.__init__()를 「」로 설정하는 @dataclass힌트 타입을 사용해야 합니다.ClassVartype의 파라미터는 클래스 수준 변수의 유형을 정의합니다.

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)

메타클래스를 사용하여 클래스를 스태틱하게 할 수도 있습니다.

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가 나타납니다.

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!

일반적으로 생성된 후에는 할당이 없습니다. 검색에서는 다음과 같이 "Drughta" 가 사용되고 있는 것에 해 주세요.self'비록'은 '비록 '비록'은label는 특정 인스턴스와 관련지을 수 없다는 의미에서 스태틱하지만 값은 (클래스의) 인스턴스에 따라 달라집니다.

네, 정적 변수와 메서드를 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

정적 메서드: 변수와 마찬가지로 클래스 이름을 사용하여 정적 메서드에 직접 액세스할 수 있습니다.인스턴스를 생성할 필요가 없습니다.

그러나 정적 메서드는 python에서 non-static 메서드를 호출할 수 없습니다.

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

답변과 관련하여 상수 정적 변수의 경우 기술자를 사용할 수 있습니다.다음은 예를 제시하겠습니다.

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를 참조하십시오.

개체 데이터 유형을 사용하면 가능합니다.하지만 다음과 같은 원시적인 유형으로는bool,int,float ★★★★★★★★★★★★★★★★★」str바하비우루상속된 클래스에는 정적 속성이 존재하지 않기 때문입니다.상속된 클래스에 속성이 없는 경우 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

refdatatype 라이브러리를 기반으로 하는 솔루션:

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

네, 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"

내가 찾은 가장 좋은 방법은 다른 수업을 이용하는 것이다.개체를 만든 다음 다른 개체에 사용할 수 있습니다.

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

를 참고하여, 저는 위음음음음, 음음음음음음음음음 named named named named named named named named named named named named named named named named 라는 수업을 .staticFlag.

var를 .__success(일부러)

tryIt는 우리가해야 하는 .class class class 、 class 、 class 。

의 깃발깃발)을 위한 .staticFlag 이 는 모든 오브젝트에 이 플래그는 모든 일반 오브젝트에 대한 참조로 전송됩니다.

.tryArr.


이 스크립트의 결과:

False
False
False
False
False
True
True
True
True
True

다른 사람의 답변을 요약하고 추가함으로써 파이썬에서 정적 메서드 또는 변수를 선언하는 방법은 여러 가지가 있습니다.

1. static method()를 데코레이터로 사용한다.

정적인 방법으로 선언된 방법(기능) 위에 장식기를 올려놓기만 하면 된다.예를 들면.

class Calculator:
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res

print(Calculator.multiply(1, 2, 3, 4))              # 24

2. static method()를 파라미터 함수로 사용한다.

이 메서드는 함수 유형의 인수를 수신할 수 있으며 전달된 함수의 정적 버전을 반환합니다.예를 들면.

class Calculator:
    def add(n1, n2, *args):
        return n1 + n2 + sum(args)

Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4))                   # 10

3. classmethod()를 데코레이터로 사용:

@classmethod는 @staticmethod와 같은 기능을 수행하는데, 이번에는 함수에서 추가 인수를 수용해야 합니다(인스턴스 변수의 self 파라미터와 유사).예를 들면.

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num

print(Calculator.get_digits(314159))                # 314159

4. classmethod()를 파라미터 함수로 사용한다.

@classmethod는 클래스 정의를 수정하지 않을 경우 파라미터 함수로도 사용할 수 있습니다.예를 들면.

class Calculator:
    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res

Calculator.divide = classmethod(Calculator.divide)

print(Calculator.divide(15, 3, 5))                  # 1.0

5. 직접 신고

다른 모든 메서드 외부에 선언된 메서드/변수는 클래스 내부에서 자동으로 정적입니다.

class Calculator:   
    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)

print(Calculator.subtract(10, 2, 3, 4))             # 1

전체

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))
    
    
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res


    def add(n1, n2, *args):
        return n1 + n2 + sum(args)
    

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num


    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res


    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)
    



Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)

print(Calculator.multiply(1, 2, 3, 4))              # 24
print(Calculator.add(1, 2, 3, 4))                   # 10
print(Calculator.get_digits(314159))                # 314159
print(Calculator.divide(15, 3, 5))                  # 1.0
print(Calculator.subtract(10, 2, 3, 4))             # 1

파이썬에서 OOP를 마스터하려면 Python 문서를 참조하십시오.

혼란을 피하기 위해 정적 변수와 불변의 개체를 대조합니다.

정수, 플로트, 문자열 및 튜플과 같은 일부 원시 개체 유형은 Python에서 불변합니다.즉, 지정된 이름으로 참조되는 객체가 앞에서 설명한 객체 유형 중 하나일 경우 변경할 수 없습니다.이름은 다른 개체에 재할당할 수 있지만 개체 자체는 변경할 수 없습니다.

변수를 static으로 설정하면 변수 이름이 현재 가리키는 개체 이외의 개체를 가리키는 것을 허용하지 않음으로써 한 단계 더 나아갑니다.(주의: 이것은 일반적인 소프트웨어 개념이며 Python에 고유하지 않습니다. Python에 statics를 구현하는 방법에 대한 정보는 다른 사람의 게시물을 참조하십시오.)

클래스 팩토리 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

그래서 이건 해킹일 수도 있지만, 저는 이 모든 것들을eval(str)파이썬 3에서 정적 객체, 일종의 모순을 얻을 수 있습니다.

py 에는 Records.py 파일만 .class정적 메서드와 일부 인수를 저장하는 생성자로 정의된 개체입니다.후 .에서 I.py.py.I.import Records 각 한 후 온해야 합니다.

에요?object_name = 'RecordOne' 이름,반 이름, 반 이름, 반 이름, 반 이름, 반 이름, 반 이름, 반 이름, 반 이름, 반 이름.cur_type = eval(object_name) 후 하려면 을 합니다.cur_inst = cur_type(args), 인스턴스화하기 할 수 .cur_type.getName()예를 들어 추상적인 기본 클래스 구현이나 목표가 무엇이든 간에 말이죠.그러나 백엔드에서는 아마 python으로 인스턴스화되어 있을 것이며 실제로는 정적이지 않습니다. 평가인스턴스화 된 것이 틀림없고, 정적과 같은 동작을 일으킵니다.

목록 또는 사전을 사용하여 인스턴스 간에 "정적 동작"을 가져올 수 있습니다.

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)

사용자 정의 클래스가 존재할 때 static 변수가 생성되어 키워드 self 뒤에 와야 하는 static 변수를 정의합니다.

class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10

@staticmethod그러나 클래스 변수는 클래스의 정적 메서드로 모든 인스턴스와 공유됩니다.

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

instance = MyClass()
print(instance.i)

또는

print(MyClass.i)

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

난 노력했어

class MyClass:
  i: str

1개의 메서드콜에 값을 할당하면 동작하지 않고 에러가 발생합니다.

i is not attribute of MyClass

클래스 변수 및 하위 분류 허용

당신이 진정으로 정적 변수를 찾는 것이 아니라 동의하는 성인에게 같은 종류의 일을 할 수 있는 어떤 비단뱀 같은 것을 찾는다고 가정하면, 클래스 변수를 사용하십시오.그러면 모든 인스턴스가 액세스(및 업데이트)할 수 있는 변수가 제공됩니다.

주의: 클래스 변수를 사용하는 다른 답변의 대부분은 하위 분류를 해제할 수 있습니다.클래스를 이름으로 직접 참조하지 마십시오.

from contextlib import contextmanager

class Sheldon(object):
    foo = 73

    def __init__(self, n):
        self.n = n

    def times(self):
        cls = self.__class__
        return cls.foo * self.n
        #self.foo * self.n would give the same result here but is less readable
        # it will also create a local variable which will make it easier to break your code
    
    def updatefoo(self):
        cls = self.__class__
        cls.foo *= self.n
        #self.foo *= self.n will not work here
        # assignment will try to create a instance variable foo

    @classmethod
    @contextmanager
    def reset_after_test(cls):
        originalfoo = cls.foo
        yield
        cls.foo = originalfoo
        #if you don't do this then running a full test suite will fail
        #updates to foo in one test will be kept for later tests

를 사용하는 것과 같은 기능을 제공합니다.Sheldon.foo변수를 해결하고 다음과 같은 테스트를 통과합니다.

def test_times():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        assert s.times() == 146

def test_update():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        s.updatefoo()
        assert Sheldon.foo == 146

def test_two_instances():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        s3 = Sheldon(3)
        assert s.times() == 146
        assert s3.times() == 219
        s3.updatefoo()
        assert s.times() == 438

또한 다른 사용자가 다음과 같은 작업을 단순화할 수 있습니다.

class Douglas(Sheldon):
    foo = 42

다음과 같이 동작합니다.

def test_subclassing():
    with Sheldon.reset_after_test(), Douglas.reset_after_test():
        s = Sheldon(2)
        d = Douglas(2)
        assert d.times() == 84
        assert s.times() == 146
        d.updatefoo()
        assert d.times() == 168 #Douglas.Foo was updated
        assert s.times() == 146 #Seldon.Foo is still 73

def test_subclassing_reset():
    with Sheldon.reset_after_test(), Douglas.reset_after_test():
        s = Sheldon(2)
        d = Douglas(2)
        assert d.times() == 84 #Douglas.foo was reset after the last test
        assert s.times() == 146 #and so was Sheldon.foo

수업을 만들 때 주의해야 할 사항에 대한 훌륭한 조언은 Raymond Hettinger의 비디오를 참조하십시오.https://www.youtube.com/watch?v=HTLu2DFOdTg

언급URL : https://stackoverflow.com/questions/68645/static-class-variables-and-methods-in-python

반응형