문제

사람이 친구가 사용하기 좋아하는 메타클래스고,정기적으로 제공으로 그들을 솔루션입니다.

나의 마음은 당신이 거의 필요하지 않 사용하여 메타클래스.왜?기 때문에 나는 그는 경우가 다음과 같은 작업을 수행되는 클래스에,당신은 아마도 그것을 하고 있는 개체입니다.고 작은 재설계/리팩터링 순서입니다.

를 사용할 수 있는 메타클래스가 발생에 많은 사람들이 많은 장소의 클래스를 사용하여 어떤 종류의 두 번째 속도체하는 것 같은 비참하다.프로그램에 의해 대체되는 메타-프로그래밍이 가능한가요?또한 클래스의 장식에는 불행하게도 그것도 더 많은 수락가능합니다.

그래서 하시기 바랍니다,나는 절망하는 알고의 유효합니다(콘크리트)사용 사례에 대한 메타클래스에서는 Python.또는 계몽 할 이유를 변화시키는 클래스가 더 이상 돌연변이,개체로.

내가 시작됩니다:

때때로 사용할 때 타사 라이브러리는 것이 유용할 수 있을 변 클래스에서 어떤 방법입니다.

(이 경우는 생각할 수 있고,그것은 콘크리트)

도움이 되었습니까?

해결책

Matplotlib의 프론트 엔드로서 비 중 활성화 플롯을 처리하는 수업이 있습니다. 그러나 때때로 대화식 플롯을 원합니다. 몇 가지 기능만으로도 그림 수를 늘리거나 수동으로 콜 드로우 등을 늘릴 수 있다는 것을 알았지 만마다 플로팅 호출 전후에이를 수행해야했습니다. 따라서 대화식 플로팅 래퍼와 오프 스크린 플로팅 래퍼를 만들려면 다음과 같은 작업을 수행하는 것보다 메타 클래스를 통해 적절한 방법을 감싸는 것이 더 효율적이라는 것을 알았습니다.

class PlottingInteractive:
    add_slice = wrap_pylab_newplot(add_slice)

이 방법은 API 변경 등을 유지하지 못하지만 클래스 속성을 반복하는 방법 __init__ 클래스 속성을 다시 설정하기 전에 더 효율적이며 최신 정보를 유지합니다.

class _Interactify(type):
    def __init__(cls, name, bases, d):
        super(_Interactify, cls).__init__(name, bases, d)
        for base in bases:
            for attrname in dir(base):
                if attrname in d: continue # If overridden, don't reset
                attr = getattr(cls, attrname)
                if type(attr) == types.MethodType:
                    if attrname.startswith("add_"):
                        setattr(cls, attrname, wrap_pylab_newplot(attr))
                    elif attrname.startswith("set_"):
                        setattr(cls, attrname, wrap_pylab_show(attr))

물론 더 나은 방법이있을 수 있지만, 이것이 효과적이라는 것을 알았습니다. 물론, 이것은 또한 할 수 있습니다 __new__ 또는 __init__, 그러나 이것은 내가 가장 간단한 솔루션이었습니다.

다른 팁

나는 최근에 같은 질문을 받았고 몇 가지 답변을 생각해 냈습니다. 언급 된 몇 가지 사용 사례에 대해 자세히 설명하고 몇 가지 새로운 사례를 추가하고 싶었 기 때문에이 스레드를 되 살리는 것이 좋기를 바랍니다.

