作用域规则之函数和类

前文讲述了变量在命名空间中的作用域规则,Python中每个代码段都有自己独立的命名空间,而函数又是以怎样的一种方式在模块、被嵌套函数的命名空间中存在呢?

这是一段含有嵌套函数的源代码,main函数调用了func函数,func函数有调用了inner_func函数,也即是有两处出现了函数的嵌套。下面是通过dis模块提取出来的字节码信息。

我们可以看到func在main栈帧运行环境中以全局变量存在,LOAD_GLOBAL。实际上保存在了frame对象中的f_globals当中,而f_globals是一个PyDictObject类型的字典对象,而字典对象又是无序存在的,只要在运行之前能正确编译出字节码对象即可。

看上去,函数和变量的作用域规则似乎有点像,实际上函数在栈帧运行环境中被看作一个全局变量来处理的。那类又是怎么样的呢,和函数有什么不同呢?

在Python内部,所有的动西都是对象,即使是用户通过class关键字定义的类也是一样,叫做类对象,这是在Python内部实现的层面上。通过class关键字定义的类又可以实例化出具体的对象,我们暂且叫做实例对象,这是从Python外部使用层面上来看的。想要了解类在命名空间中的作用域规则,首先要清楚类对象是如何产生的,以什么样的形式存在,会不会和函数一样也是作为全局变量在模块的命名空间存在呢?

Python的类对象都是通过元类来产生的,默认元类为,用户也可以通过metaclass关键字自定义元类。

classSuperTest():

def__init__(self):

self.name =''

def__repr__(self):

return'Super_ins'

classTest(SuperTest):

frame = sys._getframe()

printframe.f_globals

def__init__(self):

self.name ='test'

defmain():

t= Test()

main()

图示例源码中定义了两个有继承关系的类,在Test的栈中f_globals包含SuperTest 对象,'SuperTest': 。

classTest(SuperTest):

frame = sys._getframe()

printframe.f_globals

def__init__(self):

self.name ='test'

classSuperTest():

def__init__(self):

self.name =''

def__repr__(self):

return'Super_ins'

而如果把SuperTest定义在Test的后面,NameError的错误。

NameError: name 'SuperTest' is not defined

先来看下类对象生成过程:

首先会检查自定义类是否有基类,如果没有就默认为object。如果有就创建基类列表,为Tuple类型,实际上保存基类变量名列表。然后非别对基类进行初始化,初始化的过程就是绑定类对象元信息的过程(实际上就是用户在class中定义的数据填充到类对象tp_dict中去)。在基类初始化过程通过LOAD_NAME获取基类的时候,没有找到变量的约束关系,因为实际的约束关系绑定在后面的定义中实现的。所以就会报出NameError的错误。也就是说在有继承关系的类定义中是有先后顺序的。而函数是被当作全局变量保存在f_globals中与位置是无关的。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180629G0ZQPW00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券