为什么我们需要if __name__ == __main__:

[目录]
0.前言
1.什么是 `__name__`?
2.`if __name__ == '__main__'`: 的作用
3.为何Windows更需`if __name__ =`?

前言

if __name__ == '__main__': 是 Python 中一个非常重要的惯用法,尤其在使用 multiprocessing 模块或编写可导入的模块时。它的作用是区分脚本是直接运行还是被导入,从而控制代码的执行行为。很多初学者可能对此感到困惑,不明白其真正的用途和重要性。

直到发现自己的CPU因为不良的代码习惯而干烧了数十分钟才知道后悔

下面详细解释它的作用和工作原理。


1. 什么是 __name__

__name__ 是 Python 中的一个内置变量,它的值取决于脚本的运行方式:

  • 当脚本被直接运行时(例如通过 python script.py 运行):

    • __name__ 的值是 '__main__'
    • 这是 Python 解释器自动设置的,表示当前脚本是“主脚本”。
  • 当脚本被导入为模块时(例如 import script):

    • __name__ 的值是模块的名称(例如 script)。
    • 此时,脚本中的代码会被执行,但 __name__ 不再是 '__main__'

示例

假设有一个脚本 example.py

print("The value of __name__ is:", __name__)if __name__ == '__main__':print("This script is being run directly.")
else:print("This script is being imported as a module.")
  • 直接运行

    python example.py
    

    输出:

    The value of __name__ is: __main__
    This script is being run directly.
    
  • 作为模块导入: 创建另一个脚本 importer.py

    import example
    

    没错,这个新脚本就这么短小精悍。

    输出:

    The value of __name__ is: example
    This script is being imported as a module.
    

2.if __name__ == '__main__': 的作用

if __name__ == '__main__': 的作用是让某些代码块只在脚本被直接运行时执行,而在脚本被导入时不执行。这有以下几个重要用途:

避免导入时的副作用

当一个 Python 脚本被导入为模块时,脚本中的所有顶层代码(不在函数或类中的代码)都会被执行。
如果这些顶层代码包含不希望在导入时运行的操作(例如启动服务器、执行复杂计算、创建进程等),会产生意外行为。
使用 if name == ‘main’:,可以确保这些代码只在脚本被直接运行时执行。

示例

假设有一个脚本 math_utils.py:

# 顶层代码
print("This will always run when the script is imported!")def add(a, b):return a + b# 不使用 if __name__ == '__main__':
result = add(2, 3)
print(f"Result of add(2, 3): {result}")

另一个脚本 main.py导入了math_utils:

import math_utilsprint("Using math_utils to add numbers...")
print(math_utils.add(5, 6))

运行main.py:

This will always run when the script is imported!
Result of add(2, 3): 5
Using math_utils to add numbers...
11

问题在于,math_utils.py 中的顶层代码(printresult = add(2, 3))在导入时被执行了,这可能不是我们想要的。
现在使用 if __name__ == '__main__': 修改 math_utils.py:

print("This will always run when the script is imported!")def add(a, b):return a + bif __name__ == '__main__':result = add(2, 3)print(f"Result of add(2, 3): {result}")

这时我们得到的运行后结果为:

This will always run when the script is imported!
Using math_utils to add numbers...
11

我们可以发现,if __name__ == '__main__': 块中的代码(result = add(2, 3) 和相关的 print)只在 math_utils.py 被直接运行时执行,导入时不会运行。

其他用途

(1) 测试代码

你可以在 if name == ‘main’: 中添加测试代码,这些代码只在脚本直接运行时执行,而不会在导入时运行。譬如:

def add(a, b):return a + bif __name__ == '__main__':# 测试代码print(add(2, 3))print(add(5, 6))

直接运行时,测试代码会执行;而导入时,测试代码则不会运行。

(2) 命令行工具

许多命令行工具使用 if __name__ == '__main__': 来定义入口点,确保主逻辑只在直接运行时执行。譬如:

import sysdef main():print("Hello, world!")print("Arguments:", sys.argv)if __name__ == '__main__':main()

如果不使用 if __name__ == '__main__': 保护,主逻辑会在脚本被导入时意外执行,这可能导致不希望的行为,尤其是在命令行工具中。

3. 为何Windows更需if __name__ =

这主要取决于我们 coding \texttt{coding} coding的场景——是否会用到multiprocessing 或是其它类似方法来加速我们的计算。

在 Linux 上,multiprocessing 默认使用 fork 方法创建子进程。fork 会直接复制主进程的内存状态,子进程不会重新加载脚本,因此顶层代码不会被重复执行。

在 Windows 上,multiprocessing 使用 spawn 方法,必须重新加载脚本,导致顶层代码被重复执行,因此需要 if __name__ == '__main__': 保护。