내가 본 대부분의 메타 클래스는 두 가지 중 하나를 수행합니다.

  1. 등록 (데이터 구조에 클래스 추가) :

    models = {}
    
    class ModelMetaclass(type):
        def __new__(meta, name, bases, attrs):
            models[name] = cls = type.__new__(meta, name, bases, attrs)
            return cls
    
    class Model(object):
        __metaclass__ = ModelMetaclass
    

    서브 클래스 할 때마다 Model, 귀하의 클래스는에 등록되어 있습니다 models 사전:

    >>> class A(Model):
    ...     pass
    ...
    >>> class B(A):
    ...     pass
    ...
    >>> models
    {'A': <__main__.A class at 0x...>,
     'B': <__main__.B class at 0x...>}
    

    이것은 수업 데코레이터로도 할 수 있습니다.

    models = {}
    
    def model(cls):
        models[cls.__name__] = cls
        return cls
    
    @model
    class A(object):
        pass
    

    또는 명시 적 등록 기능으로 :

    models = {}
    
    def register_model(cls):
        models[cls.__name__] = cls
    
    class A(object):
        pass
    
    register_model(A)
    

    실제로, 이것은 거의 동일합니다. 당신은 클래스 데코레이터를 불리하게 언급하지만, 그것은 실제로 클래스에서 기능 호출에 대한 구문 설탕에 지나지 않기 때문에 그것에 대해 마술이 없습니다.

    어쨌든,이 경우 메타 클래스의 장점은 하위 클래스에 대해 작동하기 때문에 상속입니다. 반면 다른 솔루션은 서브 클래스에 대해서만 작동합니다.

    >>> class B(A):
    ...     pass
    ...
    >>> models
    {'A': <__main__.A class at 0x...> # No B :(
    
  2. 리팩토링 (클래스 속성 수정 또는 새 특성 추가) :

    class ModelMetaclass(type):
        def __new__(meta, name, bases, attrs):
            fields = {}
            for key, value in attrs.items():
                if isinstance(value, Field):
                    value.name = '%s.%s' % (name, key)
                    fields[key] = value
            for base in bases:
                if hasattr(base, '_fields'):
                    fields.update(base._fields)
            attrs['_fields'] = fields
            return type.__new__(meta, name, bases, attrs)
    
    class Model(object):
        __metaclass__ = ModelMetaclass
    

    서브 클래스 할 때마다 Model 그리고 일부를 정의하십시오 Field 속성, 그들은 그들의 이름을 주입하고 (예 :보다 유익한 오류 메시지를 위해) _fields 사전 (매번 모든 클래스 속성과 모든 기본 클래스 속성을 살펴볼 필요없이 쉬운 반복을 위해 :

    >>> class A(Model):
    ...     foo = Integer()
    ...
    >>> class B(A):
    ...     bar = String()
    ...
    >>> B._fields
    {'foo': Integer('A.foo'), 'bar': String('B.bar')}
    

    다시, 이것은 클래스 데코레이터와 함께 (상속없이) 수행 할 수 있습니다.

    def model(cls):
        fields = {}
        for key, value in vars(cls).items():
            if isinstance(value, Field):
                value.name = '%s.%s' % (cls.__name__, key)
                fields[key] = value
        for base in cls.__bases__:
            if hasattr(base, '_fields'):
                fields.update(base._fields)
        cls._fields = fields
        return cls
    
    @model
    class A(object):
        foo = Integer()
    
    class B(A):
        bar = String()
    
    # B.bar has no name :(
    # B._fields is {'foo': Integer('A.foo')} :(
    

    또는 명시 적으로 :

    class A(object):
        foo = Integer('A.foo')
        _fields = {'foo': foo} # Don't forget all the base classes' fields, too!
    

    비록 읽을 수 있고 유지 관리 가능한 비 메타 프로그래밍에 대한 옹호와는 반대로, 이것은 훨씬 더 번거롭고 중복성 및 오류가 발생하기 쉽습니다.

    class B(A):
        bar = String()
    
    # vs.
    
    class B(A):
        bar = String('bar')
        _fields = {'B.bar': bar, 'A.foo': A.foo}
    

가장 일반적이고 구체적인 사용 사례를 고려한 후, 메타 클래스를 절대적으로 사용해야하는 유일한 사례는 클래스 이름이나 기본 클래스 목록을 수정하려는 경우입니다. 한 번 정의 된 경우 이러한 매개 변수는 클래스에 구워지고 장식자가 없기 때문입니다. 또는 기능은 그것들을 풀 수 있습니다.

class Metaclass(type):
    def __new__(meta, name, bases, attrs):
        return type.__new__(meta, 'foo', (int,), attrs)

class Baseclass(object):
    __metaclass__ = Metaclass

class A(Baseclass):
    pass

class B(A):
    pass

print A.__name__ # foo
print B.__name__ # foo
print issubclass(B, A)   # False
print issubclass(B, int) # True

이는 유사한 이름이나 불완전한 상속 트리가있는 클래스가 정의 될 때마다 경고를 발행하는 프레임 워크에 유용 할 수 있지만 실제로 이러한 값을 바꾸는 트롤링 옆의 이유는 생각할 수 없습니다. 어쩌면 David Beazley가 할 수 있습니다.

어쨌든, Python 3에서는 메타 클라스가 __prepare__ 방법, 클래스 본체를 dict, 따라서 주문 된 속성, 과부하 된 속성 및 기타 사악한 멋진 것들을 지원합니다.

import collections

class Metaclass(type):

    @classmethod
    def __prepare__(meta, name, bases, **kwds):
        return collections.OrderedDict()

    def __new__(meta, name, bases, attrs, **kwds):
        print(list(attrs))
        # Do more stuff...

class A(metaclass=Metaclass):
    x = 1
    y = 2

# prints ['x', 'y'] rather than ['y', 'x']

 

class ListDict(dict):
    def __setitem__(self, key, value):
        self.setdefault(key, []).append(value)

class Metaclass(type):

    @classmethod
    def __prepare__(meta, name, bases, **kwds):
        return ListDict()

    def __new__(meta, name, bases, attrs, **kwds):
        print(attrs['foo'])
        # Do more stuff...

class A(metaclass=Metaclass):

    def foo(self):
        pass

    def foo(self, x):
        pass

# prints [<function foo at 0x...>, <function foo at 0x...>] rather than <function foo at 0x...>

주문 된 속성은 생성 카운터를 사용하여 달성 할 수 있으며 기본 인수로 과부하를 시뮬레이션 할 수 있다고 주장 할 수 있습니다.

import itertools

class Attribute(object):
    _counter = itertools.count()
    def __init__(self):
        self._count = Attribute._counter.next()

class A(object):
    x = Attribute()
    y = Attribute()

A._order = sorted([(k, v) for k, v in vars(A).items() if isinstance(v, Attribute)],
                  key = lambda (k, v): v._count)

 

class A(object):

    def _foo0(self):
        pass

    def _foo1(self, x):
        pass

    def foo(self, x=None):
        if x is None:
            return self._foo0()
        else:
            return self._foo1(x)

훨씬 추악한 것 외에도 유연성이 떨어집니다. 정수 및 문자열과 같은 순서 문자 속성을 원한다면 어떻게해야합니까? 만약 None 유효한 값입니다 x?

첫 번째 문제를 해결하는 창의적인 방법은 다음과 같습니다.

import sys

class Builder(object):
    def __call__(self, cls):
        cls._order = self.frame.f_code.co_names
        return cls

def ordered():
    builder = Builder()
    def trace(frame, event, arg):
        builder.frame = frame
        sys.settrace(None)
    sys.settrace(trace)
    return builder

@ordered()
class A(object):
    x = 1
    y = 'foo'

print A._order # ['x', 'y']

그리고 두 번째를 해결하는 창의적인 방법이 있습니다.

_undefined = object()

class A(object):

    def _foo0(self):
        pass

    def _foo1(self, x):
        pass

    def foo(self, x=_undefined):
        if x is _undefined:
            return self._foo0()
        else:
            return self._foo1(x)

그러나 이것은 단순한 메타 클라스 (특히 첫 번째 뇌가 녹는 첫 번째 메타 클래스보다 부두가 많습니다). 내 요점은, 당신은 메타 클라스를 익숙하지 않고 반 직관적 인 것으로 간주하지만, 프로그래밍 언어의 다음 진화 단계로 볼 수도 있습니다. 사고 방식을 조정해야합니다. 결국, 당신은 아마도 기능 포인터가있는 구조물을 정의하고 그 기능에 대한 첫 번째 인수로 전달하는 것을 포함하여 C로 모든 것을 할 수 있습니다. 처음으로 C ++를 보는 사람은 "이 마법은 무엇입니까? 왜 컴파일러가 암시 적으로 통과합니까? this 방법에 대해서는 규칙적이고 정적 기능이 아닌가? 당신의 주장에 대해 명시적이고 장점이되는 것이 낫습니다. " 메타 클래스를 이해하십시오. 실제로 매우 간단하므로 편리 할 때 사용하지 않겠습니까?

그리고 마지막으로, 메타 클라스는 무선이며 프로그래밍은 재미 있어야합니다. 표준 프로그래밍 구성과 디자인 패턴을 항상 사용하는 것은 지루하고 영감을주지 않으며 상상력을 방해합니다. 조금 살아라! 여기에 메타 메타 클라스가 있습니다.

class MetaMetaclass(type):
    def __new__(meta, name, bases, attrs):
        def __new__(meta, name, bases, attrs):
            cls = type.__new__(meta, name, bases, attrs)
            cls._label = 'Made in %s' % meta.__name__
            return cls 
        attrs['__new__'] = __new__
        return type.__new__(meta, name, bases, attrs)

class China(type):
    __metaclass__ = MetaMetaclass

class Taiwan(type):
    __metaclass__ = MetaMetaclass

class A(object):
    __metaclass__ = China

class B(object):
    __metaclass__ = Taiwan

print A._label # Made in China
print B._label # Made in Taiwan

메타 클라스의 목적은 클래스/객체 차이를 메타 클래스/클래스로 대체하는 것이 아닙니다. 어떤 방식 으로든 클래스 정의 (및 그 인스턴스)의 동작을 변경하는 것입니다. 효과적으로 기본값보다 특정 도메인에 더 유용 할 수있는 방식으로 클래스 문의 동작을 변경하는 것입니다. 내가 사용한 것은 다음과 같습니다.

  • 일반적으로 핸들러를 등록하기 위해 하위 클래스 추적. 플러그인 스타일 설정을 사용할 때 편리합니다. 여기서 단순히 서브 클래스를 만들고 몇 가지 클래스 속성을 설정하여 특정 항목에 대한 핸들러를 등록하려고합니다. 예를 들어. 각 클래스가 해당 유형에 맞는 적절한 방법 (재생 / GET 태그 등)을 구현하는 다양한 음악 형식에 대한 핸들러를 작성한다고 가정 해 봅시다. 새 유형에 핸들러를 추가하면 다음이됩니다.

    class Mp3File(MusicFile):
        extensions = ['.mp3']  # Register this type as a handler for mp3 files
        ...
        # Implementation of mp3 methods go here
    

    메타 클래스는 사전을 유지합니다 {'.mp3' : MP3File, ... } 기타 및 공장 기능을 통해 핸들러를 요청할 때 적절한 유형의 객체를 구성합니다.

  • 변화하는 행동. 특정 속성에 특별한 의미를 첨부하여 행동이있을 때 변경된 동작을 초래할 수 있습니다. 예를 들어 이름이있는 메소드를 찾고 싶을 수도 있습니다. _get_foo 그리고 _set_foo 그리고 그것들을 속성으로 투명하게 변환합니다. 실제 예로서 여기에 있습니다 내가 쓴 레시피는 더 C와 같은 구조물 정의를 제공하기 위해 쓴 레시피입니다. 메타 클래스는 선언 된 항목을 구조 형식 문자열로 변환하고 상속을 처리하고이를 다룰 수있는 클래스를 생성하는 데 사용됩니다.

    다른 실제 예제는 다양한 ORM을 살펴보십시오. sqlalchemy 's Orm 또는 sqlobject. 다시 말하지만, 목적은 특정 의미로 정의 (여기서 SQL 열 정의)를 해석하는 것입니다.

Tim Peter의 클래식 인용문부터 시작합시다 :

메타 클래스는 사용자의 99%가 걱정 해야하는 마법입니다. 당신이 그들을 필요로하는지 궁금해한다면, 당신은 (실제로 그들을 필요로하는 사람들은 그들이 필요하다는 것을 확실하게 알고, 그 이유에 대한 설명이 필요하지 않습니다). 팀 피터스 (CLP Post 2002-12-22)

그 말을했지만, 나는 (정기적으로) 메타 클래스의 진정한 용도를 가로 질러 달렸다. 떠오르는 것은 모든 모델이 Models.Model에서 상속되는 Django에 있습니다. Models.Model은 Django의 Orm Goodness로 DB 모델을 포장하기 위해 심각한 마법을 수행합니다. 그 마법은 메타 클라스를 통해 발생합니다. 모든 예외 클래스, 관리자 클래스 등을 만듭니다.

스토리의 시작은 django/db/models/base.py, class modelbase ()를 참조하십시오.

메타 클래스는 파이썬에서 도메인 특정 언어를 구성하는 데 유용 할 수 있습니다. 구체적인 예는 Sqlobject의 선언적 구문 인 Django입니다.

기본 예 보수적 인 메타 클라스 Ian Bicking에 의해 :

내가 사용한 메타 클래스는 주로 선언적 인 프로그래밍 스타일을 지원하기 위해 주로 사용되었습니다. 예를 들어, 유효성 검사 스키마를 고려하십시오.

class Registration(schema.Schema):
    first_name = validators.String(notEmpty=True)
    last_name = validators.String(notEmpty=True)
    mi = validators.MaxLength(1)
    class Numbers(foreach.ForEach):
        class Number(schema.Schema):
            type = validators.OneOf(['home', 'work'])
            phone_number = validators.PhoneNumber()

다른 기술 : 파이썬에서 DSL을 구축하기위한 성분 (PDF).

편집 (ALI) : 컬렉션 및 인스턴스를 사용 하여이 작업을 수행하는 예는 내가 선호하는 것입니다. 중요한 사실은 인스턴스로, 더 많은 힘을주고 메타 클래스를 사용할 이유를 제거합니다. 예제는 클래스와 인스턴스의 혼합물을 사용한다는 점에 주목할 가치가 있습니다. 이는 분명히 메타 클래스로 모든 것을 할 수는 없습니다. 그리고 진정으로 불균일 한 방법을 만듭니다.

number_validator = [
    v.OneOf('type', ['home', 'work']),
    v.PhoneNumber('phone_number'),
]

validators = [
    v.String('first_name', notEmpty=True),
    v.String('last_name', notEmpty=True),
    v.MaxLength('mi', 1),
    v.ForEach([number_validator,])
]

완벽하지는 않지만 이미 마법이 거의없고, 메타 클래스가 필요하지 않으며, 균일 성이 향상되었습니다.

메타 클라스 사용의 합리적인 패턴은 동일한 클래스가 인스턴스화 될 때마다 반복적으로 정의 될 때 한 번 일을하는 것입니다.

여러 클래스가 동일한 특수 행동을 공유 할 때 반복 __metaclass__=X 특수 목적 코드를 반복하고/또는 임시 공유 슈퍼 클래스를 소개하는 것보다 분명히 낫습니다.

그러나 하나의 특별 계급과 예측 가능한 확장이 없더라도 __new__ 그리고 __init__ 메타 클래스는 특수 목적 코드를 혼합하는 것보다 클래스 변수 또는 기타 글로벌 데이터를 초기화하는 더 깨끗한 방법입니다. def 그리고 class 클래스 정의 본문의 진술.

내가 파이썬에서 메타 클라스를 사용한 유일한 시간은 Flickr API의 래퍼를 쓸 때였습니다.

나의 목표는 긁는 것이었다 Flickr의 API 사이트 Python 객체를 사용하여 API 액세스를 허용하기 위해 완전한 클래스 계층 구조를 동적으로 생성합니다.

# Both the photo type and the flickr.photos.search API method 
# are generated at "run-time"
for photo in flickr.photos.search(text=balloons):
    print photo.description

따라서이 예에서는 웹 사이트에서 전체 Python Flickr API를 생성했기 때문에 실제로 런타임에 클래스 정의를 모릅니다. 유형을 동적으로 생성 할 수 있다는 것은 매우 유용했습니다.

나는 어제 똑같은 것을 생각하고 완전히 동의했습니다. 코드의 합병증을보다 선언하려는 시도로 인한 코드의 합병증은 일반적으로 코드베이스를 유지하기가 더 어렵고 읽기가 어렵고 피스닉이 적습니다. 또한 일반적으로 많은 copy.copy () ing (상속을 유지하고 클래스에서 인스턴스로 복사하기 위해)이 필요하며, 많은 곳에서 진행되는 일 (항상 메타 클라스에서 바라 보면서)을 찾아야한다는 것을 의미합니다. 파이썬 곡물도 있습니다. 나는 Formencode와 Sqlalchemy 코드를 통해 그러한 선언적 스타일이 그만한 가치가 있는지 확인하고 분명하지 않은지 확인했습니다. 이러한 스타일은 설명 자 (예 : 속성 및 방법) 및 불변 데이터에 맡겨야합니다. 루비는 그러한 선언적 스타일을 더 잘 지원하고 있으며 핵심 파이썬 언어가 그 경로를 내려 가지 않아서 기쁩니다.

디버깅에 대한 사용을 볼 수 있습니다. 모든 기본 클래스에 메타 클래스를 추가하여 더 풍부한 정보를 얻으십시오. 또한 일부 보일러 플레이트 코드를 제거하기 위해 (매우) 큰 프로젝트에서만 사용하는 것을 봅니다 (그러나 명확성 상실). sqlalchemy for 예시 클래스 정의의 속성 값을 기준으로 모든 서브 클래스에 특정 사용자 정의 메소드를 추가하여 다른 곳에서 사용합니까? 예를 들어 장난감 예제.

class test(baseclass_with_metaclass):
    method_maker_value = "hello"

"hello"(문자열 끝에 "hello"를 추가 한 메소드)을 기반으로 해당 클래스의 메소드를 생성하는 메타 클라스가있을 수 있습니다. 관리 가능성에 좋을 수 있습니다. 대신 정의해야 할 모든 서브 클래스에 메소드를 작성하지 않아도 메소드 _maker_value입니다.

이에 대한 필요성은 매우 드물지만 약간의 타이핑 만 줄어들어 충분한 코드베이스가 없다면 실제로 고려할 가치가 없습니다.

당신이 절대적으로 결코 를 사용하 metaclass,할 수 있기 때문에 항상을 구성하는 클래스가 무엇을 원하는 상속 사용 또는 집합의 클래스하려는 수정할 수 있습니다.

는 말했다,그것은 매우 편리할 수 있습 in Smalltalk 와 루비를 수정할 수 있어야 합니다 기존 반지만,Python 좋아하지 않는 않는다.

DeveloperWorks 문서 에 metaclassing 파이썬에는 도움이 될 수 있습니다.이 위키 문서 도 매우 좋습니다.

메타 클라스는 프로그래밍을 대체하지 않습니다! 그것들은 더 우아한 작업을 자동화하거나 더 우아하게 만들 수있는 트릭 일뿐입니다. 이것의 좋은 예는입니다 pygments 구문 강조 라이브러리. 그것은 호출 된 수업이 있습니다 RegexLexer 이를 통해 사용자는 클래스의 정규 표현식으로 일련의 Lexing 규칙을 정의 할 수 있습니다. 메타 클라스는 정의를 유용한 구문 분석기로 전환하는 데 사용됩니다.

그들은 소금과 같습니다. 너무 많이 사용하기 쉽습니다.

내가 메타 클래스를 사용한 방식은 클래스에 몇 가지 속성을 제공하는 것이 었습니다. 예를 들어 :

class NameClass(type):
    def __init__(cls, *args, **kwargs):
       type.__init__(cls, *args, **kwargs)
       cls.name = cls.__name__

말할 것입니다 이름 메타 클라스가 nameclass를 가리 키게하는 모든 클래스의 속성.

일부 GUI 라이브러리의 문제가 있을 경우 여러 스레드에서 하려고 그들과 상호 작용할 수 있습니다. tkinter 하나의 예;고있는 동안 하나의 명시적으로 처리한 문제 및 이벤트 큐,그것은 멀리 할 수 있는 간단한 라이브러리를 사용하는 방식으로 무시 문제에 모두 있습니다.보라-매직의 메타클래스.

할 수 있는 동적으로 다시 쓰는 전체 라이브러리를 원활하게 작동하도록 제대로 예상대로 다중 스레드 응용 프로그램에서 극단적으로 도움이 될 수 있는 어떤 상황에서.이 safetkinter 모듈 않는 그의 도움으로 metaclass 에 의해 제공됩 threadbox 모듈--이벤트 큐가 필요하지 않습니다.

중 하나가 깔끔한 측면 threadbox 은 그것이 무엇인지 상관하지 않는 클래스 클론입니다.제공하는 방법의 예는 모든 기본 클래스를 받을 수 있는 metaclass 경우 필요합니다.추가적 혜택을 함께 제공되는 메타클래스들에서 실행되는 클래스를 상속받니다.프로그램을 작성을 왜?

메타 클래스의 유일한 합법적 인 사용 사례는 다른 코가 개발자가 코드를 터치하지 않도록하는 것입니다. 코시 개발자가 메타 클라스를 마스터하고 당신과 함께 찌르기 시작하면 다른 수준에서 두 개로 던져서 그들을 막으십시오. 그래도 작동하지 않으면 사용을 시작하십시오 type.__new__ 또는 재귀 메타 클라스를 사용하는 일부 체계.

(뺨에 혀가 혀, 그러나 나는 이런 종류의 난독 화가 끝난 것을 보았습니다. Django는 완벽한 예입니다)

이것은 사소한 용도이지만 ... 내가 유용한 메타 클래스가 발견 된 한 가지는 서브 클래스가 생성 될 때마다 함수를 호출하는 것입니다. 나는 이것을 __initsubclass__ 속성 : 서브 클래스가 생성 될 때마다 해당 메소드를 정의하는 모든 상위 클래스가 __initsubclass__(cls, subcls). 이를 통해 부모 클래스를 생성 한 다음 일부 글로벌 레지스트리에 모든 서브 클래스를 등록하고 정의 될 때마다 서브 클래스에서 변하지 않는 검사를 실행하고, 늦은 바인딩 작업을 수행하는 등을 수행 할 필요가 없습니다. 또는 이러한 별도의 의무를 수행하는 각각의 의무를 수행하는 맞춤형 메타 클래스를 만듭니다.

당신을 염두에두고, 나는이 행동의 암시 적 마법이 문맥에서 클래스 정의를 보면 예상치 못한 일이기 때문에 서서히 바람직하지 않다는 것을 천천히 깨닫게된다. 초기화 a __super 각 클래스 및 인스턴스에 대한 속성.

최근에 미국 인구 조사 데이터로 채워진 데이터베이스 테이블 주위에 SQLALCHEMY 모델을 선언적으로 정의하는 데 도움이되는 메타 클라스를 사용해야했습니다. http://census.ire.org/data/bulkdata.html

IRE가 제공합니다 데이터베이스 쉘 인구 조사 데이터 테이블의 경우, P012015, P012016, P012017 등의 인구 조사국의 명명 대회 후 정수 열을 생성합니다.

나는 a) model_instance.p012017 구문, b) 내가하고있는 일에 대해 상당히 명백하고 c) 모델에서 수십 개의 필드를 명시 적으로 정의 할 필요가 없으므로 sqlalchemy 's를 서브 클래스했습니다. DeclarativeMeta 열 범위를 통해 반복하고 열에 해당하는 모델 필드를 자동으로 작성합니다.

