从__name__=='__main__'说到__builtin__

一、__name__

我们在写好代码进行自测的时候一般会先写这样一行代码:

# inter_method

if __name__ == '__main__':

为什么呢,可能并不是所有人都考虑过,这个就类似与C语言中的main一样,是一个函数的入口,python写的各个module都可以包含这样一个入口,但是在本module执行的时候,__name__就是__main__,而被导入的时候__name__就是module的名称,所以上面那行代码可以保证我们的测试代码只在本module生效而在被导入时并不执行,先看下面的代码print出的值就是__main__。

# inter_method

  1. def inter():
        print(__name__)

    if __name__ == '__main__':
        inter()  # __main__

 

如果被引用呢,我们从外部模块导入inter方法,看下面的代码:

# outer_method

  1. import inner_method

    if __name__ == '__main__':
        print __name__  # __main__
       
    inner_method.inter()  # inner_method

 

原文件打印的就不再是__main__了,所以测试代码不会执行。

有人会说,我导入时候不是就已经知道模块名了吗,为什么还要通过__name__来获取,其实有时候我们不一定知道,比如我们在中间导入的时候把模块名as成了其他名称,另一个模块再从这里导入我们就不知道原始的模块名了,比如:

# outer_method

  1. import inner_method as inter

 

 

# another

  1. from outer_method import inter

    if __name__ == '__main__':
        print __name__  # __main__
        print inter.__name__  # inner_method

 

在这种情况下,在another中我们不知道原始模块名的,但是__name__确是知道的。

__name__在模块中是代表module名,在类中代表类名,在方法中代表方法名,看下面的代码:

# inter_method

  1. class Test(object):
        def __init__(self):
            print '%s,%s' % ('class', Test.__name__)

        def func(self):
            print 'method %s' % Test.func.__name__

    def inter():
        obj = Test()
        obj.func()

    if __name__ == '__main__':
        inter()  # class,Test, method func

 

返回的结果是类和方法的名称,但是方法名称也不一定和你看到的一致,__name__会反应这一变化,比如被装饰的方法名称就会有变化:

# inter_method

  1. def dec(func):
        def dec_method(*args, **kwargs):
            func(*args, **kwargs)

        return dec_method

    class Test(object):
        def __init__(self):
            print '%s,%s' % ('class', Test.__name__)

        @dec
        def method(self):
            print 'method %s' % Test.method.__name__

    def inter():
        obj = Test()
        obj.method()

    if __name__ == '__main__':
        inter()# class,Test, method dec_method

 

可以看到,方法名并不是原来的method了,而是由于装饰器的原因变成了dec_method。

二、module

上面在介绍__name__的时候提到了module,在Python中,一个.py文件就构成一个module。通过module,你可以调用其它文件中的程序。我们是通过import 或import a as b的形式来引入module,以通过module.object的方式来调用引入模块中的某个对象,Python会在以下路径中搜索它想要寻找的模块:程序所在的文件夹;标准库的安装路径;操作系统环境变量PYTHONPATH所包含的路径。

有一点需要关注,某些时候他会影响你的代码,即import导入的是一个module,你通过module.object引用的对象仍然是属于原module的,但是你使用from module import object的时候是直接将该object导入到了本module,他成了当前module的一部分。我们看个例子:

  1. # config.py
    param = 100

 

 

  1. # inner_method.py
    import config
    config.param = 200

 

 

  1. # outer_method.py
    import inner_method as inter
    import config

    if __name__ == '__main__':
        print(config.param)  # 200

 

可以看到,原param的值是100,在inner_method中对其进行了修改,由于导入的config,所以修改的是原module中的值,在另外一个文件中导入的再导入该module时打印的是修改后的值,如果换一种导入方式情况就不同了:

  1. # config.py
    param = 100

 

 

  1. # inner_method.py
    from config import param
    param = 200

 

 

  1. # outer_method.py
    import inner_method as inter
    from config import param

    if __name__ == '__main__':
        print(param)  # 100

 

这种修该并不会反映到config这个module里,因为param已经被导入到inner_method的命名空间,所以这边打印的值仍然是param的原值,明白这个原理,有时候可以避免一些代码错误。

对上面的简介做个总结,即import导入的模块会保留自己的命名空间,这就是为什么你需要使用模块名来访问它的函数或属性(module.function)的原因。而from module import则要从另一个模块中将指定的函数和属性导入到你自己的名字空间,这就是为什么你可以直接访问它们却不需要引用它们所来源的模块的原因。

说到这里,又出现一个新问题,为什么我们可以直接使用str(),dict()等函数,而不需要显示的导入他们呢,下面就介绍下这个。

三、__builtin__

    python是按LEGB原则来查找函数,变量等的,即L-Local(function):函数内的名字空间;E-Enclosing function locals:外部嵌套函数的名字空间(例如closure);G-Global(module):函数定义所在模块(文件)的名字空间;B-Builtin(Python):Python内置模块的名字空间。所以在本文件内找不到的参数或者函数就会到内建模块中寻找。

在Python2.X版本中,内建模块被命名为__builtin__,当使用内建模块中函数或其它功能时,可以直接使用,不用添加内建模块的名字;但是,如果想要向内建模块中添加一些功能,以便在任何函数中都能直接使用而不 用再进行import,这时,就要导入内建模块,在内建模块的命名空间(即__dict__字典属性)中添加该功能,例如:

  1. # inner_method.py
  1. import __builtin__

    def add_func(a,b):
        return 100*a + 10*b
    __builtin__.__dict__['add_test'] = add_func

    if __name__ == '__main__':
        print add_test(1, 2)  # 120
  1.  

 

由上面的代码看出,add_test已经加到了内建空间,可以直接对其进行使用了。

还有一个__builtins__,那这个是什么呢?其实它是对内建模块一个引用,在程序启动时他会随着内建模块一起被加载入内存,和__builtin__不同,在任何模块不需导入都可以看到__builtins__,但是在__main__中__builtins__是对内建模块__builtin__本身的引用,即__builtins__完全等价于__builtin__,在非__main__模块中,__builtins__仅是对__builtin__.__dict__的引用,而非__builtin__本身,先看个例子:

  1. # inner_method.py
  1. import __builtin__

    def add_func(a,b):
        return 100*a + 10*b
    __builtin__.__dict__['add_test'] = add_func

    if __builtin__ is __builtins__:
        print('in main, __builtin__ is __builtins__')
        print(type(__builtins__))
        print (__builtins__)
    if __builtin__.__dict__ is __builtins__:
        print('not in main, __builtin__.__dict__ is __builtins__')
        print(type(__builtins__))
        print dir(__builtin__.__dict__)

    if __name__ == '__main__':
        print add_test(1, 2)

 

在inner_method文件里执行,得到的结果是这样的:

in main, __builtin__ is __builtins__

<type 'module'>

<module '__builtin__' (built-in)>

120

说明在__main__中执行__builtin__就是__builtins__,它的type是一个module,如果我们在outer_method中导入再执行,例子如下:

  1. # outer_method.py
  1. import inner_method

    if __name__ == '__main__':
        print add_test(1, 2)

 

结果是这样的:

not in main, __builtin__.__dict__ is __builtins__

<type 'dict'>

['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']

120

说明在导入的情况下执行__builtins__是__builtin__.__dict__,他是一个字典,正是由于这种特性,所以在使用的时候推荐直接使用__builtin__,因为可控的总是比不可控的要更好,在大多数地方,都是使用__builtin__为内建模块添加信息。

posted @ 2018-07-19 18:44  Small_office  阅读(604)  评论(0编辑  收藏  举报