In Python metaclass explained

Original link: http://www.cnblogs.com/james1207/p/3283646.html

 

Classes as objects

First of all, before you know metaclass, you need to realize that under python in class. python in the class of strange characteristics borrowed smalltalk language. Most languages, classes end only is the code used to describe how to create an object. In a way, python in the class is the same.

 

  >>> class ObjectCreator(object):
  ...       pass
  ... 

  >>> my_object = ObjectCreator()
  >>> print my_object
  <__main__.ObjectCreator object at 0x8974f2c>

However, classes or objects python in the same time, yes, read that right, are objects, once you use the keyword class, python will perform and produce an object (object), command

 

 

  >>> class ObjectCreator(object):
  ...       pass
  ... 

We will create a name for the object ObjectCreator in memory.

 

This object (class) have the ability to create objects (instances), which is why the class is called .

Because it is an object, so it should have some of the characteristics of the object:

  • You can assign it to a variable
  • You can copy it
  • You can add attributes to it
  • You can think of it as a parameter to a function

E.g:

 

  >>> 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>

 

Creating classes dynamically

Since classes are objects, so you may want to dynamically create their objects.

 

First, you can use the keyword in a function to create it:

 

  >>> 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>

However, this is not very dynamic, because you still have to write the whole entire function. Because classes are objects, they may be generated. When you use the keyword class, python automatically create these objects, so just like the python in most things, we are also able to manually generate.

 

Remember the function type it? One that can tell you the object type of function:

 

>>> print type(1)
<type 'int'>
>>> print type("1")
<type 'str'>
>>> print type(ObjectCreator)
<type 'type'>
>>> print type(ObjectCreator())
<class '__main__.ObjectCreator'>

Surprisingly a completely different type also has the ability to dynamically create a function that we need. the class type may be described as a parameter, and generates a class. type works like this:

 

 

  type(name of the class, 
       tuple of the parent class (for inheritance, can be empty), 
       dictionary containing attributes names and values)

E.g:

 

 

>>> class MyShinyClass(object):
...       pass

You can be created manually using the following ways:

 

 

  >>> 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>

As can be seen, we MyShinyClass as the class of the name, function very obvious, just some different parameters, there is no reason to complicate with the original author's words: They can be different, but there is no reason to complicate things.

 

 

What are metaclasses (finally)

To explain metaclasses is finally open, and I waited a long time, Metaclasses are the 'stuff' that creates classes. This is the authors say, that it is possible to create a kind of stuff, you define a class to create objects is it? But in python We see class as an object, so, metaclasses is to create objects. They are the class of the class, so you can imagine them:

 

 

  MyClass = MetaClass()
  MyObject = MyClass()

You can see that type allows you to do the same thing:

 

 

  MyClass = type('MyClass', (), {})

This is because the function type is in fact a metaclass, in python, type is used to create a metaclass category in the background. Now you know why why it is used in lower case rather than capital Type?
well, you are not thought str / int and so it functions, str used to create a string object, int to create an integer object type that just create a class object class only. You can see by looking at __class__ property. Everything is an object, so the object can be created by a function:

 

 

  >>> 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'>

Who created the creator of the class is it?

 

 

  >>> age.__class__.__class__
  <type 'type'>
  >>> name.__class__.__class__
  <type 'type'>
  >>> foo.__class__.__class__
  <type 'type'>
  >>> b.__class__.__class__
  <type 'type'>

This time should be slightly understand some of it, of course, we can also create our own metaclass.

 

 

The __metaclass__ attribute

You can add __metaclass__ properties in the class is created when:

 

 

class Foo(object):
  __metaclass__ = something...
  [...]

python metaclass will be used to create a class Foo, be careful Oh, you write a class Foo (object), but Foo has not been created in memory, python will look in your class __metaclass__ If found to use it to create, If none is found, it will use the type to create a class.

 

Elaborate Well, when you define a class:

 

class Foo(object):
   pass

python will first look in the class definition has no __metaclass__ property, did not find the parent, the module level did not go looking for, if it is not found, the last Shazhao type.

 

Well, the last question is, what do we put some stuff in __metaclass__ in it?

 