值得提醒的是,当我们在 Github \texttt{Github} Github上拿到其它大佬的项目代码时,我们自己在本地运行时一定要检查是否存在类似问题。以pix2pix与CycleGAN项目为例,其原始代码为:

import os
import numpy as np
import cv2
import argparse
from multiprocessing import Pooldef image_write(path_A, path_B, path_AB):im_A = cv2.imread(path_A, 1) # python2: cv2.CV_LOAD_IMAGE_COLOR; python3: cv2.IMREAD_COLORim_B = cv2.imread(path_B, 1) # python2: cv2.CV_LOAD_IMAGE_COLOR; python3: cv2.IMREAD_COLORim_AB = np.concatenate([im_A, im_B], 1)cv2.imwrite(path_AB, im_AB)parser = argparse.ArgumentParser('create image pairs')
parser.add_argument('--fold_A', dest='fold_A', help='input directory for image A', type=str, default='../dataset/50kshoes_edges')
parser.add_argument('--fold_B', dest='fold_B', help='input directory for image B', type=str, default='../dataset/50kshoes_jpg')
parser.add_argument('--fold_AB', dest='fold_AB', help='output directory', type=str, default='../dataset/test_AB')
parser.add_argument('--num_imgs', dest='num_imgs', help='number of images', type=int, default=1000000)
parser.add_argument('--use_AB', dest='use_AB', help='if true: (0001_A, 0001_B) to (0001_AB)', action='store_true')
parser.add_argument('--no_multiprocessing', dest='no_multiprocessing', help='If used, chooses single CPU execution instead of parallel execution', action='store_true',default=False)
args = parser.parse_args()for arg in vars(args):print('[%s] = ' % arg, getattr(args, arg))splits = os.listdir(args.fold_A)if not args.no_multiprocessing:pool=Pool()for sp in splits:img_fold_A = os.path.join(args.fold_A, sp)img_fold_B = os.path.join(args.fold_B, sp)img_list = os.listdir(img_fold_A)if args.use_AB:img_list = [img_path for img_path in img_list if '_A.' in img_path]num_imgs = min(args.num_imgs, len(img_list))print('split = %s, use %d/%d images' % (sp, num_imgs, len(img_list)))img_fold_AB = os.path.join(args.fold_AB, sp)if not os.path.isdir(img_fold_AB):os.makedirs(img_fold_AB)print('split = %s, number of images = %d' % (sp, num_imgs))for n in range(num_imgs):name_A = img_list[n]path_A = os.path.join(img_fold_A, name_A)if args.use_AB:name_B = name_A.replace('_A.', '_B.')else:name_B = name_Apath_B = os.path.join(img_fold_B, name_B)if os.path.isfile(path_A) and os.path.isfile(path_B):name_AB = name_Aif args.use_AB:name_AB = name_AB.replace('_A.', '.')  # remove _Apath_AB = os.path.join(img_fold_AB, name_AB)if not args.no_multiprocessing:pool.apply_async(image_write, args=(path_A, path_B, path_AB))else:im_A = cv2.imread(path_A, 1) # python2: cv2.CV_LOAD_IMAGE_COLOR; python3: cv2.IMREAD_COLORim_B = cv2.imread(path_B, 1) # python2: cv2.CV_LOAD_IMAGE_COLOR; python3: cv2.IMREAD_COLORim_AB = np.concatenate([im_A, im_B], 1)cv2.imwrite(path_AB, im_AB)
if not args.no_multiprocessing:pool.close()pool.join()

即是显然是在 Linux \texttt{Linux} Linux系统上使用的multiprocessing方法。本人一开始尚未注意到该问题,结果CPU干烧了十几分钟,出现类似的 RuntimeError \texttt{RuntimeError} RuntimeError

将代码修正后:

