`

Python metaclass

阅读更多

the base article is available here:  http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 

 

 

to understand the metaclass in Python, there is some background that you should be aware in order to grasp the idea of metaclass and its foundation.

 

 

Part I: 

Classes as object

 

Given an class declaration:

 

 

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

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

 

Classes in Python has more... put it simple. that Classes in Python are objects too. 

 

 

As soon as keyword class, Python execute it and craete an OBJECT. the instruction 

 

 

 

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

 

create in memory an object with name ObjectCreator.

 

 

what you can do with the Class object.

 

 

 

  • you can assign it to a variable
  • you can copy it
  • you can add attributes to it
  • you can pass it as a function parameter

 

here is an example of how you can do with the class object.

 

 

 

 

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

 

Part II:

 

Creating Classes Dynamically

 

 

In the base article, there is a example demonstrate how to create classes inside a function.  But that is not dynamic. 

 

 

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

 

Since classes are object, they must be generated by something. the somehting here is the metaclass. 

 

 

But before we drill down to the Metaclass, let's close exame type keyword .

 

 

The following shows what typically you do with type, you get what type an objects is.

 

 

 

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

 

However, type has more, it has a completely different ability, it can also create classes on the fly...

 

the function prototyp of type that create types on the fly is as follow.

 

 

 

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
...
>>> print type(MyShinyClass)
<type 'type'>
>>> MyShinyClass2 = type('MyShinyClass2', (), {})
>>> print MyShinyClass2



>>> # and then you can create the instance of the dynamically created class
...
>>> print MyShinyClass2()
<__main__.MyShinyClass2 object at 0x0110CCB0># and then you can cre
 

So, the following are equivalent.

 

 

 

>>> class Foo(object):
...       bar = True

 

 

and 

 

 

 

>>> Foo = type('Foo', (), {'bar':True})

 

 

and after you created Foo (with the type keyword), you uses it as if you have decalred it. 

 

 

 

  >>> print Foo
  <class '__main__.Foo'>
  >>> print Foo.bar
  True
  >>> f = Foo()
  >>> print f
  <__main__.Foo object at 0x8a9b84c>
  >>> print f.bar
  True

 

Part III:

 

What are metaclass (finally)

The metaclass, boils down to the following definition:

 

Metaclasses are the 'stuff' that creates classes, since classes create objects (as well as being objects), so you take that meta classes as class's class

 

 

  MyClass = MetaClass()
  MyObject = MyClass()

 

the following shows step by step by examing the internals of the type system in Python.

 

A speical note on type method itself.

 

 

 写道
It's because the function type is in fact a metaclass. type is the metaclass Python uses to create all classes behind the scenes.

 

 

Checking the __class__ attribute.

 

 

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

 

 

But what is the __class__ of the __class__, see following..

 

 

 

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

So, they are 'type'. 

 

From the examles above. we can see that a meta class is a "class factory", "type" is the built-in metaclass pythons ues, but of course, you can create your own metaclasses.

 

 

Part IV:

 

the __metaclass__ attribute

the form

 

 

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

 

remember we said before that Pyton will translate the class declaration to an object, but wait, when there is a __metaclass__ attribute.

 

 

 

Python willl look for __metaclass__ in the class definition. If it finds it, if will use it to create the object classFoo. If it doesn't, it will use type to create the class.

 

The order of searching the __metaclass__ is as follow.

 

 

 

  • Is there a __metaclass__ attribute in Foo?
  • If yes, create in memory a class object (I said a class object, stay with me here), with the nameFoo by using what is in __metaclass__.
  • If Python can't find __metaclass__, it will look for a __metaclass__ in Bar (the parent class), and try to do the same.
  • If Python can't find __metaclass__ in any parent, it will look for a __metaclass__ at the MODULE level, and try to do the same.
  • Then if it can't find any __metaclass__ at all, it will use type to create the class object.

 

 

Part V: 

What to put in a custom metaclass

Let's see a stupid example.

 

Suppose we are creating a metaclasses which will alternate all the attributes of classes that it create to have attributes of the classes to be upper cases.

 

 

The following shows how to do that via creating a function as the __metaclass__ (__metaclass__ does not necessary mean it has to be a class)  at the module level, 

 

 

 

# 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 '__'
  attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
  # turn them into uppercase
  uppercase_attr = dict((name.upper(), value) for name, value in attrs)

  # 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(object): 
  # we can define __metaclass__ here instead to affect only this class
  bar = 'bip'

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

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

 

Later, let's do that via the class defintinition

 

 

 

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

        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)

        return type(future_class_name, future_class_parents, uppercase_attr)
 

If we apply all the OOP technique (like the super keyword, calling to base __new__ and applies the convention names such as "cls", "base" and etcc..), then we can get the following code .

 

 

 

class UpperAttrMetaclass(type): 

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

        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)

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

 

 

So in a conclusion, about __metaclass__

 

 

indeed, metaclasses are especially useful to do black magic, and therefore complicated stuff. But by themselves, they are simple:

  • intercept a class creation
  • modify the class
  • return the modified class
there is also a discussion on why to use metaclass rather instead of functions. for brevity, I 'd like to ignore this part. Pease see the page http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python for more details.


Part VI:

why the hell would you use metaclass?


Normally you won't use metaclass, but there is occasions that you will find metaclass handy.


A common cases is creating of an API. A typical one is the Django ORM:


if you have 

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

and if you do this:


guy = Person(name='bob', age='35')
  print guy.age
 
It won't return an IntegerField object. It will return an int, and can even take it directly from the database.

This is possible because models.Model defines __metaclass__ and it uses some magic that will turn the Person you just defined with simple statements into a complex hook to a database field.


Part VII:

the last word:




Classes are object to create instance

Everything is an object in Python, and they are all either instances of classes or instances of metaclasses.


Exception: type;

type is its own metaclass. this is not reproducible in pure python, and is done by cheating a little bit in the implementation level.


metaclass is not absolutely necessary, youcan achieve the goal of alternating a class with 


  • monkey patching
  • class decorators








分享到:
评论

相关推荐

    python中metaclass原理与用法详解

    本文实例讲述了python中metaclass原理与用法。分享给大家供大家参考,具体如下: 什么是 metaclass. metaclass (元类)就是用来创建类的类。在前面一篇文章《python动态创建类》里我们提到过,可以用如下的一个观点来...

    详解python metaclass(元类)

    主要介绍了python metaclass(元类)的相关资料,帮助大家更好的理解和学习,感兴趣的朋友可以了解下

    Python使用metaclass实现Singleton模式的方法

    主要介绍了Python使用metaclass实现Singleton模式的方法,实例分析了Python基于metaclass实现单例模式的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

    python-metaclass.py

    python-metaclass.py

    深入理解Python中的元类(metaclass)

    提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解。他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下...

    举例讲解Python中metaclass元类的创建与使用

    在Python中我们用type函数可以动态地创建一个元类,同样也可以用__metaclass__属性来指定一个元类,接下来我们就来具体举例讲解Python中metaclass元类的创建与使用

    Python库 | metaclass-1.0-py2.py3-none-any.whl

    python库。 资源全名:metaclass-1.0-py2.py3-none-any.whl

    Python设计模式-工厂模式

    工厂模式有三种模式: 简单工厂模式:定义一个创建对象接口,通过参数来决定创建哪个类的实例 工厂方法模式:定义一个创建对象接口...class Coffee(metaclass=ABCMeta): def __init__(self,name): self.__name = name

    Python探索之Metaclass初步了解

    本文先简单介绍了Python中的类,然后是主要内容,涉及Metaclass的相关内容,还是不错的,这里分享给大家,供需要的朋友参考。

    Python 中 Meta Classes详解

    首先,在认识metaclass之前,你需要认识下python中的class。python中class的奇怪特性借鉴了smalltalk语言。大多数语言中,classes仅仅是用于描述怎样创建一个对象的代码端。在某种程度上说,python中的class也是这样...

    详解python单例模式与metaclass

    主要介绍了python单例模式与metaclass,文章介绍了单例模式的实现方式

    简单实用的python教程(通过一个个具体的实用案例快速掌握python项目应用)

    Python进阶一步步理解Python中的元类metaclass Python进阶理解Python中的异步IO和协程(Coroutine),并应用在爬虫中 Python中最好用的异步爬虫库Aiohttp代码实例 Python进阶聊聊IO密集型任务、计算密集型任务,以及多...

    Python基础教程(第2版)第九章魔法方法、属性和迭代器.pdf

    还可以在⾃⼰的类的作⽤域中对__metaclass__变量赋值 class Foo(object): __metaclass__=type 在Python3中没有"旧式"的类,也不需要显⽰地⼦类化object或者将元类设置为type,所有的类都会隐式地成为object的⼦类 ...

    超全面python面试题

    2 Python中的元类(metaclass) 3 @staticmethod和@classmethod 4 类变量和实例变量 5 Python自省 6 字典推导式 7 Python中单下划线和双下划线 8 字符串格式化:\x和.format 9 迭代器和生成器 10 *args and **kwargs 11...

Global site tag (gtag.js) - Google Analytics