Понимание метакласса и наследования в 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. В чем разница / сходство между метаклассом и наследованием?

  3. Где следует использовать мета-класс или наследование?

One Solution collect form web for “Понимание метакласса и наследования в Python”

1) что такое использование метакласса и когда его использовать?

Метаклассы относятся к классам, поскольку классы относятся к объектам. Это классы для классов (отсюда и выражение «мета»).

Метаклассы обычно используются, когда вы хотите работать вне обычных ограничений ООП.

2) какова разница / сходство между метаклассом и наследованием?

Метакласс не является частью иерархии классов объекта, тогда как базовые классы. Поэтому, когда объект выполняет «obj.some_method ()», он не будет искать метакласс для этого метода, однако метакласс мог создать его во время создания класса или объекта.

В этом примере ниже метакласс meta_car предоставляет объектам атрибут «дефект», основанный на случайном числе. Атрибут «дефект» не определен ни в одном из базовых классов объектов или самого класса. Это, однако, могло быть достигнуто только с использованием классов.

Однако (в отличие от классов) этот метакласс также перенаправляет создание объекта; в списке some_cars все Toyotas создаются с использованием класса Car. Метакласс определяет, что автомобиль __init__ содержит аргумент make, который соответствует ранее существующему классу, и таким образом возвращает объект этого класса.

Кроме того, вы также заметите, что в списке some_cars вызывается автомобиль __init__ с make = "GM". На данный момент в оценке программы класс GM не определен. Метакласс определяет, что класс не существует этим именем в аргументе make, поэтому он создает один и обновляет глобальное пространство имен (поэтому ему не нужно использовать механизм возврата). Затем он создает объект, используя новый класс и возвращает его.

 import random class CarBase(object): pass class meta_car(type): car_brands = {} def __init__(cls, cls_name, cls_bases, cls_dict): super(meta_car, cls).__init__(cls_name, cls_bases, cls_dict) if(not CarBase in cls_bases): meta_car.car_brands[cls_name] = cls def __call__(self, *args, **kwargs): make = kwargs.get("make", "") if(meta_car.car_brands.has_key(make) and not (self is meta_car.car_brands[make])): obj = meta_car.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 meta_car.car_brands.has_key(self.__name__)): new_class = meta_car(make, (GenericCar,), {}) globals()[make] = new_class obj = new_class(*args, **kwargs) else: obj = super(meta_car, self).__call__(*args, **kwargs) return obj class Car(CarBase): __metaclass__ = meta_car 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) где следует использовать метакласс или наследование?

Как упоминалось в этом ответе и в комментариях, почти всегда используют наследование при выполнении ООП. Метаклассы предназначены для работы вне этих ограничений (см. Пример) и почти всегда не нужны, однако с ними может быть достигнут очень продвинутый и чрезвычайно динамичный поток программ. Это и их сила, и их опасность .

  • Вызвать метод родительского класса из дочернего класса в Python?
  • Python: наследуйте суперкласс __init__
  • Как вызвать метод __init__ базового класса из дочернего класса?
  • Как расширить класс класса Python
  • Как `super` взаимодействует с атрибутом` __mro__` класса в множественном наследовании?
  • Наследование и внутренние классы в Python?
  • Дескрипторы и наследование Python
  • Словарь доступа Python: производные классы базового класса в том же месте памяти
  •  
    Interesting Posts for Van-Lav

    Как использовать python mysqldb для вставки сразу нескольких строк

    Python – Избегать прохождения ссылки на регистратор между функциями?

    Сортировка Python по максимуму первого элемента, затем min второго элемента

    Параметрирование Py.Test на основе параметризованного прибора

    Можно ли запускать команды в IPython с помощью отладки?

    Открытие процесса с помощью Popen и получение PID

    Мониторинг параллелизма (обмен объектами между процессами) в Python

    Составление списка с условием

    Как сжимать с помощью 7zip вместо zip, смена кода

    Django (?) Очень медленный с большими наборами данных после выполнения некоторого профилирования питона

    Использование Numpy для создания финансового ценового стола Yahoo

    Переопределение имени таблицы в Flask-Alchemy

    TypeError: объект «NoneType» не повторяется в Python

    Проблема с запросом Teradata в Python / Pyodbc

    Выполнение HTTP-запросов через модуль запросов Python не работает через прокси-сервер, где работает curl? Зачем?

    Python - лучший язык программирования в мире.