Custom metaclasses

The main purpose of a metaclass is automatic to change it when the class is created, read a little bend. In general, when you write some APIs, but these APIs to meet the current context, you can consider using metaclass. Imagine if your module class in their properties need to be written in lower case, we can try moudle level metaclass, this time, all classes in the module are created by metaclass, we have to do is tell metaclass all property converted to lowercase. Fortunately, we do not have the __metaclass__ defined as a class:

 

 

# 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_attr):
  """
    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_attr = {}
  for name, val in future_class_attr.items():
      if not name.startswith('__'):
          uppercase_attr[name.upper()] = val
      else:
          uppercase_attr[name] = val

  # let `type` do the class creation
  return type(future_class_name, future_class_parents, uppercase_attr)

__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'

print hasattr(Foo, 'bar')
# Out: False
print hasattr(Foo, 'BAR')
# Out: True

f = Foo()
print f.BAR
# Out: 'bip'

Now, we use a class to implement metaclass:

 

 

# 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_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type(future_class_name, future_class_parents, uppercase_attr)

But this is not a true OOP. We can call direct type of __new__:

 

 

class UpperAttrMetaclass(type): 

    def __new__(upperattr_metaclass, future_class_name, 
                future_class_parents, future_class_attr):

        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        # reuse the type.__new__ method
        # this is basic OOP, nothing magic in there
        return type.__new__(upperattr_metaclass, future_class_name, 
                            future_class_parents, uppercase_attr)

You may have noticed additional parameters upperattr_metaclass, that there is nothing special: a method often current instance as the first argument, just like the usual methods of self. Of course, I used the long name here seen as a clearer explanation, like self, as all parameters are customary name, so it is a product of metaclass:

 

 

class UpperAttrMetaclass(type): 

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return type.__new__(cls, clsname, bases, uppercase_attr)

We can use super to make the code cleaner:

 

 

class UpperAttrMetaclass(type): 

    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

So much, metaclass is that simple. In fact, the reason for using metaclass code is not complicated because of the use of metaclass, but because you often do need to use the metaclass introspection, operating inheritance / __dict__ and other such variables. In fact, metaclass indeed can do complicated things. However, the following is not complicated:

 

  • Creating a class to understand
  • Change category
  • It returns a modified class

 

Why would you use metaclasses classes instead of functions?

Or stick finish it! Because __metaclass__ can accept any calls, why should we use looks like it complicated? There are several reasons for it:

 

  • The purpose built class is relatively clear, refer to the above UpperAttrMetaclass (type)
  • You can use OOP. Metaclass can be inherited from the metaclass, covering the parent class method
  • You can better organize your code structure. make code easy to read
  • You can use __new__, __init__, __call__
  • Will make a metaclass, always make something of it! (The more far-fetched (:-)

 

Why the hell would you use metaclasses?

python guru written explanation Daoxing not read too shallow, not translated, but he said an example is the Django ORM model is used, for example, we can define the data model is as follows:

 

 

  class Person(models.Model):
  name = models.CharField(max_length=30)
  age = models.IntegerField()

But you call this time:

 

 

  guy = Person(name='bob', age='35')
  print guy.age

It does not return IntegerField object. It will return int, but the values ​​from the database.

 

One explanation is that models.Model defined __metaclass__, and the simple Person you define into complex linked to the database fields.

By Django expose a simple API, the many complex things that make us look very simple, but also through metaclass, regenerate the code in the background using the API.

 

The last word

Finally, the author mentions the type of exception, as well as class alterations: We mean to say most of the time is less than class alteration, and when to use it, you can use monkey patching and class decorators to achieve, it is left to the metaclass space is very small.

 

End! ! !

 

Details of the article clear to see: http: //stackoverflow.com/questions/100003/what-is-a-metaclass-in-python

Occasionally look at the python stackoverflow post, benefit, see today metaclass speak good, you try to translate it to try, you can exchange ideas welcome!



Reproduced in: https: //www.cnblogs.com/james1207/p/3283646.html

Guess you like

Origin blog.csdn.net/weixin_30648587/article/details/94986552