클래스 메소드에서 property () 사용


173

본질적으로 정적 변수를 가져오고 설정하기위한 두 가지 클래스 메소드 (classmethod () 함수 사용)가있는 클래스가 있습니다. 이것들과 함께 property () 함수를 사용하려고 시도했지만 오류가 발생합니다. 인터프리터에서 다음과 같은 오류를 재현 할 수있었습니다.

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

클래스 메서드를 보여줄 수는 있지만 속성으로 작동하지는 않습니다.

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

클래스 메소드 장식 함수와 함께 property () 함수를 사용할 수 있습니까?

답변:


90

속성은 클래스에서 만들어 지지만 인스턴스에 영향을줍니다. 따라서 classmethod 속성을 원하면 메타 클래스에 속성을 만드십시오.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

그러나 어쨌든 메타 클래스를 사용하고 있으므로 클래스 메소드를 이동하면 더 잘 읽을 수 있습니다.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

또는 Python 3의 metaclass=...구문과 foo클래스 본문 외부에 정의 된 메타 클래스 및 초기 값을 설정하는 메타 클래스를 사용합니다 _var.

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

1
이것은 Python 3.2에서 작동하지 않는 것 같습니다. foo .__ metaclass __. var = property (foo.getvar.im_func, foo.setvar.im_func)를 foo .__ metaclass __. var = property (foo.getvar .__ func__, foo.setvar .__ func__)로 변경하면 "AttributeError : type "foo.var"를 실행할 때 'foo'개체에 'var' "속성이 없습니다.
— Michael Kelley

SIGH 이중 수정 : 이것은 Python 2.7에서는 작동하지만 Python 3.2에서는 작동하지 않습니다.
— Michael Kelley

@MichaelKelley- 메타 클래스
— mac

1
나는 이것을 이해하는 파이썬 3.x 방법이 무엇인지 이해하지 못한다.
— SylvainD

8
@Josay : 먼저 메타 클래스를 정의한 다음 새 class Foo(metaclass=...)구문을 사용하여 클래스를 정의해야 합니다.
— Kevin

69

Python 2.2 릴리스 정보를 읽으면 다음을 찾을 수 있습니다.

속성이 인스턴스 속성 (C (). x)이 아닌 클래스 속성 (Cx)으로 액세스되면 속성의 get 메서드가 호출되지 않습니다. 클래스 속성으로 사용될 때 특성에 대한 __get__ 조작을 대체하려는 경우 특성을 서브 클래스 (새 스타일 유형 자체)로 __get__ 메소드를 확장하거나 새로 작성하여 디스크립터 유형을 처음부터 정의 할 수 있습니다. __get__, __set__ 및 __delete__ 메소드를 정의하는 스타일 클래스.

참고 : 아래 방법은 실제로 setter에는 적용되지 않으며 getter에만 적용됩니다.

따라서 처방 된 솔루션은 ClassProperty를 속성의 하위 클래스로 만드는 것입니다.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

그러나 세터는 실제로 작동하지 않습니다.

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var 변경되지 않은 상태에서 속성을 새 값으로 덮어 썼습니다.

ClassProperty데코레이터로 사용할 수도 있습니다 .

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5

20
나는 ClassProperty의 setter 부분이 실제로 설명 된대로 작동한다고 생각하지 않습니다. 예제 어설 션이 모두 foo._var == 4 (암시 적 3이 아님) 끝에 전달됩니다. 속성을 설정하면 속성 자체가 클로버됩니다. python-dev 에서 클래스 속성에 대해 논의했을 때 getter는 사소한 반면 메타 클래스가 없으면 setter가 어렵습니다 (불가능합니까?)
— Gabriel Grant

4
@Gabriel 완전히 맞습니다. 나는 2 년 동안 아무도 그것을 지적하지 않았다.
— agf

