Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

This question already has an answer here:

I have some confusion regarding meta-classes,

with 'Inheritance'

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

with 'Metaclass'

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

As above example is not useful as practically but just for understanding,

I have some questions Like,

1) what is use of metaclass and when to use it?

2) what is difference/similarity between metaclass and inheritance?

3) where should one use metaclass or inheritance?

share|improve this question
1  
Rule of thumb: If you can do it without metaclasses, don't use metaclasses. –  user2357112 Jul 23 '13 at 4:23
3  
If you have to ask whether or not you need a metaclass, you don't need a metaclass. –  Ignacio Vazquez-Abrams Jul 23 '13 at 4:26
add comment

marked as duplicate by Blckknght, Etaoin, Sean Vieira, mishik, Michel Keijzers Jul 23 '13 at 7:40

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1 Answer

up vote 3 down vote accepted

1) what is use of metaclass and when to use it?

Metaclasses are to classes as classes are to objects. They are classes for classes (hence the expression "meta").

Metaclasses are typically for when you want to work outside of the normal constraints of OOP.

2) what is difference/similarity between metaclass and inheritance?

A metaclass is not part of an object's class hierarchy whereas base classes are. So when an object does "obj.some_method()" it will not search the metaclass for this method however the metaclass may have created it during the class' or object's creation.

In this example below, the metaclass meta_car gives objects a "defect" attribute based on a random number. The "defect" attribute is not defined in any of the objects' base classes or the class itself. This, however, could have been achieved using classes only.

However (unlike classes), this metaclass also re-routes object creation; in the some_cars list, all the Toyotas are created using the Car class. The metaclass detects that a Car __init__ contains a make argument that matches a pre-existing class by that name and so returns a object of that class instead.

Additionally, you'll also note that in the some_cars list, a Car __init__ is called with make="GM". A GM class has not been defined at this point in the program's evaluation. The metaclass detects that a class doesn't exist by that name in the make argument, so it creates one and updates the global namespace (so it doesn't need to use the return mechanism). It then creates the object using the newly defined class and returns it.

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) where should one use metaclass or inheritance?

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.

share|improve this answer
    
Thanks dilbert .. gr8 explanation This difference can be noted from : with metaclass, issubclass(Car,AttributeInitType) returns -> False –  Nikhil Rupanawar Jul 23 '13 at 15:55
1  
That's no worries. I don't know why this was marked as duplicate; the other thread didn't really say WHY nor give a compare/contrast to ordinary OOP practices. –  dilbert Jul 23 '13 at 21:36
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.