__new__ __init__ 区别

原文地址: http://stackoverflow.com/questions/674304/pythons-use-of-new-and-init

 

Use __new__ when you need to control the creation of a new instance. Use __init__ when you need to control initialization of a new instance.

 

__new__ is the first step of instance creation. It's called first, and is responsible for returning a new instance of your class.

In contrast, __init__ doesn't return anything; it's only responsible for initializing the instance after it's been created.

 

In general, you shouldn't need to override __new__ unless you're subclassing an immutable type like str, int, unicode or tuple.

 

__call__ implements function call operator

class foo:
    def __call__(self, a, b, c):
        # ...

x = foo()
x(1, 2, 3) # __call__

原文地址:http://blog.danmarner.com/me/entry/python-new-metaclass-init-plugin-system/

一个用 class 关键字定义的类在执行a = ClassA(arg1, arg2,...)(初始化其实例)的时候,会发生 :::

a = type(ClassA).__call__(ClassA, arg1, arg2,...)

type(ClassA)实际上返回的是ClassA的metaclass,默认值为type。这个type.__call__的实现可以用如下代码表示(只能表示表示,实际代码都是用C实现的)。

def __call__(cls, *args, **kwargs):
    result = cls.__new__(cls, *args, **kwargs)
    if isinstance(result, cls):
        type(result).__init__(result,*args,**kwargs)
    return result

也就是说type.__call__先尝试用__new__来创建类的实例,只有__new__返回了类的实例,__init__才会得以应用到实例上

 

e.g.

class InjectMeta(type):
    def __new__(cls, name, bases, attrs):
        print "class:", cls
        print "name:", name
        print "bases:", bases
        print "attrs:", attrs
        return type.__new__(cls, name, bases, attrs)
    def __init__(cls, name, bases, attrs):
       print "class:", cls# cls = Data
       type.__init__(cls, name, bases, attrs)

class Data(object):
    __metaclass__ = InjectMeta
    x = 1
    def test(self): pass


res:
class: <class '__main__.InjectMeta'> name: Data bases: (<type 'object'>,) attrs: {'test': <function test at 0x02B6DDB0>, 'x': 1, '__module__': '__main__', '__metaclass__': <class '__main__.InjectMeta'>} class: <class '__main__.Data'>

 

 

我们可以从type类派生出新的 metaclass, 然后通过重新实现__new__, __init__, __call__来实现类或者类实例的生成.
Meta类 meta.py
class Meta(type): def __call__(self): print 'Enter Meta.__call__: ', self obj = type.__call__(self) print 'Exit Meta.__call__: ', obj return obj def __new__(metacls, name, bases, dictionary): print 'Enter Meta.__new__:', metacls, name, bases, dictionary newClass = type.__new__(metacls, name, bases, dictionary) print 'Exit Meta.__new__: ', newClass return newClass def __init__(cls, name, bases, dictionary): print 'Enter Meta.__init__: ', cls, name, bases, dictionary super(Meta, cls).__init__(name, bases, dictionary) print 'Exit Meta.__init__' print 'Create class A' A = Meta('A', (object,), {}) print print 'Create instance of class A' A() 当我们运行上述的python文件, 会得到下面的输出结果: $ python meta.py Create class A Enter Meta.__new__: <class '__main__.Meta'> A (<type 'object'>,) {} Exit Meta.__new__: <class '__main__.A'> Enter Meta.__init__: <class '__main__.A'> A (<type 'object'>,) {} Exit Meta.__init__ Create instance of class A Enter Meta.__call__: <class '__main__.A'> Exit Meta.__call__: <__main__.A object at 0xb76a9ccc>

 

静态类 (static class): 不允许创建实例,通常作为工具类 (Utility) 存在。
 class StaticClassMeta(type):
    def __new__(cls, name, bases, attr):
        t = type.__new__(cls, name, bases, attr)
        def ctor(cls, *args, **kwargs):
            raise RuntimeError("Cannot create a instance of the static class!")
        t.__new__ = staticmethod(ctor)
        return t

class Data(object):
   __metaclass__ = StaticClassMeta

>>> Data()
RuntimeError: Cannot create a instance of the static class!

密封类 (sealed class): 禁止被继承。
class SealedClassMeta(type):
    _types = set()

    def __init__(cls, name, bases, attrs):
    if cls._types & set(bases): # 判断当前类型基类是否是sealed class。
        raise SyntaxError("Cannot inherit from a sealed class!")
    cls._types.add(cls) # 将当前类型加入到禁用继承集合。

class A(object):
    __metaclass__ = SealedClassMeta

>>> class B(A): pass
SyntaxError: Cannot inherit from a sealed class!

 

posted @ 2015-01-15 11:13  blue_whale  阅读(154)  评论(0)    收藏  举报