또한 왜 당신이 여기를 전혀 사용하지 않아도 self.fget(owner)되고 사용하지 않는지 잘 모르겠습니다 @classmethod. (무엇의 것을 classmethod 않으며 , 번역 .__get__(instance, owner)(*args, **kwargs)에 function(owner, *args, **kwargs)중개자를 통해 호출, 속성은 중개 필요하지 않습니다).
— Martijn Pieters

귀하의 데모에는 게터 또는 세터에서 실제 변환이 부족하여 foo.var = 3할당 이 실제로 속성을 거치지 않고 속성 객체를 foo정수 로 바꿨다는 것을 깔끔하게 보여줍니다 . assert isinstance(foo.__dict__['var'], ClassProperty)어설 션 사이 에 호출 을 추가 하면 실패 후 foo.var = 3가 실행되는 것을 볼 수 있습니다.
— Martijn Pieters

1
파이썬 클래스는 설정에 대한 구속력 지원 설명을 클래스 자체에 전용하는 것에 대한 (그래서 instance.attr, instance.attr = value그리고 del instance.attr모든 바인드 기술자는에 발견 할 것이다 type(instance),하지만 반면 classobj.attr바인딩, classobj.attr = value그리고 del classobj.attr않습니다 하지 대체 또는 설명 개체 자체를 삭제하고 대신). 설정 및 삭제를 지원하려면 메타 클래스가 필요합니다 (클래스 객체를 인스턴스로 만들고 메타 클래스를 유형으로 만들기).
— Martijn Pieters

56

이 단순한 단순 읽기 전용 @classproperty데코레이터가 누군가 클래스 속성을 찾는 데 도움 이되기를 바랍니다 .

class classproperty(object):

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

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1

2
서브 클래스에서도 작동합니까? (하위 클래스가 클래스 속성을 재정의 할 수 있습니까?)
— zakdances

1
음? class D(C): x = 2; assert D.x == 2
— dtheodor

