일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- I'm Sorry
- 보안
- 웹개발
- 자료구조
- 컴퓨터공학
- 자바스크립트
- 소프트웨어공학
- 알고리즘
- 파이썬
- 2
- 버전관리
- 코딩
- 사이버보안
- 딥러닝
- 네트워크보안
- Yes
- 빅데이터
- 컴퓨터비전
- 컴퓨터과학
- 데이터구조
- 머신러닝
- 프로그래밍언어
- 인공지능
- 클라우드컴퓨팅
- 네트워크
- 소프트웨어
- 데이터베이스
- 프로그래밍
- 데이터분석
- 데이터과학
- Today
- Total
스택큐힙리스트
파이썬에서 메타클래스란 무엇입니까? 본문
metaclasses가 무엇인가요? 그것들은 어떤 용도로 사용되나요?
답변 1
클래스는 객체입니다.
메타클래스를 이해하기 전에, 파이썬 클래스를 더 깊게 이해하는 것이 도움이 됩니다. 파이썬은 스몰토크 언어에서 빌린 클래스의 개념을 가지고 있어 매우 독특합니다.
대부분의 언어에서, 클래스는 객체를 생성하는 방법을 설명하는 코드 조각에 불과합니다. 파이썬에서도 어느 정도 그렇습니다.
>>> class ObjectCreator(object):
... pass
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
하지만 파이썬에서 클래스는 그 이상입니다. 클래스도 객체입니다.
네, 물체들입니다.
파이썬 스크립트가 실행될 때마다, 모든 코드 줄이 위에서 아래로 실행됩니다. 파이썬 인터프리터가 class 키워드를 만나면, 파이썬은 이어지는 클래스의 설명에서 객체를 생성합니다. 이에 따라, 다음 지시문은 다음과 같습니다.
>>> class ObjectCreator(object):
... pass
...이름이 ObjectCreator 인 객체를 생성합니다!
이 객체 (클래스)는 자체적으로 객체 (인스턴스라고 함)를 생성할 수 있습니다.
하지만 여전히 그것은 물체입니다. 따라서, 다른 모든 물체와 마찬가지로:
당신은 그것을 변수 1에 할당할 수 있습니다.
JustAnotherVariable = ObjectCreator
당신은 그것에 속성을 부여할 수 있습니다.
ObjectCreator.class_attribute = 'foo'
함수 매개 변수로 전달할 수 있습니다.
print(ObjectCreator)
1. 다른 변수에 할당하는 것만으로는 클래스의 __name__이 변경되지 않는다는 점에 유의하십시오.
>>> print(JustAnotherVariable)
>>> print(JustAnotherVariable())
<__main__.ObjectCreator object at 0x8997b4c>
동적으로 클래스 생성하기
클래스는 객체이므로, 다른 객체와 마찬가지로 즉석에서 생성할 수 있습니다.
먼저, class를 사용하여 함수 내에서 클래스를 만들 수 있습니다.
>>> def choose_class(name):
... if name == 'foo':
... class Foo(object):
... pass
... return Foo # return the class, not an instance
... else:
... class Bar(object):
... pass
... return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
하지만 여전히 전체 클래스를 직접 작성해야하기 때문에 그리 역동적이지는 않습니다.
수업은 객체이므로, 어떤 것으로부터 생성되어야 합니다.
당신이 class 키워드를 사용할 때, Python은 이 객체를 자동으로 생성합니다. 그러나 대부분의 Python에서처럼, 수동으로 이 작업을 수행하는 방법을 제공합니다.
#$@*&!@#$& 함수를 기억하세요? 그것은 객체의 타입을 알려주는 좋은 함수입니다.
>>> print(type(1))
>>> print(type(1))
>>> print(type(ObjectCreator))
>>> print(type(ObjectCreator()))
음, type은 또한 완전히 다른 능력을 가지고 있습니다: 런타임에 클래스를 생성할 수 있습니다. type은 클래스의 설명을 매개 변수로 사용하여 클래스를 반환할 수 있습니다.
나는 알고 있어, 동일한 함수가 매개 변수에 따라 완전히 다른 용도를 가질 수 있다는 것은 우스꽝스러운 일이다. 이는 Python의 하위 호환성 문제입니다.
type은 다음과 같이 작동합니다:
type(name, bases, attrs)
어디:
name : 클래스의 이름
bases : 부모 클래스의 튜플 (상속을 위해 비어 있을 수 있음)
attrs: 속성 이름과 값이 포함된 사전
Hello - 안녕하세요
1. How are you? - 어떻게 지내세요?
2. What is your name? - 당신의 이름은 무엇인가요?
3. Where are you from? - 어디에서 왔어요?
4. I love you - 사랑해요
5. Thank you - 감사합니다
6. Goodbye - 안녕히 가세요
7. See you later - 나중에 봐요
8. Yes - 예
9. No - 아니요
10. Sorry - 미안합니다
>>> class MyShinyClass(object):
... pass
이 방법으로 수동으로 생성할 수 있습니다:
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
당신은 우리가 클래스의 이름으로 MyShinyClass를 사용하고 클래스 참조를 포함하는 변수로 사용한다는 것을 알게될 것입니다. 그들은 다를 수 있지만, 복잡하게 하기에는 이유가 없습니다.
type는 클래스 속성을 정의하는 사전(dict)을 받아들입니다. 따라서:
>>> class Foo(object):
... bar = True
번역할 수 있습니다.
>>> Foo = type('Foo', (), {'bar':True})
그리고 일반 수업으로 사용됩니다:
>>> print(Foo)
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
물론, 이를 상속 받을 수 있습니다. 따라서:
>>> class FooChild(Foo):
... pass
한국어로 번역하면:
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
>>> print(FooChild.bar) # bar is inherited from Foo
True
결국에는, 클래스에 메서드를 추가하고 싶어질 것입니다. 적절한 서명(signature)을 가진 함수를 정의하고 속성으로 할당하면 됩니다.
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
그리고 동적으로 클래스를 생성한 후에도 일반적으로 생성된 클래스 객체에 메소드를 추가하는 것과 마찬가지로 더 많은 메소드를 추가할 수 있습니다.
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
당신은 우리가 어디로 가고 있는지 본다: 파이썬에서 클래스들은 객체이며, 당신은 마음대로 클래스를 동적으로 생성할 수 있습니다.
이것은 키워드 class 를 사용할 때 Python이 수행하는 작업이며, 이 작업은 메타클래스를 사용하여 수행됩니다.
메타클래스란 무엇인가요? (마침내)
메타클래스는 클래스를 생성하는 '재료'입니다.
당신은 객체를 만들기 위해 클래스를 정의하는 것이 맞나요?
하지만 우리는 파이썬 클래스가 객체임을 배웠습니다.
음, 메타 클래스는 이러한 객체를 생성하는 것입니다. 이것들은 클래스의 클래스입니다. 이러한 관점에서 그림으로 그려 볼 수 있습니다.
MyClass = MetaClass()
my_object = MyClass()
당신은 이렇게 할 수 있는 것을 보았습니다: type
MyClass = type('MyClass', (), {})
이것은 실제로 메타클래스 인 type 함수 때문입니다. type 는 Python이 모든 클래스를 비로소 만들 때 사용하는 메타클래스입니다.
이제는 왜 대문자가 아닌 소문자로 쓰였는지 궁금해 하실 겁니다. Type 가 아닌 것은 왜일까요?
음, 아마도 문자열 객체를 생성하는 클래스인 str 와 정수 객체를 생성하는 클래스인 int 그리고 클래스 객체를 생성하는 클래스인 type 의 일관성 문제인 것 같네요.
당신은 __class__ 속성을 확인하여 그것을 볼 수 있습니다.
모든 것, 그리고 말 그대로 모든 것이 Python에서 객체입니다. 정수, 문자열, 함수 및 클래스를 포함하여 모두 객체입니다. 그리고 그 모든 것은 클래스에서 생성되었습니다.
>>> age = 35
>>> age.__class__
>>> name = 'bob'
>>> name.__class__
>>> def foo(): pass
>>> foo.__class__
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
지금, 어떤 __class__ 의 __class__ 인가요?
>>> age.__class__.__class__
>>> name.__class__.__class__
>>> foo.__class__.__class__
>>> b.__class__.__class__
그래서, 메타클래스는 클래스 객체를 생성하는 것뿐입니다.
당신은 원한다면 '클래스 공장'이라고 부를 수 있습니다.
type는 파이썬에서 내장된 메타클래스이지만, 물론 자신만의 메타클래스를 만들 수 있습니다.
Python 2에서는 클래스를 작성할 때 __metaclass__ 속성을 추가할 수 있습니다 (Python 3 구문은 다음 섹션을 참조하십시오).
class Foo(object):
__metaclass__ = something...
[...]
그렇게 하면 Python은 메타클래스를 사용하여 클래스 Foo을(를) 생성합니다.
조심하세요, tricky합니다.
당신은 먼저 class Foo(object)을 작성하지만, 클래스 객체 Foo가 아직 메모리에 생성되지 않았습니다.
파이썬은 클래스 정의에서 __metaclass__ 를 찾습니다. 찾으면, Foo 로 객체 클래스를 만듭니다. 찾지 못하면 type 로 클래스를 만듭니다.
여러 번 읽으세요.
당신이 한다면:
class Foo(Bar):
pass
파이썬은 다음과 같은 작업을 수행합니다:
Foo 에는 __metaclass__ 속성이 있나요?
예, __metaclass__ 에 있는 것을 사용하여 이름이 Foo 인 클래스 객체(클래스 객체, 따라와주세요)를 인-메모리에 생성하십시오.
파이썬이 __metaclass__를 찾을 수 없으면, 모듈 레벨에서 __metaclass__를 찾아 같은 작업을 시도할 것이다 (즉, 상속 받은 것이 없는 클래스에 대해서만 실행된다).
그러면 전혀 찾을 수 없으면 __metaclass__ 을 사용하지 않고 첫 번째 부모인 Bar 의 메타클래스(기본값이 될 수도 있는 type )를 사용하여 클래스 객체를 생성합니다.
여기서 주의하세요. @#__metaclass__ 속성은 상속되지 않습니다. 부모의 메타 클래스 (lass__ ) will be.)가 상속됩니다. 만약 Bar가 type()이 아닌 type.__new__()으로 @#__metaclass__ 속성을 사용했다면, 하위 클래스는 그 동작을 상속하지 않습니다.
이제 중요한 질문은, 당신이 __metaclass__ 에 넣을 수 있는 것이 무엇인가요?
답은 수업을 만들 수 있는 것입니다.
그리고 어떤 것이 클래스를 만들 수 있을까요? type 또는 그것을 하위 클래스 또는 사용하는 모든 것입니다.
파이썬 3에서의 메타클래스
파이썬 3에서 메타 클래스를 설정하는 구문이 변경되었습니다:
class Foo(object, metaclass=something):
...
예를 들어, __metaclass__ 속성은 더 이상 사용되지 않으며, 기본 클래스 목록의 키워드 인수를 선호합니다.
메타클래스의 동작방식은 그래도 largely the same입니다.
파이썬 3에서 메타클래스에 추가 된 하나의 기능은 키워드 인자로 속성을 전달 할 수 있다는 것입니다. 다음과 같이:
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
...
Python이 이를 다루는 방법에 대해 아래 섹션을 읽으십시오.
커스텀 메타클래스
메타클래스의 주요 목적은 클래스가 생성될 때 자동으로 클래스를 변경하는 것입니다.
일반적으로 API에 대해서는 현재 컨텍스트와 일치하는 클래스를 생성하려는 경우에 이를 수행합니다.
어리석은 예를 상상해보십시오. 모듈에서 모든 클래스의 속성이 대문자로 작성되어야한다고 결정한 경우입니다. 이를 수행하는 방법은 여러 가지가 있지만 모듈 수준에서 #$ @& ** $&를 설정하는 방법 중 하나입니다.
이 방법으로 모듈의 모든 클래스는 이 메타클래스를 사용하여 생성되며, 우리는 메타클래스에 대문자로 변경할 모든 속성을 알려주기만 하면 됩니다.
운좋게도, __metaclass__은 호출 가능한 모든 것이 될 수 있습니다. 이것은 공식적으로 클래스일 필요는 없습니다. (이름에 'class'가 포함되어 있지만, 클래스일 필요는 없습니다.)
우리는 함수를 사용하여 간단한 예를 시작할 것입니다.
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attrs):
Return a class object, with the list of its attribute turned
into uppercase.
# pick up any attribute that doesn't start with '__' and uppercase it
uppercase_attrs = {
attr if attr.startswith(__) else attr.upper(): v
for attr, v in future_class_attrs.items()
}
# let `type` do the class creation
return type(future_class_name, future_class_parents, uppercase_attrs)
__metaclass__ = upper_attr # this will affect all classes in the module
class Foo(): # global __metaclass__ won't work with object though
# but we can define __metaclass__ here instead to affect only this class
# and this will work with object children
bar = 'bip'
우리 확인해 봅시다.
>>> hasattr(Foo, 'bar')
False
>>> hasattr(Foo, 'BAR')
True
>>> Foo.BAR
'bip'
이제, 똑같이 하되, 메타클래스에 실제 클래스를 사용해 봅시다:
# remember that `type` is actually a class like `str` and `int`
# so you can inherit from it
class UpperAttrMetaclass(type):
# __new__ is the method called before __init__
# it's the method that creates the object and returns it
# while __init__ just initializes the object passed as parameter
# you rarely use __new__, except when you want to control how the object
# is created.
# here the created object is the class, and we want to customize it
# so we override __new__
# you can do some stuff in __init__ too if you wish
# some advanced use involves overriding __call__ as well, but we won't
# see this
def __new__(upperattr_metaclass, future_class_name,
future_class_parents, future_class_attrs):
uppercase_attrs = {
attr if attr.startswith(__) else attr.upper(): v
for attr, v in future_class_attrs.items()
}
return type(future_class_name, future_class_parents, uppercase_attrs)
위의 내용을 다시 작성해 봅시다. 이번에는 변수 이름이 더 짧고 현실적인 이름으로 대체합시다.
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith(__) else attr.upper(): v
for attr, v in attrs.items()
}
return type(clsname, bases, uppercase_attrs)
당신은 추가 인자 cls 를 주목했을 수도 있습니다. 그것에 대해 특별한 것은 없습니다. __new__ 은 항상 첫 번째 매개변수로 정의된 클래스를 받습니다. 그저 일반 메소드에서 인스턴스를 첫 번째 매개변수로 받을 때나 클래스 메소드에서 정의된 클래스를 받을 때처럼입니다.
하지만 이것은 적절한 OOP가 아닙니다. 우리는 직접 type를 호출하고 덮어쓰거나 부모의 __new__를 호출하지 않습니다. 대신 그렇게 해 봅시다.
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith(__) else attr.upper(): v
for attr, v in attrs.items()
}
return type.__new__(cls, clsname, bases, uppercase_attrs)
우리는 상속을 쉽게 할 수 있는 super를 사용하여 더욱 깨끗하게 만들 수 있습니다 (메타 클래스에서 상속, 타입에서 상속 등).
class UpperAttrMetaclass(type):
def __new__(cls, clsname, bases, attrs):
uppercase_attrs = {
attr if attr.startswith(__) else attr.upper(): v
for attr, v in attrs.items()
}
# Python 2 requires passing arguments to super:
return super(UpperAttrMetaclass, cls).__new__(
cls, clsname, bases, uppercase_attrs)
# Python 3 can use no-arg super() which infers them:
return super().__new__(cls, clsname, bases, uppercase_attrs)
오, 그리고 Python 3에서 이 호출을 이렇게 키워드 인수와 함께 사용하면:
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):
...
메타클래스에서 사용하려면 이렇게 번역됩니다.
class MyMetaclass(type):
def __new__(cls, clsname, bases, dct, kwargs1=default):
...
그것이 전부입니다. 메타클래스에 대해 더 이상 얘기할 것이 없습니다.
메타클래스를 사용하여 코드가 복잡해지는 이유는 메타클래스 때문이 아니라 보통 메타클래스를 사용하여 내사와 상속 조작, __dict__와 같은 변수를 이용한 내밀한 작업을 할 때 반영성에 의존하기 때문입니다.
실제로, 메타클래스는 흑마법을 실행하기 위해 특히 유용하며, 따라서 복잡한 작업을 수행하는 데 효과적입니다. 그러나 그 자체로는 단순합니다.
클래스 생성 가로채기
클래스를 수정하세요.
수정된 클래스를 반환합니다.
함수 대신 메타클래스 클래스를 사용하는 이유는 무엇인가요?
__metaclass__가 모든 호출 가능한 함수를 받을 수 있다면, 더 복잡해 보이는 클래스를 사용하는 이유가 무엇인가요?
그렇게 하는 이유는 여러 가지가 있습니다:
의도는 분명해요. UpperAttrMetaclass(type) 를 읽으면 무엇이 따라올지 알 수 있어요.
OOP를 사용할 수 있습니다. 메타클래스는 메타클래스에서 상속하고 부모 메서드를 재정의 할 수 있습니다. 메타클래스는 심지어 메타클래스도 사용할 수 있습니다.
만약 메타클래스 클래스를 지정하면, 클래스의 하위 클래스는 메타클래스의 인스턴스가 될 것입니다. 그러나 메타클래스 함수를 지정하면 그렇지 않습니다.
당신은 코드를 더 나은 구조로 만들 수 있습니다. 위의 예제와 같이 사소한 것에 메타클래스를 사용하지 마십시오. 일반적으로 복잡한 것에 사용됩니다. 여러 가지 메소드를 만들고 하나의 클래스에 그룹화할 수 있는 능력이 있다는 것은 코드를 읽기 쉽게 만드는 데 매우 유용합니다.
당신은 new__ ,
som , __init__ , 그리고 _ . Which wi 에서 당신이 다양한 것을 할 수 있습니다. 보통 당신이 모든 것을 new__ ,
som 에서 할 수 있더라도, 어떤 사람들은 __init__ 를 사용하는 게 더 편하다고 느낄 수 있습니다.
이것들은 메타클래스라고 불린다, 젠장! 반드시 뭔가를 의미하고 있을 텐데!
메타 클래스를 사용하는 이유는 무엇인가요?
이제 큰 질문입니다. 왜 일부 모호하고 오류가 발생할 가능성이 있는 기능을 사용하려고합니까?
보통 그렇게 안 해.
메타클래스는 99%의 사용자가 걱정할 필요가 없는 더 깊은 마법입니다. 만약 메타클래스가 필요한지 궁금하다면, 그렇지 않습니다(실제로 필요한 사람들은 불확실성 없이 필요하며, 그들에게 왜 필요한지 설명할 필요가 없습니다).
파이썬 전문가 팀 피터스
메타클래스의 주요 사용 사례는 API 생성입니다. 이에 대한 일반적인 예는 Django ORM입니다. 이를 통해 다음과 같은 것을 정의할 수 있습니다.
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
하지만 이렇게하면:
person = Person(name='bob', age='35')
print(person.age)
그것은 IntegerField 객체를 반환하지 않습니다. 그것은 int 을 반환하며, 데이터베이스에서 직접 가져올 수도 있습니다.
이것은 가능합니다. 왜냐하면 models.Model가 __metaclass__를 정의하며, 간단한 문장으로 정의한 Person를 데이터베이스 필드에 대한 복잡한 후크로 변환하는 마법을 사용합니다.
Django는 간단한 API를 노출하고 메타클래스를 사용하여 복잡한 것을 간단하게 만듭니다. 이 API로부터 코드를 재생성하여 이면에서 실제 작업을 수행합니다.
마지막 단어
먼저, 클래스가 인스턴스를 생성할 수 있는 객체임을 알고 계십니다.
그러면 사실 클래스들은 메타클래스의 인스턴스입니다.
>>> class Foo(object): pass
>>> id(Foo)
142630324
파이썬에서 모든 것은 객체이며, 모든 것은 클래스의 인스턴스 또는 메타클래스의 인스턴스 중 하나입니다.
type 를 제외하고.
type는 실제로 자체 메타 클래스입니다. 이것은 순수한 Python에서 재현할 수없는 것이며, 구현 수준에서 조금 속임수를 사용하여 수행됩니다.
둘째, 메타 클래스는 복잡합니다. 매우 간단한 클래스 변경에는 사용하지 않을 수도 있습니다. 클래스를 변경하는 두 가지 기술을 사용하여 클래스를 변경할 수 있습니다.
monkey patching
클래스 데코레이터
당신이 클래스 변경이 필요한 경우 99%는 이것들을 사용하는 것이 더 좋습니다.
하지만 98%의 경우, 당신은 전혀 수업 변경이 필요하지 않습니다.
답변 2
파이썬에서 메타클래스란 무엇일까요? 메타클래스는 파이썬의 특별한 기능 중 하나로, 클래스를 만드는 클래스라고 할 수 있습니다. 이러한 메타클래스는 파이썬의 객체지향 프로그래밍에 매우 중요한 역할을 합니다.
메타클래스는 기본적으로 파이썬에서 클래스가 만들어질 때마다 호출되는 함수입니다. 이 함수를 통해 클래스를 만들기 위한 기본 틀을 만들 수 있습니다. 그리고 이 틀은 다양한 방식으로 조작될 수 있으며, 이를 통해 다양한 종류의 클래스를 만들 수 있습니다.
메타클래스를 사용하면 클래스를 만들 때 추가적인 함수나 변수를 포함시킬 수 있습니다. 예를 들면, ORM(Object-Relational Mapping)을 구현하는 데 사용할 수 있는 클래스가 있습니다.
메타클래스를 사용하는 것은 파이썬에서 고급 객체지향 프로그래밍을 구현하는 데 매우 중요합니다. 이 기술을 잘 활용하면 더욱 강력하고 유연한 클래스를 만들 수 있습니다.
따라서, 파이썬을 사용하여 고급 객체지향 프로그래밍을 구현하는 개발자라면 메타클래스를 잘 이해하고 이를 적용하여 코드를 작성해야 합니다.
한 마디로, 파이썬에서 메타클래스란 클래스를 만들기 위한 클래스로, 객체지향 프로그래밍에서 매우 중요한 역할을 합니다. 이 기능을 잘 활용하면 더욱 강력하고 유연한 코드를 작성할 수 있습니다.