欢迎光临
我们一直在努力

【python】if __name__ == ‘__main__‘ 到底做了啥

if \\__name\\__ == '\\__main\\__' 到底做了啥

    • 理解内置的 __name__ 变量
    • 直接运行 vs 模块导入
      • 实验1:直接运行
      • 实验2:作为模块导入
    • 核心结论
    • 衍生思考:和网络安全的关系

很多初学 Python 的小伙伴,经常会在 Python 中会看到类似如下的代码:

def main():
print('Hello world')

if __name__ == '__main__':
main()

小伙伴们大多会有3个疑问:

  • 上面的 def main() 是干嘛用的?
  • 下面的 main() 又是干嘛用的?
  • 为什么还要加个if判断条件,然后写了一个很莫名其妙的判断公式:__name__ == '__main__'?
  • 稍微学下 Python 的函数知识后,应该对 def main() 定义函数,以及对下面的 main() 调用函数不再难理解,这里就不再详细展开。我们接下来说下这个 if 判断条件的到底在做什么?

    理解内置的 name 变量

    __name__ 是 Python 的一个内置变量,它用于表示当前模块的名字。 我们简单写个print(__name__),运行下可以看到,会打印出来 __main__ ,这表明

    当我们直接运行一个 .py 文件时,Python 解释器会将该文件的 __name__ 设置为特殊字符串 __main__ ,也意味着这个文件是程序的主入口。

    运行一个很简单的print(__name__) 我们也直接在 Python 交互界面用 dir() 就看到,__name__ 变量在 Python 运行时已自动存在,以及当前环境下它的值就是__main__。 在交互界面中用dir()打印出当前的

    直接运行 vs 模块导入

    Python 中,一个 .py 文件就是一个模块。模块可以被其他模块导入以实现代码复用。if __name__ == ‘__main__‘: 的精妙之处,就在于它区分了当前模块是 被直接运行 还是 被导入 。

    实验1:直接运行

    我们创建一个 A.py 文件中并编写个函数,在该文件中直接调用这个函数,具体代码如下,并观测运行结果。

    # filename:A.py

    def hello(string):
    """
    :param string: 打印传入的字符串
    """

    print(string)

    hello('if前面的')

    if __name__ == '__main__':
    # 如果 __name__ 的值是 __main__ 则打印 True~~~~
    hello("True!!!")
    print(__name__) # 同时打印__name__的值
    else:
    # 如果 __name__ 的值不是 __main__ 则打印 False~~~~
    hello("False!!!")
    print(__name__) # 同时打印__name__的值

    运行代码后可以看到它直接打印出了 if 前面调用的函数 hello('if前面的') ,同时调用了 if 函数判断为真时的分支 hello('True!!!') ,接下来打印出了 __name__ 的值为__main__。 代码A.py运行截图

    实验2:作为模块导入

    我们在和 A.py 同一个目录下创建一个很简单的 B.py 文件调用A.py中的代码。

    # filename:B.py

    import A

    A.hello('我是从模块引入的')

    我们运行之后可以看到,代码从最上面开始运行,首先执行了 if 上面的 hello('if前面的') 函数,输出打印了文本 if前面的;接下来执行到了模块 A.py 中 if 条件判断,判断结果是 False ,所以调用了 False 情况下的分支执行了函数 hello("False!!!") ,并执行了print(__name__),输出的结果是A(也就是这个A.py的文件名)。因为 A 和__main__不等,所以进一步证实了上面执行的是 if 判断走的是 False 分支。 从A.py模块中调用函数过程

    核心结论

    我们回到最初的代码,可以得出以下结论:

    if __name__ == '__main__':的True分支下的代码,就是判断当前模块是否是程序的启动入口。

    • 如果是(直接运行),则 __name__ 为 '__main__',条件成立,其下的代码块(通常是主程序逻辑)会被执行。
    • 如果不是(被导入),则 __name__ 为模块名,条件不成立,其下的代码块不会执行。这保证了模块中的测试代码或执行逻辑不会在导入时意外运行。

    def main():
    print('Hello world')

    if __name__ == '__main__':
    main()

    而如果下面这种情况,if 上面的的这个 main() 不管是直接通过解释器运行,还是从外部作为模块导入,都会被执行。

    def main():
    print('Hello world')
    main() # 这里多了个main()
    if __name__ == '__main__':
    main()

    衍生思考:和网络安全的关系

    这个机制本身是Python模块化的基础,但理解它也有助于认识一些潜在的安全问题。核心在于:一个模块在被导入时,其顶层(非函数/类内部)的代码会立即执行。 Python 内置模块(如os 和subprocess)是可以执行操作系统层级命令的,如下面2段代码均执行了 dir /b 打印出当前文件夹的文件。

    import os
    print(os.popen('dir /b').read())

    import subprocess
    subprocess.run('dir /b',shell=True)

    利用os/subprocess执行操作系统命令 如果有人在我们项目目录下,放置了一个恶意的 subprocess.py 文件,或者打包下载的项目中有如下类似的恶意代码:

    # filename:subprocess.py
    import os
    os.system('calc')

    我们的代码或依赖的库尝试 import subprocess 时,Python 的导入机制会优先在当前目录查找。如果找到了这个恶意文件,它顶层的 os.system(‘calc.exe’) 就会被立即执行,从而造成安全隐患。 在这里插入图片描述 attrib +h subprocess.py 隐藏文件 dir /a 查看所有文件含隐藏文件可以看到,或者文件夹设置也可以

    这提醒我们:

  • 不要轻易将不可信目录添加到 Python 路径;
  • 注意项目依赖的安全性;
  • 也正因如此,将可执行代码放入 if __name__ == '__main__': 之后,是一种良好的隔离实践。

  • 希望这篇文章能帮各位小伙伴彻底理解这个 Python 中常见的魔法语句,同时也希望各位小伙伴学习和工作过程中,注重网络安全。

    赞(0)
    未经允许不得转载:171主机测评 » 【python】if __name__ == ‘__main__‘ 到底做了啥
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址