나는 이것을 다음 .format과 같이 사용할 때 효과가 있었으면 좋겠다 "{x}".format(**dict(self.__class__.__dict__, **self.__dict__)):(
— 2rs2ts

@Nathan뿐만 아니라 ... 설정하면의 모든 x액세스 권한 을 무시합니다 10. 이 방법처럼 나는 안티 패턴처럼 단정하고 간단하지만 소리 때문에
— 미셸 다 미코

쉽게 고정하십시오 추가 __set__가 제기하는 ValueError재정의를 방지 할 수 있습니다.
— Kiran Jonnalagadda

30

클래스 메소드 장식 함수와 함께 property () 함수를 사용할 수 있습니까?

아니.

그러나 클래스 메소드는 단순히 해당 클래스의 인스턴스에서 액세스 할 수있는 클래스의 바인딩 된 메소드 (일부 함수)입니다.

인스턴스는 클래스의 함수이므로 인스턴스에서 클래스를 파생시킬 수 있으므로 다음을 사용하여 클래스 속성에서 원하는 동작을 얻을 수 있습니다 property.

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

이 코드는 테스트하는 데 사용될 수 있습니다. 오류없이 발생해야합니다.

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

그리고 우리는 메타 클래스가 전혀 필요하지 않았으며 클래스의 인스턴스를 통해 메타 클래스에 직접 액세스하지 않습니다.

@classproperty데코레이터 작성

classproperty서브 클래 싱을 통해 몇 줄의 코드로 데코레이터를 실제로 만들 수 있습니다 property(C로 구현되었지만 여기에서 동등한 Python을 볼 수 있습니다 ).

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

그런 다음 데코레이터를 속성과 결합 된 클래스 메소드처럼 취급하십시오.

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

그리고이 코드는 오류없이 작동해야합니다.

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

그러나 이것이 얼마나 잘 충고되었는지는 확실하지 않습니다. 오래된 메일 링리스트 기사에 따르면 작동하지 않아야합니다.

강의실에서 숙소를 이용하기 :

위의 단점은 "클래스 속성"은 클래스에서 데이터 디스크립터를 덮어 쓰기 때문에 클래스에서 액세스 할 수 없다는 것 __dict__입니다.

그러나 metaclass에 정의 된 속성으로이를 재정의 할 수 있습니다 __dict__. 예를 들면 다음과 같습니다.

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

그런 다음 메타 클래스의 클래스 인스턴스는 이전 섹션에서 이미 설명한 원칙을 사용하여 클래스의 속성에 액세스하는 속성을 가질 수 있습니다.

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

이제 우리는 두 인스턴스를 모두 본다

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

그리고 수업

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

클래스 속성에 액세스 할 수 있습니다.


3
명확하고 간결하며 철저한 답변입니다. 이것은 정답입니다.
— pfabri

25

파이썬 3!

오래된 질문, 많은 견해, 진실한 파이썬 3 방법이 절실히 필요합니다.

운 좋게도 metaclasskwarg를 사용하면 쉽습니다.

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

그때, >>> Foo.var

'FOO!'


1
즉, 상자 밖으로 나가는 간단한 방법이 없습니다
— mehmet

@mehmet 이것은 간단하지 않습니까? Foo은 메타 클래스의 인스턴스이며의 인스턴스와 @property마찬가지로 메소드에 사용할 수 있습니다 Foo.
— OJFord

2
메타 클래스를 재사용 할 수 없다고 가정하면 클래스의 다른 클래스를 정의해야했습니다.
— mehmet

클래스 메소드는 클래스와 인스턴스 모두에서 작동합니다. 이 속성은 클래스에서만 작동합니다. 나는 이것이 요구되는 것이라고 생각하지 않습니다.
— Aaron Hall

1
@AaronHall 중요하다면,에 쉽게 추가 할 수 있습니다 Foo.__new__. 그 시점에서 getattribute를 대신 사용하거나 언어 기능을 가장하는 것이 실제로 어떤 접근 방법인지 질문하는 것이 좋습니다.
— OJFord

16

이 "클래스 속성"시스템을 파이썬에서 작동시키는 합리적인 방법은 없습니다.

그것이 작동하게하는 불합리한 방법은 다음과 같습니다. 메타 클래스 마법의 양을 늘리면 더 매끄럽게 만들 수 있습니다.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

문제의 핵심은 속성이 파이썬이 "설명자"라고 부르는 것입니다. 이러한 종류의 메타 프로그래밍이 어떻게 작동하는지 설명 할 수있는 짧고 쉬운 방법은 없으므로 설명자 howto 를 알려야합니다. .

상당히 고급 프레임 워크를 구현하는 경우 이러한 종류의 것들만 이해하면됩니다. 투명한 객체 지속성 또는 RPC 시스템 또는 일종의 도메인 별 언어와 같습니다.

그러나 이전 답변에 대한 의견에서 귀하는

클래스의 모든 인스턴스에서 볼 수있는 방식으로 속성을 수정해야하며 이러한 클래스 메소드가 호출되는 범위에 클래스의 모든 인스턴스에 대한 참조가 없습니다.

당신이 정말로 원하는 것은 관찰자 디자인 패턴입니다.


코드 예제의 아이디어가 마음에 들지만 실제로는 약간 어색한 것 같습니다.
— Mark Roddy

내가 성취하려고하는 것은 모든 인스턴스의 동작을 수정하기위한 플래그로 사용되는 단일 속성을 얻는 것입니다. 따라서 Observer가 내가하려는 일에 과장되어 있다고 생각합니다. 문제의 속성이 여러 개인 경우 더 기울어 질 것입니다.
— Mark Roddy

단순히 함수를 공개하고 직접 호출하는 것이 단순한 솔루션이었습니다. 내가 잘못하고 있거나 노력하고 있는지가 궁금했습니다. 그런데 여러 의견에 대해 죄송합니다. 300 자 제한.
— Mark Roddy

코드 예제의 멋진 점은 모든 복잡한 비트를 한 번 구현 한 다음 상속 할 수 있다는 것입니다. _var을 파생 클래스로 옮기십시오. 클래스 D1 (푸) : _var = 21 개 클래스 D2 (푸) _var = "안녕하세요"D1.var 21 D2.var 안녕하세요
— 토마스 L Holaday

6

메타 클래스에서만 설정하면 인스턴스화 된 객체를 통해 클래스 속성에 액세스하려는 경우 도움이되지 않습니다.이 경우 객체에 일반 속성을 설치해야합니다 (클래스 속성으로 디스패치). 다음은 조금 더 분명하다고 생각합니다.

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo

3

절반의 솔루션 인 __set__은 여전히 ​​작동하지 않습니다. 솔루션은 속성과 정적 메서드를 모두 구현하는 사용자 지정 속성 클래스입니다.

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not

3

클래스의 모든 인스턴스에서 볼 수있는 방식으로 이러한 클래스 메소드가 호출되는 범위에서 속성을 수정해야하기 때문에 클래스의 모든 인스턴스에 대한 참조가 없습니다.

수업 중 하나 이상의 인스턴스에 액세스 할 수 있습니까? 그때 할 수있는 방법을 생각할 수 있습니다.

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var

2

시도해보십시오. 기존 코드를 많이 변경 / 추가하지 않고도 작업을 수행 할 수 있습니다.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

이 property함수에는 두 개의 callable인수 가 필요합니다 . 람다 래퍼 (인스턴스를 첫 번째 인수로 전달)를 제공하면 모든 것이 잘됩니다.


Florian Bösch가 지적했듯이 (타사 라이브러리 또는 레거시 코드에 필요한) 구문은 foo.var입니다.
— Thomas L Holaday

2

다음은 클래스를 통한 액세스와 메타 클래스를 사용하는 인스턴스를 통한 액세스 모두에서 작동해야하는 솔루션입니다.

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

메타 클래스에 정의 된 setter 와도 작동합니다.


1

다른 장소를 검색 한 후 Python 2 및 3에서 유효한 클래스 속성을 정의하는 방법을 찾았습니다.

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

이것이 누군가를 도울 수 있기를 바랍니다 :)


