Programing

기본 클래스에서 파생 클래스를 동적으로 만드는 방법

lottogame 2020. 9. 23. 08:04
반응형

기본 클래스에서 파생 클래스를 동적으로 만드는 방법


예를 들어 다음과 같은 기본 클래스가 있습니다.

class BaseClass(object):
    def __init__(self, classtype):
        self._type = classtype

이 클래스에서 몇 가지 다른 클래스를 파생합니다.

class TestClass(BaseClass):
    def __init__(self):
        super(TestClass, self).__init__('Test')

class SpecialClass(BaseClass):
    def __init__(self):
        super(TestClass, self).__init__('Special')

다음과 같이 새 클래스를 현재 범위에 넣는 함수 호출을 통해 이러한 클래스를 동적으로 생성하는 멋지고 비단뱀적인 방법이 있습니까?

foo(BaseClass, "My")
a = MyClass()
...

왜 이것이 필요한지에 대한 의견과 질문이있을 것입니다. 파생 된 클래스는 모두 동일한 내부 구조를 가지지 만 생성자는 이전에 정의되지 않은 여러 인수를 사용합니다. 따라서, 예를 들어, MyClass키워드를 취 a클래스의 생성자는 동안 TestClass소요 b하고 c.

inst1 = MyClass(a=4)
inst2 = MyClass(a=5)
inst3 = TestClass(b=False, c = "test")

그러나 그들은 클래스의 유형을 다음과 같은 입력 인수로 사용해서는 안됩니다.

inst1 = BaseClass(classtype = "My", a=4)

이 작업을 수행했지만 다른 방식, 즉 동적으로 생성 된 클래스 개체를 선호합니다.


이 코드를 사용하면 동적 이름과 매개 변수 이름으로 새 클래스를 만들 수 있습니다. 의 매개 변수 확인은 __init__알 수없는 매개 변수를 허용하지 않습니다. 유형과 같은 다른 확인이 필요하거나 필수 항목 인 경우 여기에 논리를 추가하면됩니다.

class BaseClass(object):
    def __init__(self, classtype):
        self._type = classtype

def ClassFactory(name, argnames, BaseClass=BaseClass):
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
            # here, the argnames variable is the one passed to the
            # ClassFactory call
            if key not in argnames:
                raise TypeError("Argument %s not valid for %s" 
                    % (key, self.__class__.__name__))
            setattr(self, key, value)
        BaseClass.__init__(self, name[:-len("Class")])
    newclass = type(name, (BaseClass,),{"__init__": __init__})
    return newclass

그리고 이것은 다음과 같이 작동합니다.

>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass

지금 - 당신이 명명 범위에 동적 이름을 삽입을 요구하고 볼 것을 당신도 변수 코딩시에 알려진 이름, 또는 데이터가 - - 파이썬에서 좋은 연습으로 간주되지 않으며, 런타임에서 배운 이름은 "더 있습니다 데이터 "보다"변수 "-

따라서 클래스를 사전에 추가하고 거기에서 사용할 수 있습니다.

name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)

And if your design absolutely needs the names to come in scope, just do the same, but use the dictionary returned by the globals() call instead of an arbitrary dictionary:

name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)

(It indeed would be possible for the class factory function to insert the name dynamically on the global scope of the caller - but that is even worse practice, and is not compatible across Python implementations. The way to do that would be to get the caller's execution frame, through sys._getframe(1) and setting the class name in the frame's global dictionary in its f_globals attribute).

update, tl;dr: This answer had become popular, still its very specific to the question body. The general answer on how to "dynamically create derived classes from a base class" in Python is a simple call to type passing the new class name, a tuple with the baseclass(es) and the __dict__ body for the new class -like this:

>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})

update
Anyone needing this should also check the dill project - it claims to be able to pickle and unpickle classes just like pickle does to ordinary objects, and had lived to it in some of my tests.


type() is the function that creates classes (and in particular sub-classes):

def set_x(self, value):
    self.x = value

SubClass = type('SubClass', (BaseClass,), {'set_x': set_x})
# (More methods can be put in SubClass, including __init__().)

obj = SubClass()
obj.set_x(42)
print obj.x  # Prints 42
print isinstance(obj, BaseClass)  # True

참고URL : https://stackoverflow.com/questions/15247075/how-can-i-dynamically-create-derived-classes-from-a-base-class

반응형