import os
import numpy as np
import cv2
import argparse
from multiprocessing import Pooldef image_write(path_A, path_B, path_AB):im_A = cv2.imread(path_A, 1)im_B = cv2.imread(path_B, 1)if im_A is None or im_B is None:print(f"Failed to load images: {path_A} or {path_B}")returnim_AB = np.concatenate([im_A, im_B], 1)cv2.imwrite(path_AB, im_AB)if __name__ == '__main__':parser = argparse.ArgumentParser('create image pairs')parser.add_argument('--fold_A', dest='fold_A', help='input directory for image A', type=str, default='../dataset/50kshoes_edges')parser.add_argument('--fold_B', dest='fold_B', help='input directory for image B', type=str, default='../dataset/50kshoes_jpg')parser.add_argument('--fold_AB', dest='fold_AB', help='output directory', type=str, default='../dataset/test_AB')parser.add_argument('--num_imgs', dest='num_imgs', help='number of images', type=int, default=1000000)parser.add_argument('--use_AB', dest='use_AB', help='if true: (0001_A, 0001_B) to (0001_AB)', action='store_true')parser.add_argument('--no_multiprocessing', dest='no_multiprocessing', help='If used, chooses single CPU execution instead of parallel execution', action='store_true', default=False)args = parser.parse_args()for arg in vars(args):print('[%s] = ' % arg, getattr(args, arg))splits = os.listdir(args.fold_A)if not args.no_multiprocessing:pool = Pool()for sp in splits:img_fold_A = os.path.join(args.fold_A, sp)img_fold_B = os.path.join(args.fold_B, sp)img_list = os.listdir(img_fold_A)if args.use_AB:img_list = [img_path for img_path in img_list if '_A.' in img_path]num_imgs = min(args.num_imgs, len(img_list))print('split = %s, use %d/%d images' % (sp, num_imgs, len(img_list)))img_fold_AB = os.path.join(args.fold_AB, sp)if not os.path.isdir(img_fold_AB):os.makedirs(img_fold_AB)print('split = %s, number of images = %d' % (sp, num_imgs))for n in range(num_imgs):name_A = img_list[n]path_A = os.path.join(img_fold_A, name_A)if args.use_AB:name_B = name_A.replace('_A.', '_B.')else:name_B = name_Apath_B = os.path.join(img_fold_B, name_B)if os.path.isfile(path_A) and os.path.isfile(path_B):print(f"Found pair: {path_A} and {path_B}")name_AB = name_Aif args.use_AB:name_AB = name_AB.replace('_A.', '.')  # remove _Apath_AB = os.path.join(img_fold_AB, name_AB)if not args.no_multiprocessing:pool.apply_async(image_write, args=(path_A, path_B, path_AB))else:image_write(path_A, path_B, path_AB)else:print(f"Pair not found: {path_A} or {path_B}")if not args.no_multiprocessing:pool.close()pool.join()

终于能够正常运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/78829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

速盾:高防CDN的原理和高防IP一样吗?

随着互联网的发展,网络安全威胁日益严重,尤其是DDoS攻击、CC攻击等恶意行为,给企业带来了巨大的风险。为了应对这些挑战,许多企业开始采用高防CDN(内容分发网络)和高防IP作为防御措施。尽管两者都能提供一定…

《算法笔记》3.6小节——入门模拟->字符串处理

1009 说反话 #include <cstdio>int main() {char sen[80][80];int num0;while(scanf("%s",sen[num])!EOF){num;}for (int i num-1; i > 0; --i) {printf("%s ",sen[i]);}printf("%s\n",sen[0]);return 0; }字符串连接 #include <io…

供应链业务-供应链全局观(三)- 供应链三流的集成

概述 供应链的全局观的全两篇文章主要描述了供应链的基础概念和供应链的协作和集成问题。 供应链业务-供应链全局观&#xff08;一&#xff09;定义了什么是供应链和供应链管理。 所谓供应链就是把采购进来的东西&#xff0c;通过自身的生成加工&#xff0c;进行增值服务&am…

链表-算法小结

链表 单链表 双链表 循环链表 链表_stl-CSDN博客 虚拟头结点 反转链表 删除链表元素 方法一: 直接使用原来的链表来进行删除操作。 头节点是否为空头链表的值是否为要删除的值头结点删除后,新的头节点是否依旧要删除 ,删除后的,新头节点可能是空结点 方法二: 设置一个虚拟…

C语言中常用的调试宏和函数总结(__LINE__、__FUNCTION__)

表格&#xff1a;C语言调试工具 类别工具描述示例代码预定义宏__LINE__表示当前源代码的行号。printf("Error occurred at line %d\n", __LINE__);__FILE__表示当前源代码文件的名称。printf("Error occurred in file %s\n", __FILE__);__func__表示当前函…

DotnetCore开源库SampleAdmin源码编译

1.报错: System.Net.Sockets.SocketException HResult0x80004005 Message由于目标计算机积极拒绝&#xff0c;无法连接。 SourceSystem.Net.Sockets StackTrace: 在 System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, C…

如何使用切片操作来处理序列数据

1 问题 本文主要探究 Python 中切片操作的原理和应用。具体来说&#xff0c;我们将分析切片的基本语法、切片的步长和切片的边界&#xff0c;并通过示例代码展示如何使用切片操作来处理序列数据。 2 方法 为了更好地理解切片操作&#xff0c;我们采用如下的思路学习python中的切…

java(二):java的运算和流程控制

java中单引号和双引号区别和用法 区别1&#xff1a;java中的单引号表示字符&#xff0c;双引号表示字符串。 区别2&#xff1a;单引号引的数据一般是char类型的&#xff1b;双引号引的数据 是String类型的。 区别3&#xff1a;java中单引号里面只能放一个字母或数字或符号&…

Android envsetup与Python venv使用指南