1
이 방법이 당신이 어딘가에서 찾은 것이라면, 링크를 제공하는 것이 좋을 것입니다 ( 다른 사람들이 쓴 자료를 참조하는 방법 참조 )
— Andrew Myers

-27

여기 내 제안이 있습니다. 클래스 메소드를 사용하지 마십시오.

진심으로.

이 경우 클래스 메소드를 사용하는 이유는 무엇입니까? 왜 평범한 수업의 평범한 물건이 없습니까?


단순히 값을 변경하려는 경우 속성이 그다지 도움이되지 않습니까? 속성 값을 설정하고 완료하십시오.

감추어 야 할 것이 있다면, 미래 구현에서 변경 될 수있는 것만 사용해야합니다.

어쩌면 귀하의 예가 끝났을 수도 있고, 끝내지 못한 계산이있을 수도 있습니다. 그러나 속성이 상당한 가치를 부여하는 것처럼 보이지 않습니다.

Java에 영향을 미치는 "개인 정보 보호"기술 (Python에서 _로 시작하는 속성 이름)은 그다지 도움이되지 않습니다. 누구 한테서? (Python에서와 같이) 소스를 가지고있을 때 개인의 관점은 조금 성가시다.

Java에 영향을 미치는 EJB 스타일 getter 및 setter (종종 Python의 특성으로 수행됨)는 정적 언어 컴파일러를 사용하여 소집자를 전달할뿐만 아니라 Java의 원시적 인트로 스펙 션을 용이하게합니다. 그 게터와 세터는 모두 파이썬에서 도움이되지 않습니다.


14
클래스의 모든 인스턴스에서 볼 수있는 방식으로 이러한 클래스 메소드가 호출되는 범위에서 속성을 수정해야하기 때문에 클래스의 모든 인스턴스에 대한 참조가 없습니다.
— Mark Roddy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.