oop - Quels sont les métaclasses en Python

Mots clés : pythonoopmetaclasspython-classpython-datamodelpython

meilleur 5 Réponses oop - Quels sont les métaclasses en Python

vote vote

93

>>> class ObjectCreator(object): ...       pass ...  >>> my_object = ObjectCreator() >>> print(my_object) <__main__.ObjectCreator object at 0x8974f2c> 
>>> class ObjectCreator(object): ...       pass ... 
>>> print(ObjectCreator) # you can print a class because it's an object <class '__main__.ObjectCreator'> >>> def echo(o): ...       print(o) ... >>> echo(ObjectCreator) # you can pass a class as a parameter <class '__main__.ObjectCreator'> >>> print(hasattr(ObjectCreator, 'new_attribute')) False >>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class >>> print(hasattr(ObjectCreator, 'new_attribute')) True >>> print(ObjectCreator.new_attribute) foo >>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable >>> print(ObjectCreatorMirror.new_attribute) foo >>> print(ObjectCreatorMirror()) <__main__.ObjectCreator object at 0x8997b4c> 
>>> def choose_class(name): ...     if name == 'foo': ...         class Foo(object): ...             pass ...         return Foo # return the class, not an instance ...     else: ...         class Bar(object): ...             pass ...         return Bar ... >>> MyClass = choose_class('foo') >>> print(MyClass) # the function returns a class, not an instance <class '__main__.Foo'> >>> print(MyClass()) # you can create an object from this class <__main__.Foo object at 0x89c6d4c> 
>>> print(type(1)) <type 'int'> >>> print(type("1")) <type 'str'> >>> print(type(ObjectCreator)) <type 'type'> >>> print(type(ObjectCreator())) <class '__main__.ObjectCreator'> 
type(name, bases, attrs) 
>>> class MyShinyClass(object): ...       pass 
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object >>> print(MyShinyClass) <class '__main__.MyShinyClass'> >>> print(MyShinyClass()) # create an instance with the class <__main__.MyShinyClass object at 0x8997cec> 
>>> class Foo(object): ...       bar = True 
>>> Foo = type('Foo', (), {'bar':True}) 
>>> print(Foo) <class '__main__.Foo'> >>> print(Foo.bar) True >>> f = Foo() >>> print(f) <__main__.Foo object at 0x8a9b84c> >>> print(f.bar) True 
>>>   class FooChild(Foo): ...         pass 
>>> FooChild = type('FooChild', (Foo,), {}) >>> print(FooChild) <class '__main__.FooChild'> >>> print(FooChild.bar) # bar is inherited from Foo True 
>>> def echo_bar(self): ...       print(self.bar) ... >>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) >>> hasattr(Foo, 'echo_bar') False >>> hasattr(FooChild, 'echo_bar') True >>> my_foo = FooChild() >>> my_foo.echo_bar() True 
>>> def echo_bar_more(self): ...       print('yet another method') ... >>> FooChild.echo_bar_more = echo_bar_more >>> hasattr(FooChild, 'echo_bar_more') True 
MyClass = MetaClass() my_object = MyClass() 
MyClass = type('MyClass', (), {}) 
>>> age = 35 >>> age.__class__ <type 'int'> >>> name = 'bob' >>> name.__class__ <type 'str'> >>> def foo(): pass >>> foo.__class__ <type 'function'> >>> class Bar(object): pass >>> b = Bar() >>> b.__class__ <class '__main__.Bar'> 
>>> age.__class__.__class__ <type 'type'> >>> name.__class__.__class__ <type 'type'> >>> foo.__class__.__class__ <type 'type'> >>> b.__class__.__class__ <type 'type'> 
class Foo(object):     __metaclass__ = something...     [...] 
class Foo(Bar):     pass 
class Foo(object, metaclass=something):     ... 
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):     ... 
# the metaclass will automatically get passed the same argument # that you usually pass to `type` def upper_attr(future_class_name, future_class_parents, future_class_attrs):     """       Return a class object, with the list of its attribute turned       into uppercase.     """     # pick up any attribute that doesn't start with '__' and uppercase it     uppercase_attrs = {         attr if attr.startswith("__") else attr.upper(): v         for attr, v in future_class_attrs.items()     }      # let `type` do the class creation     return type(future_class_name, future_class_parents, uppercase_attrs)  __metaclass__ = upper_attr # this will affect all classes in the module  class Foo(): # global __metaclass__ won't work with "object" though     # but we can define __metaclass__ here instead to affect only this class     # and this will work with "object" children     bar = 'bip' 
>>> hasattr(Foo, 'bar') False >>> hasattr(Foo, 'BAR') True >>> Foo.BAR 'bip' 
# remember that `type` is actually a class like `str` and `int` # so you can inherit from it class UpperAttrMetaclass(type):     # __new__ is the method called before __init__     # it's the method that creates the object and returns it     # while __init__ just initializes the object passed as parameter     # you rarely use __new__, except when you want to control how the object     # is created.     # here the created object is the class, and we want to customize it     # so we override __new__     # you can do some stuff in __init__ too if you wish     # some advanced use involves overriding __call__ as well, but we won't     # see this     def __new__(upperattr_metaclass, future_class_name,                 future_class_parents, future_class_attrs):         uppercase_attrs = {             attr if attr.startswith("__") else attr.upper(): v             for attr, v in future_class_attrs.items()         }         return type(future_class_name, future_class_parents, uppercase_attrs) 
class UpperAttrMetaclass(type):     def __new__(cls, clsname, bases, attrs):         uppercase_attrs = {             attr if attr.startswith("__") else attr.upper(): v             for attr, v in attrs.items()         }         return type(clsname, bases, uppercase_attrs) 
class UpperAttrMetaclass(type):     def __new__(cls, clsname, bases, attrs):         uppercase_attrs = {             attr if attr.startswith("__") else attr.upper(): v             for attr, v in attrs.items()         }         return type.__new__(cls, clsname, bases, uppercase_attrs) 
class UpperAttrMetaclass(type):     def __new__(cls, clsname, bases, attrs):         uppercase_attrs = {             attr if attr.startswith("__") else attr.upper(): v             for attr, v in attrs.items()         }         return super(UpperAttrMetaclass, cls).__new__(             cls, clsname, bases, uppercase_attrs) 
class Foo(object, metaclass=MyMetaclass, kwarg1=value1):     ... 
class MyMetaclass(type):     def __new__(cls, clsname, bases, dct, kwargs1=default):         ... 
class Person(models.Model):     name = models.CharField(max_length=30)     age = models.IntegerField() 
person = Person(name='bob', age='35') print(person.age) 
>>> class Foo(object): pass >>> id(Foo) 142630324 
vote vote