from sqlalchemy.ext.declarative.api import DeclarativeMeta

class CensusTableMeta(DeclarativeMeta):
    def __init__(cls, classname, bases, dict_):
        table = 'p012'
        for i in range(1, 49):
            fname = "%s%03d" % (table, i)
            dict_[fname] = Column(Integer)
            setattr(cls, fname, dict_[fname])

        super(CensusTableMeta, cls).__init__(classname, bases, dict_)

그런 다음 모델 정의 에이 메타 클래스를 사용하고 모델의 자동 열거 된 필드에 액세스 할 수 있습니다.

CensusTableBase = declarative_base(metaclass=CensusTableMeta)

class P12Tract(CensusTableBase):
    __tablename__ = 'ire_p12'

    geoid = Column(String(12), primary_key=True)

    @property
    def male_under_5(self):
        return self.p012003

    ...

설명 된 합법적 인 용도가있는 것 같습니다 여기 - 메타 클라스로 파이썬 문서를 다시 작성합니다.

이진 파서가 사용하기 쉽도록 한 번 사용해야했습니다. 와이어에 필드의 속성이있는 메시지 클래스를 정의합니다. 그들은 최종 와이어 형식을 구성하도록 선언 된 방식으로 주문해야했습니다. 주문한 네임 스페이스 딕을 사용하는 경우 메타 클래스로 수행 할 수 있습니다. 실제로, 그것은 중량체의 예에서 :

