Development Tip

Python의 메타 클래스 및 상속 이해

yourdevel 2020. 12. 31. 23:02
반응형

Python의 메타 클래스 및 상속 이해


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

메타 클래스에 대해 약간의 혼란이 있습니다.

상속으로

class AttributeInitType(object):

   def __init__(self,**kwargs):
       for name, value in kwargs.items():
          setattr(self, name, value)

class Car(AttributeInitType):

    def __init__(self,**kwargs):
        super(Car, self).__init__(**kwargs)
    @property
    def description(self):
       return "%s %s %s %s" % (self.color, self.year, self.make, self.model)

c = Car(make='Toyota', model='Prius', year=2005, color='green')
print c.description

메타 클래스로

class AttributeInitType(type):
   def __call__(self, *args, **kwargs):
       obj = type.__call__(self, *args)
       for name, value in kwargs.items():
           setattr(obj, name, value)
       return obj

class Car(object):
   __metaclass__ = AttributeInitType

   @property
   def description(self):
       return "%s %s %s %s" % (self.color, self.year, self.make, self.model)


c = Car(make='Toyota', model='Prius', year=2005,color='blue')
print c.description

위의 예는 실제적으로 유용하지는 않지만 이해를 위해

몇 가지 질문이 있습니다.

  1. 메타 클래스와 상속의 차이점 / 유사성은 무엇입니까?

  2. 메타 클래스 또는 상속을 어디에 사용해야합니까?


1) 메타 클래스의 사용은 무엇이며 언제 사용합니까?

메타 클래스는 클래스와 객체에 대한 클래스입니다. 클래스에 대한 클래스입니다 (따라서 "메타"라는 표현).

메타 클래스는 일반적으로 OOP의 일반적인 제약을 벗어나 작업하려는 경우에 사용됩니다.

2) 메타 클래스와 상속의 차이점 / 유사성은 무엇입니까?

메타 클래스는 객체의 클래스 계층 구조의 일부가 아니지만 기본 클래스는 있습니다. 따라서 객체가 수행 obj.some_method()할 때이 메서드에 대한 메타 클래스를 검색 하지 않지만 메타 클래스가 클래스 또는 객체 생성 중에 생성했을 수 있습니다.

아래의이 예에서 메타 클래스 MetaCardefect난수를 기반으로하는 속성을 객체에 제공합니다 . defect속성은 객체의 기본 클래스 나 클래스 자체의에 정의되어 있지 않습니다. 그러나 이것은 클래스만을 사용하여 달성 할 수 있습니다.

그러나 (클래스와 달리)이 메타 클래스는 객체 생성 경로도 다시 지정합니다. some_cars목록, 모든 토요타는 사용하여 만든 Car클래스를. 메타 클래스는 해당 이름으로 기존 클래스와 일치 Car.__init__하는 make인수 포함 된 것을 감지하고 대신 해당 클래스의 객체를 반환합니다.

또한, 당신은 또한에 참고하겠습니다 some_cars목록, Car.__init__호출됩니다 make="GM". GM클래스는 프로그램의 평가의이 시점에서 정의되지 않았습니다. 메타 클래스는 make 인수에서 해당 이름으로 클래스가 존재하지 않음을 감지하여 하나를 만들고 전역 네임 스페이스를 업데이트합니다 (반환 메커니즘을 사용할 필요가 없음). 그런 다음 새로 정의 된 클래스를 사용하여 객체를 생성하고 반환합니다.

import random

class CarBase(object):
    pass

class MetaCar(type):
    car_brands = {}
    def __init__(cls, cls_name, cls_bases, cls_dict):
        super(MetaCar, cls).__init__(cls_name, cls_bases, cls_dict)
        if(not CarBase in cls_bases):
            MetaCar.car_brands[cls_name] = cls

    def __call__(self, *args, **kwargs):
        make = kwargs.get("make", "")
        if(MetaCar.car_brands.has_key(make) and not (self is MetaCar.car_brands[make])):
            obj = MetaCar.car_brands[make].__call__(*args, **kwargs)
            if(make == "Toyota"):
                if(random.randint(0, 100) < 2):
                    obj.defect = "sticky accelerator pedal"
            elif(make == "GM"):
                if(random.randint(0, 100) < 20):
                    obj.defect = "shithouse"
            elif(make == "Great Wall"):
                if(random.randint(0, 100) < 101):
                    obj.defect = "cancer"
        else:
            obj = None
            if(not MetaCar.car_brands.has_key(self.__name__)):
                new_class = MetaCar(make, (GenericCar,), {})
                globals()[make] = new_class
                obj = new_class(*args, **kwargs)
            else:
                obj = super(MetaCar, self).__call__(*args, **kwargs)
        return obj

class Car(CarBase):
    __metaclass__ = MetaCar

    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def __repr__(self):
        return "<%s>" % self.description

    @property
    def description(self):
        return "%s %s %s %s" % (self.color, self.year, self.make, self.model)

class GenericCar(Car):
    def __init__(self, **kwargs):
        kwargs["make"] = self.__class__.__name__
        super(GenericCar, self).__init__(**kwargs)

class Toyota(GenericCar):
    pass

colours = \
[
    "blue",
    "green",
    "red",
    "yellow",
    "orange",
    "purple",
    "silver",
    "black",
    "white"
]

def rand_colour():
    return colours[random.randint(0, len(colours) - 1)]

some_cars = \
[
    Car(make="Toyota", model="Prius", year=2005, color=rand_colour()),
    Car(make="Toyota", model="Camry", year=2007, color=rand_colour()),
    Car(make="Toyota", model="Camry Hybrid", year=2013, color=rand_colour()),
    Car(make="Toyota", model="Land Cruiser", year=2009, color=rand_colour()),
    Car(make="Toyota", model="FJ Cruiser", year=2012, color=rand_colour()),
    Car(make="Toyota", model="Corolla", year=2010, color=rand_colour()),
    Car(make="Toyota", model="Hiace", year=2006, color=rand_colour()),
    Car(make="Toyota", model="Townace", year=2003, color=rand_colour()),
    Car(make="Toyota", model="Aurion", year=2008, color=rand_colour()),
    Car(make="Toyota", model="Supra", year=2004, color=rand_colour()),
    Car(make="Toyota", model="86", year=2013, color=rand_colour()),
    Car(make="GM", model="Camaro", year=2008, color=rand_colour())
]

dodgy_vehicles = filter(lambda x: hasattr(x, "defect"), some_cars)
print dodgy_vehicles

3) 메타 클래스 나 상속은 어디에서 사용해야합니까?

As mentioned in this answer and in the comments, almost always use inheritance when doing OOP. Metaclasses are for working outside those constraints (refer to example) and is almost always not necessary however some very advanced and extremely dynamic program flow can be achieved with them. This is both their strength and their danger.

ReferenceURL : https://stackoverflow.com/questions/17801344/understanding-metaclass-and-inheritance-in-python

반응형