Android envsetup 和 Python venv 是两种完全不同的环境配置工具&#xff0c;分别服务于不同的开发场景。以下是对它们的详细解释及使用方法&#xff1a; 1. Android envsetup 用途&#xff1a; Android envsetup 是 Android 源码开发中的环境配置脚本&#xff08;envsetup.sh…

游戏引擎学习第222天

回顾昨天的过场动画工作 我们正在制作一个游戏&#xff0c;目标是通过直播的方式完成整个游戏的开发。在昨天的工作中&#xff0c;我享受了制作过场动画的过程&#xff0c;所以今天我决定继续制作多个层次的过场动画。 昨天我们已经开始了多层次过场动画的基本制作&#xff0…

Leedcode刷题 | Day31_贪心算法05

一、学习任务 56. 合并区间代码随想录738. 单调递增的数字968. 监控二叉树 二、具体题目 1.56合并区间56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 给出一个区间的集合&#xff0c;请合并所有重叠的区间。 示例 1: 输入: intervals [[1,3],[2,6],[8,10],[15,1…

app逆向专题五:新快报app数据采集

app逆向专题五:新快报app数据采集 一、抓包寻找数据接口二、编写代码三、完整代码一、抓包寻找数据接口 打开charles,并在手机端打开新快报app,点击“广州”或者“经济”等选项卡,抓包,寻找数据接口,如图所示: 二、编写代码 这里介绍一种简便的代码编写方法,在数据…

Java面试黄金宝典45

1. 非对称加密 RSA 定义:RSA 是一种广泛使用的非对称加密算法,其安全性基于大整数分解的困难性。它使用一对密钥,即公钥和私钥。公钥可公开用于加密消息,而私钥必须保密,用于解密由相应公钥加密的消息。要点: 公钥公开,私钥保密,二者成对出现。加密和解密使用不同的密钥…

提权实战!

就是提升权限&#xff0c;当我们拿到一个shell权限较低&#xff0c;当满足MySQL提权的要求时&#xff0c;就可以进行这个提权。 MySQL数据库提权&#xff08;Privilege Escalation&#xff09;是指攻击者通过技术手段&#xff0c;从低权限的数据库用户提升到更高权限&#xff…

在虚拟机上修改saprk的版本

之前安装的spark版本是3.4&#xff0c;现在实验需要的版本是2.4。现在需要更改spark的版本。 方法很简单&#xff1a; 直接将原有的spark3.4的文件删除&#xff0c;再安装2.4版本。 安装过程之后再写。Spark2.1.0入门&#xff1a;Spark的安装和使用_厦大数据库实验室博客

文献分享: DESSERT基于LSH的多向量检索(Part3.2.外部聚合的联合界)

原论文 文章目录 1. \textbf{1. } 1. 定理 4.2 \textbf{4.2} 4.2的内容 1.1. \textbf{1.1. } 1.1. 一些符号 1.2. \textbf{1.2. } 1.2. 定理内容 3. \textbf{3. } 3. 联合界限 Ps. \textbf{Ps. } Ps. 运行时间分析 1. \textbf{1. } 1. 定理 4.2 \textbf{4.2} 4.2的内容 1.1. \t…

MIPI协议介绍

MIPI协议介绍 mipi 协议分为 CSI 和DSI,两者的区别在于 CSI用于接收sensor数据流 DSI用于连接显示屏 csi分类 csi 分为 csi2 和 csi3 csi2根据物理层分为 c-phy 和 d-phy, csi-3采用的是m-phy 一般采用csi2 c-phy 和 d-phy的区别 d-phy的时钟线和数据线是分开的,2根线一对…

【中间件】nginx反向代理实操

一、说明 nginx用于做反向代理&#xff0c;其目标是将浏览器中的请求进行转发&#xff0c;应用场景如下&#xff1a; 说明&#xff1a; 1、用户在浏览器中发送请求 2、nginx监听到浏览器中的请求时&#xff0c;将该请求转发到网关 3、网关再将请求转发至对应服务 二、具体操作…

在3ds Max中视口显示为黑色或深灰色

在3ds Max中视口显示为黑色或深灰色 Autodesk Support 2023年10月8日 涵盖的产品和版本 问题&#xff1a; 在3ds Max中&#xff0c;使用“深”UI方案时视口显示为完全黑色&#xff0c;使用“浅”UI方案时视口显示为深灰色。 原因&#xff1a; 已为用户界面禁用Gamma校正。…

Vue.js 中 v-if 的使用及其原理

在 Vue.js 的开发过程中&#xff0c;条件渲染是一项极为常见的需求。v-if指令作为 Vue.js 实现条件渲染的关键手段&#xff0c;能够根据表达式的真假来决定是否渲染某一块 DOM 元素。它在优化页面展示逻辑、提升用户体验等方面发挥着重要作用。接下来&#xff0c;我们就深入探讨…