https://docs.python.org/3/reference/datamodel.html#metaclass-example

그러나 일반적으로 : 실제로 메타 클래스의 추가 복잡성이 필요한 경우 매우 신중하게 평가하십시오.

@dan gittik의 답은 멋지다

결국 예제는 많은 것들을 명확히 할 수 있고, 나는 그것을 Python 3으로 변경하고 몇 가지 설명을합니다.

class MetaMetaclass(type):
    def __new__(meta, name, bases, attrs):
        def __new__(meta, name, bases, attrs):
            cls = type.__new__(meta, name, bases, attrs)
            cls._label = 'Made in %s' % meta.__name__
            return cls

        attrs['__new__'] = __new__
        return type.__new__(meta, name, bases, attrs)

#China is metaclass and it's __new__ method would be changed by MetaMetaclass(metaclass)
class China(MetaMetaclass, metaclass=MetaMetaclass):
    __metaclass__ = MetaMetaclass

#Taiwan is metaclass and it's __new__ method would be changed by MetaMetaclass(metaclass)
class Taiwan(MetaMetaclass, metaclass=MetaMetaclass):
    __metaclass__ = MetaMetaclass

#A is a normal class and it's __new__ method would be changed by China(metaclass)
class A(metaclass=China):
    __metaclass__ = China

