programing tip

클래스가 서브 클래 싱 될 때 코드를 실행하는 방법은 무엇입니까?

itbloger 2020. 9. 2. 14:55
반응형

클래스가 서브 클래 싱 될 때 코드를 실행하는 방법은 무엇입니까? [복제]


이 질문에 이미 답변이 있습니다.

내 클래스가 서브 클래 싱 될 때 코드를 트리거하는 방법이 있습니까?

class SuperClass:
    def triggered_routine(subclass):
        print("was subclassed by " + subclass.__name__)

magically_register_triggered_routine()

print("foo")

class SubClass0(SuperClass):
    pass

print("bar")

class SubClass1(SuperClass):
    print("test")

출력해야 함

foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1

클래스 (기본적으로)는 type. 클래스의 인스턴스가있는 것처럼 Foo의해 생성 foo = Foo(...)의 인스턴스 type(즉, 클래스)에 의해 생성된다 myclass = type(name, bases, clsdict).

클래스 생성 순간에 특별한 일이 일어나기를 원한다면, 클래스를 생성하는 것을 수정해야합니다 type. 이를 수행하는 방법은 하위 클래스, type즉 메타 클래스를 정의하는 것 입니다.

메타 클래스는 클래스와 인스턴스에 대한 클래스입니다.

Python2에서는 다음을 사용하여 클래스의 메타 클래스를 정의합니다.

class SuperClass:
    __metaclass__ = Watcher

Watcher의 하위 클래스는 어디에 있습니까 type?

Python3에서는 구문이 다음과 같이 변경되었습니다.

class SuperClass(metaclass=Watcher)

둘 다 다음과 같습니다.

Superclass = Watcher(name, bases, clsdict)

여기서,이 경우에는 name문자열과 동일 'Superclass'하고, bases튜플이다 (object, ). clsdict클래스 정의의 본문에 정의 된 클래스 속성의 사전입니다.

에 유사성을합니다 myclass = type(name, bases, clsdict).

따라서 __init__인스턴스 생성 순간에 이벤트를 제어 하기 위해 클래스를 사용하는 것처럼 메타 클래스의 __init__다음을 사용하여 클래스 생성 순간에 이벤트를 제어 할 수 있습니다 .


class Watcher(type):
    def __init__(cls, name, bases, clsdict):
        if len(cls.mro()) > 2:
            print("was subclassed by " + name)
        super(Watcher, cls).__init__(name, bases, clsdict)

class SuperClass:
    __metaclass__ = Watcher


print("foo")

class SubClass0(SuperClass):
  pass

print("bar")

class SubClass1(SuperClass):
  print("test")

인쇄물

foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1

편집 : 내 이전 게시물이 실제로 작동하지 않았습니다. 에서 서브 클래 싱 classmethod이 예상대로 작동하지 않습니다.

First, we would like to have some way to tell the metaclass that this particular method is supposed to have the special called on subclass behavior, we'll just set an attribute on the function we'd like to call. As a convenience, we'll even turn the function into a classmethod so that the real baseclass it was found in can be discovered, too. We'll return the classmethod so that it can be used as a decorator, which is most convenient.

import types
import inspect

def subclass_hook(func):
    func.is_subclass_hook = True
    return classmethod(func)

We're also going to want a convenient way to see that the subclass_hook decorator was used. We know that classmethod has been used, so we'll check for that, and only then look for the is_subclass_hook attribute.

def test_subclass_hook(thing):
    x = (isinstance(thing, types.MethodType) and
         getattr(thing.im_func, 'is_subclass_hook', False))
    return x

Finally, we need a metaclass that acts on the information: For most cases, the most interesting thing to do here is just check each of the supplied bases for hooks. In that way, super works in the least surprising way.

class MyMetaclass(type):
    def __init__(cls, name, bases, attrs):
        super(MyMetaclass, cls).__init__(name, bases, attrs)

        for base in bases:
            if base is object:
                continue
            for name, hook in inspect.getmembers(base, test_subclass_hook):
                hook(cls)

and that should do it.

>>> class SuperClass:
...     __metaclass__ = MyMetaclass
...     @subclass_hook
...     def triggered_routine(cls, subclass):
...         print(cls.__name__ + " was subclassed by " + subclass.__name__)

>>> class SubClass0(SuperClass):
...     pass
SuperClass was subclassed by SubClass0

>>> class SubClass1(SuperClass):
...     print("test")
test
SuperClass was subclassed by SubClass1

참고URL : https://stackoverflow.com/questions/18126552/how-to-run-code-when-a-class-is-subclassed

반응형