82

def make_hook(f):     """Decorator to turn 'foo' method into '__foo__'"""     f.is_hook = 1     return f  class MyType(type):     def __new__(mcls, name, bases, attrs):          if name.startswith('None'):             return None          # Go over attributes and see if they should be renamed.         newattrs = {}         for attrname, attrvalue in attrs.iteritems():             if getattr(attrvalue, 'is_hook', 0):                 newattrs['__%s__' % attrname] = attrvalue             else:                 newattrs[attrname] = attrvalue          return super(MyType, mcls).__new__(mcls, name, bases, newattrs)      def __init__(self, name, bases, attrs):         super(MyType, self).__init__(name, bases, attrs)          # classregistry.register(self, self.interfaces)         print "Would register class %s now." % self      def __add__(self, other):         class AutoClass(self, other):             pass         return AutoClass         # Alternatively, to autogenerate the classname as well as the class:         # return type(self.__name__ + other.__name__, (self, other), {})      def unregister(self):         # classregistry.unregister(self)         print "Would unregister class %s now." % self  class MyObject:     __metaclass__ = MyType   class NoneSample(MyObject):     pass  # Will print "NoneType None" print type(NoneSample), repr(NoneSample)  class Example(MyObject):     def __init__(self, value):         self.value = value     @make_hook     def add(self, other):         return self.__class__(self.value + other.value)  # Will unregister the class Example.unregister()  inst = Example(10) # Will fail with an AttributeError #inst.unregister()  print inst + inst class Sibling(MyObject):     pass  ExampleSibling = Example + Sibling # ExampleSibling is now a subclass of both Example and Sibling (with no # content of its own) although it will believe it's called 'AutoClass' print ExampleSibling print ExampleSibling.__mro__ 
vote vote

73

class type(object)   |  type(object) -> the object's type   |  type(name, bases, dict) -> a new type 
class ThisIsTheName(Bases, Are, Here):     All_the_code_here     def doesIs(create, a):         dict 
def test_metaclass(name, bases, dict):     print 'The Class Name is', name     print 'The Class Bases are', bases     print 'The dict has', len(dict), 'elems, the keys are', dict.keys()      return "yellow"  class TestName(object, None, int, 1):     __metaclass__ = test_metaclass     foo = 1     def baz(self, arr):         pass  print 'TestName = ', repr(TestName)  # output =>  The Class Name is TestName The Class Bases are (<type 'object'>, None, <type 'int'>, 1) The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__'] TestName =  'yellow' 
def init_attributes(name, bases, dict):     if 'attributes' in dict:         for attr in dict['attributes']:             dict[attr] = None      return type(name, bases, dict)  class Initialised(object):     __metaclass__ = init_attributes     attributes = ['foo', 'bar', 'baz']  print 'foo =>', Initialised.foo # output=> foo => None 
class MetaSingleton(type):     instance = None     def __call__(cls, *args, **kw):         if cls.instance is None:             cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)         return cls.instance  class Foo(object):     __metaclass__ = MetaSingleton  a = Foo() b = Foo() assert a is b 
vote vote

69

class MyMeta(type):      counter = 0      def __init__(cls, name, bases, dic):         type.__init__(cls, name, bases, dic)         cls._order = MyMeta.counter         MyMeta.counter += 1  class MyType(object):              # Python 2     __metaclass__ = MyMeta  class MyType(metaclass=MyMeta):    # Python 3     pass 
vote vote

50

class Person(models.Model):     first_name = models.CharField(max_length=30)     last_name = models.CharField(max_length=30) 

Questions similaires