メタクラスに関して混乱があります。
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)メタクラスの使用とは何ですか?
クラスがオブジェクトに対するものであるように、メタクラスはクラスに対するものです。これらはクラスのクラスです(したがって、「メタ」という表現)。
メタクラスは、通常、OOPの通常の制約の外で作業する場合に使用します。
2)メタクラスと継承の違い/類似点は何ですか?
メタクラスはオブジェクトのクラス階層の一部ではありませんが、基本クラスはそうです。したがって、オブジェクトがobj.some_method()
を実行すると、このメソッドのメタクラスは検索されませんが、クラスまたはオブジェクトの作成中にメタクラスが作成した可能性があります。
以下のこの例では、メタクラスMetaCar
は、乱数に基づいてオブジェクトにdefect
属性を与えます。 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)どこでメタクラスまたは継承を使用する必要がありますか?
この回答とコメントで述べたように、OOPを行うときはほとんど常に継承を使用します。メタクラスはこれらの制約の外で動作するためのものであり(例を参照)、ほとんどの場合必要ではありませんが、非常に高度で、非常に動的プログラムフローを実現できます。これは、彼らの強さと危険の両方です。