#B is a normal class and it's __new__ method would be changed by Taiwan(metaclass)
class B(metaclass=Taiwan):
    __metaclass__ = Taiwan


print(A._label)  # Made in China
print(B._label)  # Made in Taiwan

  • 모든 것이 객체이므로 클래스는 객체입니다
  • 클래스 객체는 metaclass에 의해 생성됩니다
  • 유형에서 상속 된 모든 클래스는 메타 클라스입니다
  • 메타 클라스는 클래스 생성을 제어 할 수 있습니다
  • 메타 클라스는 메타 클라스 생성도 제어 할 수 있습니다 (따라서 영원히 루프 할 수 있습니다)
  • 이것은 메타 프로 그라밍입니다 ... 실행 시간에 유형 시스템을 제어 할 수 있습니다.
  • 다시, 모든 것이 객체이며, 이것은 균일 한 시스템, 유형 유형 유형 및 유형의 인스턴스 유형입니다.

또 다른 사용 사례는 클래스 수준 속성을 수정하고 당면한 객체에만 영향을 미치는지 확인하는 경우입니다. 실제로, 이것은 메타 클라스 및 계급 인스턴스화의 단계를 "병합"한다는 것을 의미하므로 자신의 (고유 한) 종류의 클래스 사례 만 다루게됩니다.

나는 또한 (우려를 위해 유명한 그리고 다형성) 우리는 원했다 동적으로 정의합니다 property값을 반환 한 S (5 월) 수업 수준에서만 수행 할 수 있습니다, 메타 클라스 인스턴스화 후 및 계급 인스턴스화 전에.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top