4

我想知道口译员在幕后所做的所有动作的顺序(无论它们是否明确声明)。

例如:

  • __init__称呼
  • super()称呼
  • __new__称呼
  • 全局变量
  • 构造函数变量的初始化
  • 装饰者调用等

编辑:让我们假设它是一个拥有一切的类(你命名它)

global_var = 2468
class A(superA):
    class_var = 1234

    __init__(self):
        superA.__init__(self)
        another_var = 5678

    @random_decorator
    def method(self):
        # do stuff
4

2 回答 2

4
class Foo(object):
    def __init__(self, *args, **kwargs):
        pass

>>> foo = Foo(a, b=c)
  1. 它的调用type.__call__(Foo, a, b=c)...... (而不是type你的班级的元类)
  2. ...调用Foo.__new__(a, b=c)哪个创建Foo...的实例
  3. ...并调用foo.__init__(a, b=c)并返回foo

换句话说,b = B(*args)type.__call__(B, *args)where这样的工作type.__call__可以表示为:

class type(object):

    def __call__(cls, *args, **kwargs)
         obj = cls.__new__(*args, **kwargs)
         obj.__init__(*args, **kwargs)
         return obj

函数super仅在您调用它的地方执行(就像普通函数一样)。

装饰是在类和方法的初始化中执行的,在包装器上替换它们。

完整示例:

def dec(func):
    print 'decorate', func.__name__
    def wrapper(*args):
        print 'call wrapper of', func.__name__
        return func(*args)
    return wrapper

class A(object):

    def __new__(*args):
        print 'call A.__new__'
        return object.__new__(*args)

    def __init__(self, *args):
        print 'call A.__init__'


class MyMetaclass(type):

    def __call__(mcls, *args):
        print 'call MyMetaclass.__call__'
        return super(MyMetaclass, mcls).__call__(*args)

class B(A):

    __metaclass__ = MyMetaclass

    @dec
    def __new__(*args):
        print 'call B.__new__'
        return A.__new__(*args)

    @dec
    def __init__(self, *args):
        print 'call B.__init__'
        return super(B, self).__init__(*args)

print 'start creating instance'
b = B()
print 'end creating instance'

结果:

decorate __new__
decorate __init__
start creating instance
call MyMetaclass.__call__
call wrapper of __new__
call B.__new__
call A.__new__
call wrapper of __init__
call B.__init__
call A.__init__
end creating instance
于 2012-10-11T13:58:41.893 回答
2

这一切都很简单。加载模块时,代码从上到下运行。因此,全局变量将在它们出现在模块代码中时被实例化。当一个函数被调用时,其中的代码从上到下运行。

装饰器有点例外,因为它们是在定义了它们要装饰的函数之后按从下到上的顺序调用的。因此,如果您有:

@hits
@dies
@rofls
def watcher(): pass

它与以下内容相同:

def watcher(): pass
watcher = hits(dies(rofls(watcher)))

如果您认为每个装饰器都将所有内容包装在其下方,这是有道理的。

创建对象时,首先__new__调用,然后调用__init__. super()如果你碰巧在某处调用它,就会调用它,就像其他任何东西一样......只要你碰巧在__init__.

编辑:看看你的例子:

class A(superA):
    class_var = 1234

    def __init__(self):
        superA.__init__(self)
        another_var = 5678

    @random_decorator
    def method(self):
        # do stuff

我会教你如何钓鱼。

def random_decorator(f):
    print "random_decorator called"
    return f

def init_var(varname, val):
    print '%s being initialized' % (varname,)
    return val

class superA(object):
    def __new__(cls):
        print 'superA.__new__ called'
        return super(superA, cls).__new__(cls)
    def __init__(self): 
        print "superA.__init__ called"

class A(superA):
    class_var = init_var('class_var', 1234)

    def __new__(cls):
        print 'A.__new__ called'
        return super(A, cls).__new__(cls)

    def __init__(self):
        print 'A.__init__ called'
        superA.__init__(self)
        another_var = init_var('another_var', 5678)

    @random_decorator
    def method(self):
        print 'method called'
        # do stuff

    class_var2 = init_var('class_var2', 9012)

A().method()

查看打印语句的输出顺序。

于 2012-10-11T14:03:52.893 回答