
[{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/tags/blowfish/","section":"标签","summary":"","title":"Blowfish","type":"tags"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/tags/hugo/","section":"标签","summary":"","title":"Hugo","type":"tags"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/tags/","section":"标签","summary":"","title":"标签","type":"tags"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/categories/","section":"分类列表","summary":"","title":"分类列表","type":"categories"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/","section":"欢迎来到 Cloud_Shy! 🎉","summary":"","title":"欢迎来到 Cloud_Shy! 🎉","type":"page"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/archives/","section":"历史文档","summary":"","title":"历史文档","type":"archives"},{"content":"","date":"2025-08-18","externalUrl":null,"permalink":"/categories/%E6%96%B0%E6%89%8B%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B%E9%9B%86%E5%90%88/","section":"分类列表","summary":"","title":"新手入门教程集合","type":"categories"},{"content":" Cloud_Shy 分享热爱 \u0026#x1f60d; 本节包含一些软件工具安装流程记录，主要用于记录博主本人的学习过程以及促进和广大网友们的交流学习。您还可以参考标签页面的内容。\n","date":"2025-08-18","externalUrl":null,"permalink":"/naivelearnings/","section":"新手入门教程集合","summary":"","title":"新手入门教程集合","type":"naivelearnings"},{"content":" 一、Hugo 配置 Blowfish 主题 # 1、新建一个网站根目录 # 在下载的含有 hugo.exe 文件的目录中，输入 cmd 打开命令行窗口，输入命令：\nhugo new site mywebsite 这里的 mywebsite 文件夹就是我们新建的网站的根目录，牢记该目录，后续很多操作都需要在该目录下进行。\n2、切换到刚刚新建的文件夹 # 3、初始化一个新的 git 仓库并将 Blowfish 添加为子模块。 # git init\rgit submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfish 4、设置主题的配置文件 # 在根目录 mywebsite 中，删除 Hugo 自动生成的 hugo.toml 文件。从主题中复制 config 文件夹中的 *.toml 文件，粘贴到 config/_default/ 目录（若没有该文件夹，可直接将主题中的 config 文件夹复制到根目录下）中。\n5、基础设置 # 在刚刚安装完成，创建内容之前，有几个设置需要关注。从 hugo.toml 开始，设置 baseURL 和 languageCode 参数。languageCode参数是用来指定你创作内容的主要语言。\n尽管 Blowfish 支持多语言，但是 hugo.toml 只能配置一个主语言。在 config/_default 文件夹中找到 languages.en.toml。如果你的主语言是英语，你可以直接使用此文件。否则需要重命名为主语言对应的文件名。例如，如果主语言是简体中文，那么需要将文件命名为 languages.fr.toml。然后编辑该文件内的相应部分，\n**注意：**语言配置文件名中的语言代码需要与 hugo.toml 中 languageCode 相匹配，另外 Blowfish 中的为 “zh-cn”。故对 hugo.toml w 文件作出如下修改：\n6、文章缩略图 # 在 content\\posts\\yourpostfile 目录下添加一个以 feature* 开头的特征图片（推荐使用 .png 或 .jpg），这就是 yourpostfile 目录中 index.md 的特征图片，在网站中作为缩略图使用。\n实际效果如下，\n7、自定义自己的网站图标 # 网站图标——Favicon 是 favorites icon 的缩写，又称为 website icon（网页图标）、page icon （页面图标）或者 url icon（URL 图标）。可以使用 https://favicon.io/favicon-generator/ 自定义生成自己喜欢的图标并下载下来。\n将下载后的图标资源解压放在 static/ 文件夹中，并务必按照如下的名称命名。如果你使用了favicon.io，那么下载下来的文件名和下面的示例完全一致；当然你也可以通过别的方式提供，记得重命名就行。\nstatic/\r├─ android-chrome-192x192.png\r├─ android-chrome-512x512.png\r├─ apple-touch-icon.png\r├─ favicon-16x16.png\r├─ favicon-32x32.png\r├─ favicon.ico\r└─ site.webmanifest 然后，在 config/_default/params.toml 中添加基础配置，\n[params]\rfavicon = \u0026#34;favicon.ico\u0026#34; 接着，在根目录下新建一个文件 layouts/partials/favicons.html，在其中写入：\n\u0026lt;!-- Apple --\u0026gt;\r\u0026lt;link rel=\u0026#34;apple-touch-icon\u0026#34; sizes=\u0026#34;180x180\u0026#34; href=\u0026#34;{{ \u0026#34;apple-touch-icon.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- PNG Favicon --\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;32x32\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-32x32.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;16x16\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-16x16.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Manifest --\u0026gt;\r\u0026lt;link rel=\u0026#34;manifest\u0026#34; href=\u0026#34;{{ \u0026#34;site.webmanifest\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Safari --\u0026gt;\r\u0026lt;link rel=\u0026#34;mask-icon\u0026#34; href=\u0026#34;{{ \u0026#34;safari-pinned-tab.svg\u0026#34; | relURL }}\u0026#34; color=\u0026#34;#5bbad5\u0026#34;\u0026gt;\r\u0026lt;!-- ICO fallback --\u0026gt;\r\u0026lt;link rel=\u0026#34;shortcut icon\u0026#34; href=\u0026#34;{{ \u0026#34;favicon.ico\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Windows --\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileColor\u0026#34; content=\u0026#34;#2b5797\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileImage\u0026#34; content=\u0026#34;{{ \u0026#34;mstile-150x150.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;theme-color\u0026#34; content=\u0026#34;#ffffff\u0026#34;\u0026gt; 这样 Blowfish 原有的 head.html 会继续引入 \u0026lt;meta charset=\u0026quot;utf-8\u0026quot;\u0026gt; 等必需信息，你的 favicon 代码也会插入，不会乱码。\n最后，进行测试，在根目录下打开命令行窗口，输入：\nhugo server -D 效果如下，\n关于网站页面内的图标展示，需要修改根目录下 config/_default/languages.zh-cn.toml 中的 params.logo，这里的 logo 大小为 64*64 的 png。\n二、GitHub 部署 # 参考:\n​ [1]. 使用 Hugo 和 Github Pages 服务从零开始搭建个人博客_hugo 中文文档-CSDN 博客\n​ [2]. https://blowfish.page/zh-cn/docs/installation/\n​ [3]. (27 封私信 / 62 条消息) 10 分钟部署你的 blog 网站到 github pages - 知乎\n1、新建一个仓库，点击 GitHub 个人主页的 New\n2、输入仓库名称，以及设置为公共访问：\n3、到 MyBlog 中的 Hugo.toml 中修改链接，即更换成自己的 GitHub 仓库链接，\n4、保存后，MyBlog 目录中会自动生成一个 public 文件夹，\n将其删除，使用 cmd 重新生成一个，\n5、双击 public 打开后，使用 cmd 打开命令行窗口，输入以下代码：\ngit init\rgit add .\rgit commit -m \u0026#34;first commit\u0026#34;\rgit branch -M main\rgit remote add origin https://github.com/teliduxingdimiao/teliduxingdimiao.github.io.git\rgit push -u origin main 输入第三行代码报错，原因是未配置 GitHub 用户名和邮箱，解决方法如下：\n拓展：GitHub 用户名与昵称 https://gitwebcn.com/47996.html\ngit config --global user.email \u0026#34;xxxxxx@xx.com\u0026#34;\t# 注册 GitHub 的邮箱\rgit config --global user.name \u0026#34;xxxxxx\u0026#34;\t# GitHub 的用户名 配置完成后，运行成功，\n最后一行代码。可能需要登陆，\n6、回到 GitHub 的个人仓库，可以看到我们的个人博客仓库已经建好了，点开看一些有哪些内容，\n接下来，需要开启静态页面，点击 Setting，\n找到左边栏 Pages，进行修改：\n等待一段时间后，当前页面显示如下，个人博客即部署完成。\n三、集成 Firebase 获取阅读量和点赞量 # 1、Firebase 托管 # 首先，使用您的 Google 帐户免费注册一个 Firebase 账号，https://firebase.google.com/?hl=zh-cn 点击官方链接，在首页点击右上角的 “Go to console” 控制台，\n跳转到欢迎页面，然后点击 “创建新的 Firebase 项目”，\n输入自己的项目名称，\n然后，点击继续，直到 “配置 Google Analytics“，选择默认的账号，\n接下来，需要等待一段时间，完成资源配置，\n配置完成后，页面跳转到该新建项目首页，点击创建 web 按钮，\n按照流程进行设置，\n第二步中的 SDK 可以先不复制，完成设置后可以到项目设置里查看，\n然后，win + R 输入 cmd 启动命令行窗口，输入命令 npm install -g firebase-tools 安装 Firebase CLI，注意：这里需要先安装好 Node.js 才能使用 npm。\n步骤 4 中的立即部署提到的 Web 应用的根目录，指的是本机中创建的 Hugo 网站的项目根目录，例如 hugo\\myblog，\n设置完成后，可以看到，新建的 Web 应用以及右边的设置按钮，\n点击设置，在常规页面滚轮下滑，找到 ”SDK 设置和配置“ 复制，\n将其中的配置信息复制到本地项目根目录中的 config/_default/params.toml，覆盖原有的 firebase 标签，\n注意，修改格式，改成等号和删除逗号，下图为示例（非严格相同），\n2、配置 Authentication # 在新建的 Firebase 项目的主页面点击 “所有产品” ，再点击 Authentication，\n点击开始，选择登陆方法为匿名，\n然后配置 Firstore，回到项目主页面，点击所有产品，选择 Cloud Firestore 创建数据库，选择数据库位置（视情况而定，推荐选近一点的），默认以生产模式开始，\n创建成功后，会跳转到以下页面，\n3、检验效果 # 回到本地 Hugo 项目根目录中，打开命令行窗口，执行 hugo server访问本地网站，在首页页面中右键点击 “查看页面源代码”，可以看到先前的配置信息，\n然后回到我们的本地项目根目录中的 config/_default/params.toml，找到 article.showViews 和 article.Links，将其修改为 true，才能显示文章和列表页面的阅读量。\n接下来，就是将修改同步到项目根目录中的 public，即在命令行窗口中输入 hugo，然后 cd public进入到 public 目录，将修改推送到 GitHub Pages 仓库，即\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 访问我们的 hugo 网站就可以在文章下方看到阅读量和点赞量了。Happy！！！\n四、创建文章及上传 # 1、创建一篇 Blog # 这里提供两种方法：\n方法一 # 在项目根目录下，启动命令行窗口，输入一下命令，\nhugo new content posts/Article01.md\t# 自命名文章名称 这样就可以在 content/posts 目录下生成一个 markdown 文件，使用编辑器（VS Code 或者 typora）打开，可以看到其默认生成的文件头信息（front matter），一般为创建时间、是否为草稿以及文章名称。我们需要初步修改的是将 draft = true 改成 draft = false，以便于在网站中显示该文章。\n然后就可以在此文章中编辑内容了。其中图片的编辑不可避免，在这里推荐的是使用 Page Bundle 管理图片。\n假设文章结构如下：\ncontent/posts/my-post/index.md\rcontent/posts/my-post/img/img1.jpg\rcontent/posts/my-post/img/img2.png 这样，图片和文章一起管理，迁移方便。然后在 index.md 里直接用 HTML 标签来插入图片：\n\u0026lt;center\u0026gt;\u0026lt;img src=\u0026#34;img\\img1.jpg\u0026#34; width=\u0026#34;100%\u0026#34; /\u0026gt;\u0026lt;/center\u0026gt; 这样可以实现更复杂的图像布局或样式，或者控制图片的大小。\n方法二 # 直接在编辑器中使用 markdown 语法编辑文章，然后将其复制到 content/posts 目录中的新建的文章同名文件夹中，将其重命名为 index.md，打开文件后在文章顶部插入 front matter，图片编辑方法同方法一。\n2、更新文章内容 # 在创建一个新的 blog 后，在根目录下打开 cmd 命令行窗口，输入 hugo -D，将根目录中的内容更新到 public 文件夹中（自动覆盖），\n然后，输入 cd public，切换到 public 目录下，执行以下命令进行仓库 push，将需要用到的资源同步到 GitHub 仓库上，\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 可以看到在我们的 GitHub 仓库中，该网站的仓库的 Actions 正在执行更新，\n打开我们的网站，静态部署的内容已经更新到最新的网站中了，\n","date":"2025-08-18","externalUrl":null,"permalink":"/archives/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E8%BF%9B%E9%98%B6/","section":"历史文档","summary":"","title":"新手小白个人博客搭建之 Hugo 进阶","type":"archives"},{"content":" 一、Hugo 配置 Blowfish 主题 # 1、新建一个网站根目录 # 在下载的含有 hugo.exe 文件的目录中，输入 cmd 打开命令行窗口，输入命令：\nhugo new site mywebsite 这里的 mywebsite 文件夹就是我们新建的网站的根目录，牢记该目录，后续很多操作都需要在该目录下进行。\n2、切换到刚刚新建的文件夹 # 3、初始化一个新的 git 仓库并将 Blowfish 添加为子模块。 # git init\rgit submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfish 4、设置主题的配置文件 # 在根目录 mywebsite 中，删除 Hugo 自动生成的 hugo.toml 文件。从主题中复制 config 文件夹中的 *.toml 文件，粘贴到 config/_default/ 目录（若没有该文件夹，可直接将主题中的 config 文件夹复制到根目录下）中。\n5、基础设置 # 在刚刚安装完成，创建内容之前，有几个设置需要关注。从 hugo.toml 开始，设置 baseURL 和 languageCode 参数。languageCode参数是用来指定你创作内容的主要语言。\n尽管 Blowfish 支持多语言，但是 hugo.toml 只能配置一个主语言。在 config/_default 文件夹中找到 languages.en.toml。如果你的主语言是英语，你可以直接使用此文件。否则需要重命名为主语言对应的文件名。例如，如果主语言是简体中文，那么需要将文件命名为 languages.fr.toml。然后编辑该文件内的相应部分，\n**注意：**语言配置文件名中的语言代码需要与 hugo.toml 中 languageCode 相匹配，另外 Blowfish 中的为 “zh-cn”。故对 hugo.toml w 文件作出如下修改：\n6、文章缩略图 # 在 content\\posts\\yourpostfile 目录下添加一个以 feature* 开头的特征图片（推荐使用 .png 或 .jpg），这就是 yourpostfile 目录中 index.md 的特征图片，在网站中作为缩略图使用。\n实际效果如下，\n7、自定义自己的网站图标 # 网站图标——Favicon 是 favorites icon 的缩写，又称为 website icon（网页图标）、page icon （页面图标）或者 url icon（URL 图标）。可以使用 https://favicon.io/favicon-generator/ 自定义生成自己喜欢的图标并下载下来。\n将下载后的图标资源解压放在 static/ 文件夹中，并务必按照如下的名称命名。如果你使用了favicon.io，那么下载下来的文件名和下面的示例完全一致；当然你也可以通过别的方式提供，记得重命名就行。\nstatic/\r├─ android-chrome-192x192.png\r├─ android-chrome-512x512.png\r├─ apple-touch-icon.png\r├─ favicon-16x16.png\r├─ favicon-32x32.png\r├─ favicon.ico\r└─ site.webmanifest 然后，在 config/_default/params.toml 中添加基础配置，\n[params]\rfavicon = \u0026#34;favicon.ico\u0026#34; 接着，在根目录下新建一个文件 layouts/partials/favicons.html，在其中写入：\n\u0026lt;!-- Apple --\u0026gt;\r\u0026lt;link rel=\u0026#34;apple-touch-icon\u0026#34; sizes=\u0026#34;180x180\u0026#34; href=\u0026#34;{{ \u0026#34;apple-touch-icon.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- PNG Favicon --\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;32x32\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-32x32.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;16x16\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-16x16.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Manifest --\u0026gt;\r\u0026lt;link rel=\u0026#34;manifest\u0026#34; href=\u0026#34;{{ \u0026#34;site.webmanifest\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Safari --\u0026gt;\r\u0026lt;link rel=\u0026#34;mask-icon\u0026#34; href=\u0026#34;{{ \u0026#34;safari-pinned-tab.svg\u0026#34; | relURL }}\u0026#34; color=\u0026#34;#5bbad5\u0026#34;\u0026gt;\r\u0026lt;!-- ICO fallback --\u0026gt;\r\u0026lt;link rel=\u0026#34;shortcut icon\u0026#34; href=\u0026#34;{{ \u0026#34;favicon.ico\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Windows --\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileColor\u0026#34; content=\u0026#34;#2b5797\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileImage\u0026#34; content=\u0026#34;{{ \u0026#34;mstile-150x150.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;theme-color\u0026#34; content=\u0026#34;#ffffff\u0026#34;\u0026gt; 这样 Blowfish 原有的 head.html 会继续引入 \u0026lt;meta charset=\u0026quot;utf-8\u0026quot;\u0026gt; 等必需信息，你的 favicon 代码也会插入，不会乱码。\n最后，进行测试，在根目录下打开命令行窗口，输入：\nhugo server -D 效果如下，\n关于网站页面内的图标展示，需要修改根目录下 config/_default/languages.zh-cn.toml 中的 params.logo，这里的 logo 大小为 64*64 的 png。\n二、GitHub 部署 # 参考:\n[1]. 使用 Hugo 和 Github Pages 服务从零开始搭建个人博客_hugo 中文文档-CSDN 博客\n[2]. https://blowfish.page/zh-cn/docs/installation/\n[3]. (27 封私信 / 62 条消息) 10 分钟部署你的 blog 网站到 github pages - 知乎\n1、新建一个仓库，点击 GitHub 个人主页的 New\n2、输入仓库名称，以及设置为公共访问：\n3、到 MyBlog 中的 Hugo.toml 中修改链接，即更换成自己的 GitHub 仓库链接，\n4、保存后，MyBlog 目录中会自动生成一个 public 文件夹，\n将其删除，使用 cmd 重新生成一个，\n5、双击 public 打开后，使用 cmd 打开命令行窗口，输入以下代码：\ngit init\rgit add .\rgit commit -m \u0026#34;first commit\u0026#34;\rgit branch -M main\rgit remote add origin https://github.com/teliduxingdimiao/teliduxingdimiao.github.io.git\rgit push -u origin main 输入第三行代码报错，原因是未配置 GitHub 用户名和邮箱，解决方法如下：\n拓展：GitHub 用户名与昵称 https://gitwebcn.com/47996.html\ngit config --global user.email \u0026#34;xxxxxx@xx.com\u0026#34;\t# 注册 GitHub 的邮箱\rgit config --global user.name \u0026#34;xxxxxx\u0026#34;\t# GitHub 的用户名 配置完成后，运行成功，\n最后一行代码。可能需要登陆，\n6、回到 GitHub 的个人仓库，可以看到我们的个人博客仓库已经建好了，点开看一些有哪些内容，\n接下来，需要开启静态页面，点击 Setting，\n找到左边栏 Pages，进行修改：\n等待一段时间后，当前页面显示如下，个人博客即部署完成。\n三、集成 Firebase 获取阅读量和点赞量 # 1、Firebase 托管 # 首先，使用您的 Google 帐户免费注册一个 Firebase 账号，https://firebase.google.com/?hl=zh-cn 点击官方链接，在首页点击右上角的 “Go to console” 控制台，\n跳转到欢迎页面，然后点击 “创建新的 Firebase 项目”，\n输入自己的项目名称，\n然后，点击继续，直到 “配置 Google Analytics“，选择默认的账号，\n接下来，需要等待一段时间，完成资源配置，\n配置完成后，页面跳转到该新建项目首页，点击创建 web 按钮，\n按照流程进行设置，\n第二步中的 SDK 可以先不复制，完成设置后可以到项目设置里查看，\n然后，win + R 输入 cmd 启动命令行窗口，输入命令 npm install -g firebase-tools 安装 Firebase CLI，注意：这里需要先安装好 Node.js 才能使用 npm。\n步骤 4 中的立即部署提到的 Web 应用的根目录，指的是本机中创建的 Hugo 网站的项目根目录，例如 hugo\\myblog，\n设置完成后，可以看到，新建的 Web 应用以及右边的设置按钮，\n点击设置，在常规页面滚轮下滑，找到 ”SDK 设置和配置“ 复制，\n将其中的配置信息复制到本地项目根目录中的 config/_default/params.toml，覆盖原有的 firebase 标签，\n注意，修改格式，改成等号和删除逗号，下图为示例（非严格相同），\n2、配置 Authentication # 在新建的 Firebase 项目的主页面点击 “所有产品” ，再点击 Authentication，\n点击开始，选择登陆方法为匿名，\n然后配置 Firstore，回到项目主页面，点击所有产品，选择 Cloud Firestore 创建数据库，选择数据库位置（视情况而定，推荐选近一点的），默认以生产模式开始，\n创建成功后，会跳转到以下页面，\n3、检验效果 # 回到本地 Hugo 项目根目录中，打开命令行窗口，执行 hugo server访问本地网站，在首页页面中右键点击 “查看页面源代码”，可以看到先前的配置信息，\n然后回到我们的本地项目根目录中的 config/_default/params.toml，找到 article.showViews 和 article.Links，将其修改为 true，才能显示文章和列表页面的阅读量。\n接下来，就是将修改同步到项目根目录中的 public，即在命令行窗口中输入 hugo，然后 cd public进入到 public 目录，将修改推送到 GitHub Pages 仓库，即\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 访问我们的 hugo 网站就可以在文章下方看到阅读量和点赞量了。Happy！！！\n四、创建文章及上传 # 1、创建一篇 Blog # 这里提供两种方法：\n方法一 # 在项目根目录下，启动命令行窗口，输入一下命令，\nhugo new content posts/Article01.md\t# 自命名文章名称 这样就可以在 content/posts 目录下生成一个 markdown 文件，使用编辑器（VS Code 或者 typora）打开，可以看到其默认生成的文件头信息（front matter），一般为创建时间、是否为草稿以及文章名称。我们需要初步修改的是将 draft = true 改成 draft = false，以便于在网站中显示该文章。\n然后就可以在此文章中编辑内容了。其中图片的编辑不可避免，在这里推荐的是使用 Page Bundle 管理图片。\n假设文章结构如下：\ncontent/posts/my-post/index.md\rcontent/posts/my-post/img/img1.jpg\rcontent/posts/my-post/img/img2.png 这样，图片和文章一起管理，迁移方便。然后在 index.md 里直接用 HTML 标签来插入图片：\n\u0026lt;center\u0026gt;\u0026lt;img src=\u0026#34;img\\img1.jpg\u0026#34; width=\u0026#34;100%\u0026#34; /\u0026gt;\u0026lt;/center\u0026gt; 这样可以实现更复杂的图像布局或样式，或者控制图片的大小。\n方法二 # 直接在编辑器中使用 markdown 语法编辑文章，然后将其复制到 content/posts 目录中的新建的文章同名文件夹中，将其重命名为 index.md，打开文件后在文章顶部插入 front matter，图片编辑方法同方法一。\n2、更新文章内容 # 在创建一个新的 blog 后，在根目录下打开 cmd 命令行窗口，输入 hugo -D，将根目录中的内容更新到 public 文件夹中（自动覆盖），\n然后，输入 cd public，切换到 public 目录下，执行以下命令进行仓库 push，将需要用到的资源同步到 GitHub 仓库上，\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 可以看到在我们的 GitHub 仓库中，该网站的仓库的 Actions 正在执行更新，\n打开我们的网站，静态部署的内容已经更新到最新的网站中了，\n","date":"2025-08-18","externalUrl":null,"permalink":"/naivelearnings/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E8%BF%9B%E9%98%B6/","section":"新手入门教程集合","summary":"","title":"新手小白个人博客搭建之 Hugo 进阶","type":"naivelearnings"},{"content":" 一、Hugo 配置 Blowfish 主题 # 1、新建一个网站根目录 # 在下载的含有 hugo.exe 文件的目录中，输入 cmd 打开命令行窗口，输入命令：\nhugo new site mywebsite 这里的 mywebsite 文件夹就是我们新建的网站的根目录，牢记该目录，后续很多操作都需要在该目录下进行。\n2、切换到刚刚新建的文件夹 # 3、初始化一个新的 git 仓库并将 Blowfish 添加为子模块。 # git init\rgit submodule add -b main https://github.com/nunocoracao/blowfish.git themes/blowfish 4、设置主题的配置文件 # 在根目录 mywebsite 中，删除 Hugo 自动生成的 hugo.toml 文件。从主题中复制 config 文件夹中的 *.toml 文件，粘贴到 config/_default/ 目录（若没有该文件夹，可直接将主题中的 config 文件夹复制到根目录下）中。\n5、基础设置 # 在刚刚安装完成，创建内容之前，有几个设置需要关注。从 hugo.toml 开始，设置 baseURL 和 languageCode 参数。languageCode参数是用来指定你创作内容的主要语言。\n尽管 Blowfish 支持多语言，但是 hugo.toml 只能配置一个主语言。在 config/_default 文件夹中找到 languages.en.toml。如果你的主语言是英语，你可以直接使用此文件。否则需要重命名为主语言对应的文件名。例如，如果主语言是简体中文，那么需要将文件命名为 languages.fr.toml。然后编辑该文件内的相应部分，\n**注意：**语言配置文件名中的语言代码需要与 hugo.toml 中 languageCode 相匹配，另外 Blowfish 中的为 “zh-cn”。故对 hugo.toml w 文件作出如下修改：\n6、文章缩略图 # 在 content\\posts\\yourpostfile 目录下添加一个以 feature* 开头的特征图片（推荐使用 .png 或 .jpg），这就是 yourpostfile 目录中 index.md 的特征图片，在网站中作为缩略图使用。\n实际效果如下，\n7、自定义自己的网站图标 # 网站图标——Favicon 是 favorites icon 的缩写，又称为 website icon（网页图标）、page icon （页面图标）或者 url icon（URL 图标）。可以使用 https://favicon.io/favicon-generator/ 自定义生成自己喜欢的图标并下载下来。\n将下载后的图标资源解压放在 static/ 文件夹中，并务必按照如下的名称命名。如果你使用了favicon.io，那么下载下来的文件名和下面的示例完全一致；当然你也可以通过别的方式提供，记得重命名就行。\nstatic/\r├─ android-chrome-192x192.png\r├─ android-chrome-512x512.png\r├─ apple-touch-icon.png\r├─ favicon-16x16.png\r├─ favicon-32x32.png\r├─ favicon.ico\r└─ site.webmanifest 然后，在 config/_default/params.toml 中添加基础配置，\n[params]\rfavicon = \u0026#34;favicon.ico\u0026#34; 接着，在根目录下新建一个文件 layouts/partials/favicons.html，在其中写入：\n\u0026lt;!-- Apple --\u0026gt;\r\u0026lt;link rel=\u0026#34;apple-touch-icon\u0026#34; sizes=\u0026#34;180x180\u0026#34; href=\u0026#34;{{ \u0026#34;apple-touch-icon.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- PNG Favicon --\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;32x32\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-32x32.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;link rel=\u0026#34;icon\u0026#34; type=\u0026#34;image/png\u0026#34; sizes=\u0026#34;16x16\u0026#34; href=\u0026#34;{{ \u0026#34;favicon-16x16.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Manifest --\u0026gt;\r\u0026lt;link rel=\u0026#34;manifest\u0026#34; href=\u0026#34;{{ \u0026#34;site.webmanifest\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Safari --\u0026gt;\r\u0026lt;link rel=\u0026#34;mask-icon\u0026#34; href=\u0026#34;{{ \u0026#34;safari-pinned-tab.svg\u0026#34; | relURL }}\u0026#34; color=\u0026#34;#5bbad5\u0026#34;\u0026gt;\r\u0026lt;!-- ICO fallback --\u0026gt;\r\u0026lt;link rel=\u0026#34;shortcut icon\u0026#34; href=\u0026#34;{{ \u0026#34;favicon.ico\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;!-- Windows --\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileColor\u0026#34; content=\u0026#34;#2b5797\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;msapplication-TileImage\u0026#34; content=\u0026#34;{{ \u0026#34;mstile-150x150.png\u0026#34; | relURL }}\u0026#34;\u0026gt;\r\u0026lt;meta name=\u0026#34;theme-color\u0026#34; content=\u0026#34;#ffffff\u0026#34;\u0026gt; 这样 Blowfish 原有的 head.html 会继续引入 \u0026lt;meta charset=\u0026quot;utf-8\u0026quot;\u0026gt; 等必需信息，你的 favicon 代码也会插入，不会乱码。\n最后，进行测试，在根目录下打开命令行窗口，输入：\nhugo server -D 效果如下，\n关于网站页面内的图标展示，需要修改根目录下 config/_default/languages.zh-cn.toml 中的 params.logo，这里的 logo 大小为 64*64 的 png。\n二、GitHub 部署 # 参考:\n[1]. 使用 Hugo 和 Github Pages 服务从零开始搭建个人博客_hugo 中文文档-CSDN 博客\n[2]. https://blowfish.page/zh-cn/docs/installation/\n[3]. (27 封私信 / 62 条消息) 10 分钟部署你的 blog 网站到 github pages - 知乎\n1、新建一个仓库，点击 GitHub 个人主页的 New\n2、输入仓库名称，以及设置为公共访问：\n3、到 MyBlog 中的 Hugo.toml 中修改链接，即更换成自己的 GitHub 仓库链接，\n4、保存后，MyBlog 目录中会自动生成一个 public 文件夹，\n将其删除，使用 cmd 重新生成一个，\n5、双击 public 打开后，使用 cmd 打开命令行窗口，输入以下代码：\ngit init\rgit add .\rgit commit -m \u0026#34;first commit\u0026#34;\rgit branch -M main\rgit remote add origin https://github.com/teliduxingdimiao/teliduxingdimiao.github.io.git\rgit push -u origin main 输入第三行代码报错，原因是未配置 GitHub 用户名和邮箱，解决方法如下：\n拓展：GitHub 用户名与昵称 https://gitwebcn.com/47996.html\ngit config --global user.email \u0026#34;xxxxxx@xx.com\u0026#34;\t# 注册 GitHub 的邮箱\rgit config --global user.name \u0026#34;xxxxxx\u0026#34;\t# GitHub 的用户名 配置完成后，运行成功，\n最后一行代码。可能需要登陆，\n6、回到 GitHub 的个人仓库，可以看到我们的个人博客仓库已经建好了，点开看一些有哪些内容，\n接下来，需要开启静态页面，点击 Setting，\n找到左边栏 Pages，进行修改：\n等待一段时间后，当前页面显示如下，个人博客即部署完成。\n三、集成 Firebase 获取阅读量和点赞量 # 1、Firebase 托管 # 首先，使用您的 Google 帐户免费注册一个 Firebase 账号，https://firebase.google.com/?hl=zh-cn 点击官方链接，在首页点击右上角的 “Go to console” 控制台，\n跳转到欢迎页面，然后点击 “创建新的 Firebase 项目”，\n输入自己的项目名称，\n然后，点击继续，直到 “配置 Google Analytics“，选择默认的账号，\n接下来，需要等待一段时间，完成资源配置，\n配置完成后，页面跳转到该新建项目首页，点击创建 web 按钮，\n按照流程进行设置，\n第二步中的 SDK 可以先不复制，完成设置后可以到项目设置里查看，\n然后，win + R 输入 cmd 启动命令行窗口，输入命令 npm install -g firebase-tools 安装 Firebase CLI，注意：这里需要先安装好 Node.js 才能使用 npm。\n步骤 4 中的立即部署提到的 Web 应用的根目录，指的是本机中创建的 Hugo 网站的项目根目录，例如 hugo\\myblog，\n设置完成后，可以看到，新建的 Web 应用以及右边的设置按钮，\n点击设置，在常规页面滚轮下滑，找到 ”SDK 设置和配置“ 复制，\n将其中的配置信息复制到本地项目根目录中的 config/_default/params.toml，覆盖原有的 firebase 标签，\n注意，修改格式，改成等号和删除逗号，下图为示例（非严格相同），\n2、配置 Authentication # 在新建的 Firebase 项目的主页面点击 “所有产品” ，再点击 Authentication，\n点击开始，选择登陆方法为匿名，\n然后配置 Firstore，回到项目主页面，点击所有产品，选择 Cloud Firestore 创建数据库，选择数据库位置（视情况而定，推荐选近一点的），默认以生产模式开始，\n创建成功后，会跳转到以下页面，\n3、检验效果 # 回到本地 Hugo 项目根目录中，打开命令行窗口，执行 hugo server访问本地网站，在首页页面中右键点击 “查看页面源代码”，可以看到先前的配置信息，\n然后回到我们的本地项目根目录中的 config/_default/params.toml，找到 article.showViews 和 article.Links，将其修改为 true，才能显示文章和列表页面的阅读量。\n接下来，就是将修改同步到项目根目录中的 public，即在命令行窗口中输入 hugo，然后 cd public进入到 public 目录，将修改推送到 GitHub Pages 仓库，即\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 访问我们的 hugo 网站就可以在文章下方看到阅读量和点赞量了。Happy！！！\n四、创建文章及上传 # 1、创建一篇 Blog # 这里提供两种方法：\n方法一 # 在项目根目录下，启动命令行窗口，输入一下命令，\nhugo new content posts/Article01.md\t# 自命名文章名称 这样就可以在 content/posts 目录下生成一个 markdown 文件，使用编辑器（VS Code 或者 typora）打开，可以看到其默认生成的文件头信息（front matter），一般为创建时间、是否为草稿以及文章名称。我们需要初步修改的是将 draft = true 改成 draft = false，以便于在网站中显示该文章。\n然后就可以在此文章中编辑内容了。其中图片的编辑不可避免，在这里推荐的是使用 Page Bundle 管理图片。\n假设文章结构如下：\ncontent/posts/my-post/index.md\rcontent/posts/my-post/img/img1.jpg\rcontent/posts/my-post/img/img2.png 这样，图片和文章一起管理，迁移方便。然后在 index.md 里直接用 HTML 标签来插入图片：\n\u0026lt;center\u0026gt;\u0026lt;img src=\u0026#34;img\\img1.jpg\u0026#34; width=\u0026#34;100%\u0026#34; /\u0026gt;\u0026lt;/center\u0026gt; 这样可以实现更复杂的图像布局或样式，或者控制图片的大小。\n方法二 # 直接在编辑器中使用 markdown 语法编辑文章，然后将其复制到 content/posts 目录中的新建的文章同名文件夹中，将其重命名为 index.md，打开文件后在文章顶部插入 front matter，图片编辑方法同方法一。\n2、更新文章内容 # 在创建一个新的 blog 后，在根目录下打开 cmd 命令行窗口，输入 hugo -D，将根目录中的内容更新到 public 文件夹中（自动覆盖），\n然后，输入 cd public，切换到 public 目录下，执行以下命令进行仓库 push，将需要用到的资源同步到 GitHub 仓库上，\ngit add .\rgit commit -m \u0026#34;update\u0026#34;\rgit push 可以看到在我们的 GitHub 仓库中，该网站的仓库的 Actions 正在执行更新，\n打开我们的网站，静态部署的内容已经更新到最新的网站中了，\n","date":"2025-08-18","externalUrl":null,"permalink":"/posts/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E8%BF%9B%E9%98%B6/","section":"Posts","summary":"","title":"新手小白个人博客搭建之 Hugo 进阶","type":"posts"},{"content":"","date":"2025-08-11","externalUrl":null,"permalink":"/tags/blog/","section":"标签","summary":"","title":"Blog","type":"tags"},{"content":"参考：\n[1]. Hugo 安装保姆级教程（搭建个人 blog）_hugo 搭建个人博客-CSDN 博客\n[2]. 从零到一，用 Hugo 打造你的个人网站\n一、下载与安装 # 进入官方网站： https://gohugo.io/，点击 GitHub 。\n接着点击 Releases 发行版，进入历史仓库，\n选择最新版本，\n在 Assets 中，选择合适的压缩包下载（本机系统为 win11，故选择 hugo_extended_0.148.2_windows-amd64.zip），\n下载压缩包到任意文件夹后，解压。\n在文件命令行输入 cmd 进入命令行窗口，输入命令：\nhugo new site MyBlog\t# 这里的 MyBlog 是用户自定义的文件夹名称 接着切换目录到刚刚新建的文件夹 MyBlog：\ncd MyBlog 打开相应的资源管理器界面可以看到刚刚新建的 MyBlog 文件夹。需要注意的是，由于没有配置全局环境变量，因此要复制 hugo.exe 到 MyBlog 文件夹中才能运行。\n最后，先验证一下 Hugo 博客是否创建成功：\nhugo server --buildDrafts\rhugo server -D\t# 两个命令任选其一执行 点击界面中的启动地址（Ctrl + 单击），\n跳转出的 web 页面如下，说明创建成功（没有内容属于正常情况）：\n接下来，我们需要创建或者安装一个主题。\n二、创建安装主题 # 回到官方主页面，点击 Themes，\n可以看到官方提供的主题样式是很丰富的，\n挑选一个自己喜好的主题进行下载就可以，这里我选择的是 hugo-theme-reimu 这个主题（二次元勿喷）：\n点击 Demo 可以预先展示其效果，还是很好看的。\n点击 Download 下载，会跳转到 GitHub 页面，然后点击 Releases，\n当前版本为 v0.12.0，下拉找到 Assets，点击 Source code（zip）下载，\n将下载好的压缩包复制或剪切到之前创建的 MyBlog 文件夹中的 theme 目录中，并解压到当前目录同名文件夹，\n接下来，就是详细的配置操作了。由于每个主题的开发者实现的功能不同，因此建议根据下载的主题的 Github 上的 Readme.md 文件中的操作一步步来进行配置。\n剧透：该主题在本地可以正常显示，但是部署到 GitHub Pages 就各种异常，各种尝试解决无果后，个人分析原因可能是：该主题是从 hexo 转到 hugo 的，文件目录就很 hexo，感觉配置上可能有些 bug。查询网上的案例也比较少，真的尽力了[kuku]。\n1、官方操作 # **说明：**按照 Readme.md 文件可以实现，但有些地方需要更改。\n需要事先安装好 Git Git 详细安装教程（详解 Git 安装过程的每一个步骤）_git 安装-CSDN 博客\n这里使用的 hugo-theme-reimu 主题的具体操作如下：\n解决 GitHub 连接超时问题 Recv failure: Connection was reset：\ngit config --global http.proxy http://127.0.0.1:7890\rgit config --global -l\t# 查看是否设置成功 hugo new site MyBlog\rcd MyBlog\rgit init\rgit submodule add https://github.com/D-Sketon/hugo-theme-reimu.git themes/reimu\recho theme = \u0026#39;reimu\u0026#39; \u0026gt;\u0026gt; hugo.toml\t# 官方文档符号不对\rhugo server 将主题内的 config/_default/params.yml 复制到 _default 文件夹下，此文件作为主题配置文件，可在此文件中修改主题配置\n2、成功在于简单粗暴 # 直接将解压后的文件夹复制到 MyBlog 目录中去，进行覆盖，实操可用。不过到自定义阶段，可能会有些问题，还是不推荐这样做。\n3、创建文章 # 在 MyBlog 目录下运行命令：\nhugo new post/Articles 01. md\t# 注意这里是 post，也有的是 posts，根据个人安装的主题不同，哪个能够显示文章用哪个。 然后输入启动命令，就可以看到我们新建的文章了，\n4、归档文件 Archives # 将 reimu 文件夹中的 _example 中的 archives 文件复制到 MyBlog 目录下的 content 文件夹中去，\n5、修改侧边栏 sidebar 位置 # 打开目录 MyBlog\\config_default 中的 params.yml，搜索 sidebar ，修改成 left，\n三、自定义配置 # 参考：https://sobaigu.com/hugo-config-structure.html\n1、语言配置 # 在 MyBlog 目录下找到 hugo.toml 文件，\n打开该文件修改语言：\nlanguageCode = \u0026#39;zh-CN\u0026#39;\rdefaultContentLanguage = \u0026#39;zh-CN\u0026#39;\r[languages]\r[languages.zh-CN]\rlanguageName = \u0026#39;简体中文\u0026#39;\rweight = 1\rhasCJKLanguage = true 2、基本结构 # 同原文档操作。\n3、头像 # （1）头像应保存于 static/avatar/avatar.webp，可在 params.yml 中修改文件名：\navatar: \u0026#34;avatar.webp\u0026#34; 拓展：WebP，是一种同时提供了有损压缩与无损压缩的图片文件格式\nparams.yml 的文件路径为 MyBlog\\config\\_default，使用记事本打开 params.yml 后，Ctrl + F 输入 avatar 即可找到，\n修改后，可以看到网页中的头像已经更换成我们自己的图片了：\n4、内置主题配色 # 原装的 reimu 主题配色是红色系，这里我们自定义为自己喜欢的配色，还是找到 MyBlog\\config\\_default 目录下的 params.yml，打开后搜索 internal_theme，修改如下内容：\n这里原来的配色可以自行搜索查看具体颜色，这里给一个链接方便查看：颜色代码转换 - 锤子在线工具\n新的配色可以选择一个主色调，然后使用这个工具来找到系列配色：Deepskyblue／深天藍／#00bfff 十六进制颜色代码表，图表，调色板，绘图\u0026amp;油漆\n我是用的是蓝色系，如下：\n修改完成后，还需要将 MyBlog\\themes\\reimu\\assets 目录中文件复制到 MyBlog\\assets 目录中去，因为其中的 css 文件夹中的 _variables.scss 对应我们刚刚修改的 internal_theme，可以打开来看一下，\n从上图中的红框中的内容，可以明显地知道其对应的就是我们自己修改的颜色。\n写在最后：制作不易，请友友们点赞！收藏！分享！\nDon\u0026rsquo;t be shy, dare to share！ShyShy ！\n","date":"2025-08-11","externalUrl":null,"permalink":"/archives/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E5%85%A5%E9%97%A8/","section":"历史文档","summary":"","title":"新手小白个人博客搭建之 Hugo 入门","type":"archives"},{"content":"参考：\n[1]. Hugo 安装保姆级教程（搭建个人 blog）_hugo 搭建个人博客-CSDN 博客\n[2]. 从零到一，用 Hugo 打造你的个人网站\n一、下载与安装 # 进入官方网站： https://gohugo.io/，点击 GitHub 。\n接着点击 Releases 发行版，进入历史仓库，\n选择最新版本，\n在 Assets 中，选择合适的压缩包下载（本机系统为 win11，故选择 hugo_extended_0.148.2_windows-amd64.zip），\n下载压缩包到任意文件夹后，解压。\n在文件命令行输入 cmd 进入命令行窗口，输入命令：\nhugo new site MyBlog\t# 这里的 MyBlog 是用户自定义的文件夹名称 接着切换目录到刚刚新建的文件夹 MyBlog：\ncd MyBlog 打开相应的资源管理器界面可以看到刚刚新建的 MyBlog 文件夹。需要注意的是，由于没有配置全局环境变量，因此要复制 hugo.exe 到 MyBlog 文件夹中才能运行。\n最后，先验证一下 Hugo 博客是否创建成功：\nhugo server --buildDrafts\rhugo server -D\t# 两个命令任选其一执行 点击界面中的启动地址（Ctrl + 单击），\n跳转出的 web 页面如下，说明创建成功（没有内容属于正常情况）：\n接下来，我们需要创建或者安装一个主题。\n二、创建安装主题 # 回到官方主页面，点击 Themes，\n可以看到官方提供的主题样式是很丰富的，\n挑选一个自己喜好的主题进行下载就可以，这里我选择的是 hugo-theme-reimu 这个主题（二次元勿喷）：\n点击 Demo 可以预先展示其效果，还是很好看的。\n点击 Download 下载，会跳转到 GitHub 页面，然后点击 Releases，\n当前版本为 v0.12.0，下拉找到 Assets，点击 Source code（zip）下载，\n将下载好的压缩包复制或剪切到之前创建的 MyBlog 文件夹中的 theme 目录中，并解压到当前目录同名文件夹，\n接下来，就是详细的配置操作了。由于每个主题的开发者实现的功能不同，因此建议根据下载的主题的 Github 上的 Readme.md 文件中的操作一步步来进行配置。\n剧透：该主题在本地可以正常显示，但是部署到 GitHub Pages 就各种异常，各种尝试解决无果后，个人分析原因可能是：该主题是从 hexo 转到 hugo 的，文件目录就很 hexo，感觉配置上可能有些 bug。查询网上的案例也比较少，真的尽力了[kuku]。\n1、官方操作 # **说明：**按照 Readme.md 文件可以实现，但有些地方需要更改。\n需要事先安装好 Git Git 详细安装教程（详解 Git 安装过程的每一个步骤）_git 安装-CSDN 博客\n这里使用的 hugo-theme-reimu 主题的具体操作如下：\n解决 GitHub 连接超时问题 Recv failure: Connection was reset：\ngit config --global http.proxy http://127.0.0.1:7890\rgit config --global -l\t# 查看是否设置成功 hugo new site MyBlog\rcd MyBlog\rgit init\rgit submodule add https://github.com/D-Sketon/hugo-theme-reimu.git themes/reimu\recho theme = \u0026#39;reimu\u0026#39; \u0026gt;\u0026gt; hugo.toml\t# 官方文档符号不对\rhugo server 将主题内的 config/_default/params.yml 复制到 _default 文件夹下，此文件作为主题配置文件，可在此文件中修改主题配置\n2、成功在于简单粗暴 # 直接将解压后的文件夹复制到 MyBlog 目录中去，进行覆盖，实操可用。不过到自定义阶段，可能会有些问题，还是不推荐这样做。\n3、创建文章 # 在 MyBlog 目录下运行命令：\nhugo new post/Articles 01. md\t# 注意这里是 post，也有的是 posts，根据个人安装的主题不同，哪个能够显示文章用哪个。 然后输入启动命令，就可以看到我们新建的文章了，\n4、归档文件 Archives # 将 reimu 文件夹中的 _example 中的 archives 文件复制到 MyBlog 目录下的 content 文件夹中去，\n5、修改侧边栏 sidebar 位置 # 打开目录 MyBlog\\config_default 中的 params.yml，搜索 sidebar ，修改成 left，\n三、自定义配置 # 参考：https://sobaigu.com/hugo-config-structure.html\n1、语言配置 # 在 MyBlog 目录下找到 hugo.toml 文件，\n打开该文件修改语言：\nlanguageCode = \u0026#39;zh-CN\u0026#39;\rdefaultContentLanguage = \u0026#39;zh-CN\u0026#39;\r[languages]\r[languages.zh-CN]\rlanguageName = \u0026#39;简体中文\u0026#39;\rweight = 1\rhasCJKLanguage = true 2、基本结构 # 同原文档操作。\n3、头像 # （1）头像应保存于 static/avatar/avatar.webp，可在 params.yml 中修改文件名：\navatar: \u0026#34;avatar.webp\u0026#34; 拓展：WebP，是一种同时提供了有损压缩与无损压缩的图片文件格式\nparams.yml 的文件路径为 MyBlog\\config\\_default，使用记事本打开 params.yml 后，Ctrl + F 输入 avatar 即可找到，\n修改后，可以看到网页中的头像已经更换成我们自己的图片了：\n4、内置主题配色 # 原装的 reimu 主题配色是红色系，这里我们自定义为自己喜欢的配色，还是找到 MyBlog\\config\\_default 目录下的 params.yml，打开后搜索 internal_theme，修改如下内容：\n这里原来的配色可以自行搜索查看具体颜色，这里给一个链接方便查看：颜色代码转换 - 锤子在线工具\n新的配色可以选择一个主色调，然后使用这个工具来找到系列配色：Deepskyblue／深天藍／#00bfff 十六进制颜色代码表，图表，调色板，绘图\u0026amp;油漆\n我是用的是蓝色系，如下：\n修改完成后，还需要将 MyBlog\\themes\\reimu\\assets 目录中文件复制到 MyBlog\\assets 目录中去，因为其中的 css 文件夹中的 _variables.scss 对应我们刚刚修改的 internal_theme，可以打开来看一下，\n从上图中的红框中的内容，可以明显地知道其对应的就是我们自己修改的颜色。\n写在最后：制作不易，请友友们点赞！收藏！分享！\nDon\u0026rsquo;t be shy, dare to share！ShyShy ！\n","date":"2025-08-11","externalUrl":null,"permalink":"/naivelearnings/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E5%85%A5%E9%97%A8/","section":"新手入门教程集合","summary":"","title":"新手小白个人博客搭建之 Hugo 入门","type":"naivelearnings"},{"content":"参考：\n[1]. Hugo 安装保姆级教程（搭建个人 blog）_hugo 搭建个人博客-CSDN 博客\n[2]. 从零到一，用 Hugo 打造你的个人网站\n一、下载与安装 # 进入官方网站： https://gohugo.io/，点击 GitHub 。\n接着点击 Releases 发行版，进入历史仓库，\n选择最新版本，\n在 Assets 中，选择合适的压缩包下载（本机系统为 win11，故选择 hugo_extended_0.148.2_windows-amd64.zip），\n下载压缩包到任意文件夹后，解压。\n在文件命令行输入 cmd 进入命令行窗口，输入命令：\nhugo new site MyBlog\t# 这里的 MyBlog 是用户自定义的文件夹名称 接着切换目录到刚刚新建的文件夹 MyBlog：\ncd MyBlog 打开相应的资源管理器界面可以看到刚刚新建的 MyBlog 文件夹。需要注意的是，由于没有配置全局环境变量，因此要复制 hugo.exe 到 MyBlog 文件夹中才能运行。\n最后，先验证一下 Hugo 博客是否创建成功：\nhugo server --buildDrafts\rhugo server -D\t# 两个命令任选其一执行 点击界面中的启动地址（Ctrl + 单击），\n跳转出的 web 页面如下，说明创建成功（没有内容属于正常情况）：\n接下来，我们需要创建或者安装一个主题。\n二、创建安装主题 # 回到官方主页面，点击 Themes，\n可以看到官方提供的主题样式是很丰富的，\n挑选一个自己喜好的主题进行下载就可以，这里我选择的是 hugo-theme-reimu 这个主题（二次元勿喷）：\n点击 Demo 可以预先展示其效果，还是很好看的。\n点击 Download 下载，会跳转到 GitHub 页面，然后点击 Releases，\n当前版本为 v0.12.0，下拉找到 Assets，点击 Source code（zip）下载，\n将下载好的压缩包复制或剪切到之前创建的 MyBlog 文件夹中的 theme 目录中，并解压到当前目录同名文件夹，\n接下来，就是详细的配置操作了。由于每个主题的开发者实现的功能不同，因此建议根据下载的主题的 Github 上的 Readme.md 文件中的操作一步步来进行配置。\n剧透：该主题在本地可以正常显示，但是部署到 GitHub Pages 就各种异常，各种尝试解决无果后，个人分析原因可能是：该主题是从 hexo 转到 hugo 的，文件目录就很 hexo，感觉配置上可能有些 bug。查询网上的案例也比较少，真的尽力了[kuku]。\n1、官方操作 # **说明：**按照 Readme.md 文件可以实现，但有些地方需要更改。\n需要事先安装好 Git Git 详细安装教程（详解 Git 安装过程的每一个步骤）_git 安装-CSDN 博客\n这里使用的 hugo-theme-reimu 主题的具体操作如下：\n解决 GitHub 连接超时问题 Recv failure: Connection was reset：\ngit config --global http.proxy http://127.0.0.1:7890\rgit config --global -l\t# 查看是否设置成功 hugo new site MyBlog\rcd MyBlog\rgit init\rgit submodule add https://github.com/D-Sketon/hugo-theme-reimu.git themes/reimu\recho theme = \u0026#39;reimu\u0026#39; \u0026gt;\u0026gt; hugo.toml\t# 官方文档符号不对\rhugo server 将主题内的 config/_default/params.yml 复制到 _default 文件夹下，此文件作为主题配置文件，可在此文件中修改主题配置\n2、成功在于简单粗暴 # 直接将解压后的文件夹复制到 MyBlog 目录中去，进行覆盖，实操可用。不过到自定义阶段，可能会有些问题，还是不推荐这样做。\n3、创建文章 # 在 MyBlog 目录下运行命令：\nhugo new post/Articles 01. md\t# 注意这里是 post，也有的是 posts，根据个人安装的主题不同，哪个能够显示文章用哪个。 然后输入启动命令，就可以看到我们新建的文章了，\n4、归档文件 Archives # 将 reimu 文件夹中的 _example 中的 archives 文件复制到 MyBlog 目录下的 content 文件夹中去，\n5、修改侧边栏 sidebar 位置 # 打开目录 MyBlog\\config_default 中的 params.yml，搜索 sidebar ，修改成 left，\n三、自定义配置 # 参考：https://sobaigu.com/hugo-config-structure.html\n1、语言配置 # 在 MyBlog 目录下找到 hugo.toml 文件，\n打开该文件修改语言：\nlanguageCode = \u0026#39;zh-CN\u0026#39;\rdefaultContentLanguage = \u0026#39;zh-CN\u0026#39;\r[languages]\r[languages.zh-CN]\rlanguageName = \u0026#39;简体中文\u0026#39;\rweight = 1\rhasCJKLanguage = true 2、基本结构 # 同原文档操作。\n3、头像 # （1）头像应保存于 static/avatar/avatar.webp，可在 params.yml 中修改文件名：\navatar: \u0026#34;avatar.webp\u0026#34; 拓展：WebP，是一种同时提供了有损压缩与无损压缩的图片文件格式\nparams.yml 的文件路径为 MyBlog\\config\\_default，使用记事本打开 params.yml 后，Ctrl + F 输入 avatar 即可找到，\n修改后，可以看到网页中的头像已经更换成我们自己的图片了：\n4、内置主题配色 # 原装的 reimu 主题配色是红色系，这里我们自定义为自己喜欢的配色，还是找到 MyBlog\\config\\_default 目录下的 params.yml，打开后搜索 internal_theme，修改如下内容：\n这里原来的配色可以自行搜索查看具体颜色，这里给一个链接方便查看：颜色代码转换 - 锤子在线工具\n新的配色可以选择一个主色调，然后使用这个工具来找到系列配色：Deepskyblue／深天藍／#00bfff 十六进制颜色代码表，图表，调色板，绘图\u0026amp;油漆\n我是用的是蓝色系，如下：\n修改完成后，还需要将 MyBlog\\themes\\reimu\\assets 目录中文件复制到 MyBlog\\assets 目录中去，因为其中的 css 文件夹中的 _variables.scss 对应我们刚刚修改的 internal_theme，可以打开来看一下，\n从上图中的红框中的内容，可以明显地知道其对应的就是我们自己修改的颜色。\n写在最后：制作不易，请友友们点赞！收藏！分享！\nDon\u0026rsquo;t be shy, dare to share！ShyShy ！\n","date":"2025-08-11","externalUrl":null,"permalink":"/posts/%E6%96%B0%E6%89%8B%E5%B0%8F%E7%99%BD%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E4%B9%8B-hugo-%E5%85%A5%E9%97%A8/","section":"Posts","summary":"","title":"新手小白个人博客搭建之 Hugo 入门","type":"posts"},{"content":"","date":"2025-04-15","externalUrl":null,"permalink":"/tags/centos/","section":"标签","summary":"","title":"CentOS","type":"tags"},{"content":"","date":"2025-04-15","externalUrl":null,"permalink":"/tags/linux/","section":"标签","summary":"","title":"Linux","type":"tags"},{"content":"","date":"2025-04-15","externalUrl":null,"permalink":"/tags/vmware/","section":"标签","summary":"","title":"VMware","type":"tags"},{"content":"前言：本文主要介绍 CentOS 7 的安装使用，学习过程跟随“老男孩”老师，因此本文也有部分学习笔记可供参考。\n一、创建一个新的虚拟机 # 1、使用快捷键 ctrl+N 会弹出新建虚拟机向导的窗口。\n2、使用自定义，继续下一步，接着默认下一步。\n3、这里选择稍后安装系统，在创建虚拟机后，手动选择镜像或光盘放入虚拟光驱进行安装。\n如果选择“安装程序光盘印象文件”，则会在创建完虚拟机后自动安装系统，虽然方便，但是会增加太多的安装包，并且会自动分区，这样不符合企业环境安装的标准。\n4、这里选择 Linux 系统，版本为“CentOS 7 64 位”，接着下一步。\n5、为虚拟机命名并选择程序安装路径。\n6、配置虚拟机处理器。\n7、为虚拟机选择内存资源的大小。\n8、为虚拟机选择网络类型。\n这里使用 NAT（地址转换）进行网络连接。虚拟机借助 NAT (网络地址转换)功能，通过宿主机所在的网络来访问公网。采用 NAT 模式最大的优势是虚拟系统接入互联网非常简单，你不需要进行任何其他的配置，只需要宿主机器能访问互联网即可。\n参考链接：\n桥接、NAT、Host-only 上网方式的区别-腾讯云开发者社区-腾讯云\n三种连接方式：bridge，NAT,host-only 的区别_hostonly nat-CSDN 博客\n9、选择虚拟机的 I/O 控制器类型，一般使用默认的。\n10、磁盘类型选择推荐的类型。\n11、采用默认的“创建新虚拟磁盘”。\n12、采用默认的 20GB 的大小。\n13、指定磁盘文件存储位置，路径为：I:\\VMwareALL\\clusters\\CentOS_7_OldboyCoreBasis\\CentOS_7_OldboyCoreBasis.vmdk。\n14、检查配置的虚拟机的所有选项信息。点击“自定义硬件”按钮可以进行修改。\n15、创建虚拟机后的界面信息，左边是虚拟机的名称，右边是虚拟机的实际配置。\n16、将 ISO 镜像文件载入光驱\n二、下载 CentOS 系统 ISO 镜像 # 访问 CentOS 的官方站点（不挂梯子） The CentOS Project\n其他国内的下载站点 centos 安装包下载_开源镜像站-阿里云\n三、安装 CentOS 操作系统 # 1、选择系统引导方式 # 共三种方式，选择第一个直接安装\n第三种 Troubleshooting 是系统故障恢复。\n2、修改网卡名为 eth0 的形式，按 Tab 键进入内核参数配置界面，并手动输入如下参数： # net.ifnames=0 biosdevname=0 3、进入图形安装界面，默认选择安装过程的语言为英语。 # 4、进入到安装摘要界面（Installation Summary） # 5、配置系统时区和时间（上海） # 6、选择额外的语言支持 # 7、系统软件包选择，一般选择最小化安装。 # 8、配置网络和主机名，激活右上角的网卡按钮“ON”，然后配置左下角的主机名为“www”。 # 不建议保留默认的“Host name”主机名，设置一个规范的主机名，会显得更加专业。\n9、选择磁盘设备，配置分区。 # 10、按企业生产标准定制磁盘分区，将 LVM 分区改为更优秀的标准分区模式“Standard Partition”。 # Linux 系统磁盘分区知识简介：\n1、磁盘在使用之前一般要先分区（买房分居室）\n2、分区有主分区、扩展分区和逻辑分区。一块磁盘最多可以拥有 4 个分区，其中一个主分区的位置可以用一个扩展分区来替换，在这个扩展分区内可以划分多个逻辑分区。\n3、如果规划的分区数量超过 4 个，则分区组合可为 3primary(p)+1extend(e)或 2p+1e 或 1p+1e。\n4、一块磁盘最多只能有一个扩展分区，扩展分区不能直接使用，必须在扩展分区上划分逻辑分区，然后格式化（创建文件系统)，之后才能存取数据或装系统。\n磁盘分区命名及编号方式：\n（1）以设备名命名 在 Linux 系统中，磁盘设备对应于系统中的特殊文件，这些特殊的文件放在“/dev”目录中，不同的设备对应的设备名称具体如下。 *系统的第一块 IDE 接口的硬盘称为/dev/hda。 *系统的第二块 IDE 接口的硬盘称为/dev/hdb。\n*系统的第一块 SCSI 接口的硬盘称为/dev/sda ​ *系统的第二块 SCSI 接口的硬盘称为/dev/sdb。 （2）使用数字编号 ​ 为了表示不同的分区，通常会使用数字进行编号，比如如下示例名称。 ​ *系统的第一块 IDE 接口硬盘的第 1 个分区称为/dev/hda1 ​ *系统的第一块 IDE 接口硬盘的第 5 个分区称为/dev/hda5 ​ *系统的第二块 SCSI 接口硬盘的第 1 个分区称为/dev/sdb1。 ​ *系统的第二块 SCSI 接口硬盘的第 5 个分区称为/dev/sdb5 ​ 需要注意的是，在对分区进行编号时，数字 1~4 只能留给主分区或扩展分区使用， 逻辑分区(在扩展分区基础之上）的编号只能从 5 开始。 ​ 在对 Linux 系统设置了分区之后，还要在分区上创建文件系统才能安装系统，这个在安装时可由系统自行完成创建。\nLinux 系统对分区的基本要求 1）最少要有一个根（ / ）分区，用来存放系统文件及程序。其大小至少在 5GB 以上。\n2）要有一个 swap（交换）分区， 它的作用相当于 Windows 里的虚拟内存，swap 分区的大小一般为物理内存容量的 1.5 倍(内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时， 则对 swap 分区配置 8-16GB 即可， 太大无用，浪费磁盘空间。swap 分区不是必须的, 但是大多数情况下还是设置一下比较好，个别企业的数据库应用场景不分 swap 。\n3）/boot 分区，这是 Linux 系统的引导分区，用于存放系统引导文件， 如 Linux 内核等。对于 CentOS7 而言，其要比以前的版本大一些。因此， 该分区可以设置为 1024MB,这个分区也不是必须的。\n企业生产场景中 Linux 系统的分区方案 常规的分区方案如下。 方案 1：针对网站集群架构中的某个节点服务器分区，该服务器上的数据包含多份（其他节点也有）且数据不太重要，建议的分区方案如下。\n/boot: 设置为 512~1024MB\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 剩余硬盘空间大小(/usr、/home、/var 等分区和“ / ”共用一个分区，这就相当于是在 Windows 系统中只有一个 C 盘一样，所有数据和系统文件都存放在一起)。\n方案 2: 针对数据库及存储角色的服务器分区，该服务器的业务包含了大量重要的数据，建议分区方案如下。\n/boot: 设置为 512~1024MB。\n/: 大小设置为 50-200GB,只存放系统相关文件，网站等的业务数据不放在这里。\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时，分配 8~16GB 即可。\n/data:剩余硬盘空间大小，存放数据库及存储服务等重要数据。当然,data 的名称也可以换成别的名字。\n本方案其实就是将重要数据单独分区,以便于备份和管理。\n方案 3: 针对大网站或门户级别企业的服务器进行分区 /boot: 大小设置为 512~1024MB。\n/swap: 物理内存的 1.5 倍，当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 大小设置为 50~200GB,只存放系统相关文件,网站等的业务数据不放在这里。\n保留剩余的磁盘空间，不再进行分区，将来分配给不同的使用部门，由他们自己根据需求再分!\n此种分区方案更灵活，比较适合业务线比较多且需求不确定的大企业使用。 对于分区，有网友还给出了如下的方案:\n/boot、swap、/、/usr、/home、/var\n这种分区方案的特点是典型的没有主见的被动式的分区,分了太多的额外分区(/usr、/home、/var)，没有必要不说，管理起来也更麻烦了， 这就类似于一个家庭就 2~3 口人，买了 100 平米的房子，却非要隔成好几个房间是一个道理的， 笔者极不推荐这样的分区方案。\n如果说是怕某个分区满了会影响系统运行，那么这样的分区想法就更错了。第一， 硬盘空间是固定的，分区多了，比只分一个区肯定更容易满；第二，在企业应用里业务不可用和服务器宕机的危害几乎差不多，因此，分区少一些，然后对所有分区进行监控报警，这是目前大多数规范企业的选择。\n本文采用常规的服务器分区方案，即分为/boot、swap、/ 三个分区，注意分区的先后顺序。\n11、开始增加分区 # Mount Point（挂载点）是 Linux 下访问磁盘分区的入口，往 /boot 分区（ /dev/sda1 ）里写入数据，则必须通过 /boot 入口来写入。\n**Linux 文件系统类型：**xfs 作为 CentOS 7 中的默认文件系统类型替代了 CentOS 6 中默认使用的 ext4。\nswap：内存交换空间。由于 swap 并不会使用到目录树的挂载，因此不需要指定挂载点。\n搞懂 Linux 文件系统，99%的操作不求人_linux 文件系统-CSDN 博客\nswap 分区配置说明 1）swap 分区不配置 Mount point 挂载点,swap 不需要人为访问,交给系统自动处理即可。 2）swap 分区的大小一般为物理内存容量的 1.5 倍（内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时，swap 分区配置 8-16GB 即可,太大无用,还会浪费磁盘空间。 3）如果是学习环境，为了节省空间，swap 设置得小一点也没有问题。\n**注意：**Linux 系统分区时，常规的分区方案为“/”、/boot、swap，其中 swap 不是挂载点（ “/”、/boot 都是挂载点)，而是分区类型，类似 ext4 的一个文件系统，如果在挂载点输入框处输入 /swap 创建 swap 分区那就错了。\n分区设置后的提示界面，注意分区的顺序是：/boot、swap、/\n提示: 这里采用的是生产环境中集群节点下的节点服务器的分区方式， 即系统坏掉后硬盘数据不需要保留。此分区方式也适合用于大多数生产环境的服务器， 如果是数据库以及存储等有重要数据的特殊业务服务, 那么一般会单独划分存放数据的分区如“/data” 。\n除了/boot、swap 和“/”三个分区外，还可以加/usr、/home、 /var 等分区,具体情况需要根据服务器的需求来决定，一般情况下，只配置这三个分区就足够了。\n这种分区方案最大的优点就是简单，使用方便，可批量安装部署， 而且不会存在有的分区满了， 有的分区还剩余了很多空间又不能被利用的情况(LVM 的情况这里我们先不阐述)。\n该分区方案的缺点是:如果系统坏了，那么重新装系统时， 因为数据都在“/”(根) 分区，这就导致了数据备份很麻烦；如果设置了/usr、 /home、/var 等分区，那么即使系统出了故障,也可以直接在“/”(根）分区装系统,这样并不会破坏其他分区的数据。当然,刚才也说了,如果是不存在备份数据的集群节点,那么采用这种分区方案就是很明智的，不用特别担心某个分区爆满的问题。\n12、开始系统安装 # 设置管理员 root安全密码\n这里的登陆账户名是：root\n13、系统安装后的基本配置 # 登录界面中的英文内容为 CentOS 的版本以及内核的当前版本。显示的 www 为主机名，login 为登陆提示。\n当前 Linux 内核版本号为：\n这里的“＃”为超级管理员 root 输入命令的提示符。\n配置网卡设置网络联网\n这里已经事先在前面的安装步骤设置完成。\n故障排除方法：\na、查看网卡信息\nip add 该命令是 Linux 系统中用于显示和管理网络接口地址的命令之一。它可以列出系统中所有的网络接口，包括物理网卡和虚拟网卡，并显示其 IP 地址、MAC 地址、网关、网络掩码等信息。\nb、查看网卡配置文件以及网卡配置项的含义：\ncat /etc/sysconfig/network-scripts/ifcfg-ens33 c、重启网卡的命令\nsystemctl restart network 查看默认网关设置的命令\nip route 查看 DNS 设置的命令\ncat /etc/resolv.conf 14、使用 VMware 为新系统创建快照 # 创建快照的目的是将来能将系统随时还原到做快照时候的系统状态。关闭系统后再创建快照，可以节省磁盘空间。\n15、更新系统打补丁到最新 # yum 是 Linux 下安装软件的优秀工具，是 CentOS Linux 下最好用的包管理器和安装软件包的工具，用起来很方便。Linux 的二进制软件包一般是 rpm 包，类似于 windows 下的 exe 程序。需要将默认获取 rpm 包的地址改成国内的 yum 源地址。\n参考：CentOS 停服后如何配置国内 yum 源镜像 | 丰盘 ECM 帮助中心\n先备份系统原始 yum 源配置文件\n将系统内置或手工配置的 yum 源配置文件移动至至新的目录，例如 /etc/yum.repos.d/bak240712/ ，这样后续如果想恢复或者重置也比较方便。注意，如果不移走的话，最后步骤「重建本地缓存」的时候，有可能会受到老配置文件的影响而失败。\n# 创建备份文件夹（sudo使用的是root权限，root登陆状态下可以省略）\rsudo mkdir -p /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;)\r# 将源配置移动至备份文件夹\rsudo mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;) 修改更新 yum 源的命令为：\ncurl -s -o /etc/yum.repos.d/Centos-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 下载 epel 源配置文件。\ncurl -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 运行一下两行命令重建本地缓存即可生效\nyum clean all \u0026amp;\u0026amp; yum makecache 测试安装软件包是否正常\nyum install curl wget 使用如下命令将系统更新到最新状态：\nyum update -y （也可以使用 yum upgrade -y） 16、额外安装一些有用的软件包 # CentOS 6 和 CentOS 7 都要安装的企业运维常用的基础工具包：\nyum install tree nmap dos2unix lrzsz nc lsof wget tcpdump htop iftop iotop sysstat nethogs -y centos 7 需要安装的企业运维常用的基础工具包：\nyum install psmisc net-tools bash-completiom vim-enhanced -y 四、远程连接管理 Linux # **IDC 机房：**互联网数据中心（Internet Data Center）简称 IDC，就是电信部门利用已有的互联网通信线路、带宽资源，建立标准化的电信专业级机房环境，为企业、政府提供服务器托管、租用以及相关增值等方面的全方位服务。\n遇到的问题：远程 ssh 服务器拒绝了 x11 转发请求,彻底解决用 Xshell 连接 linux ssh 时出现“The remote SSH server rejected X11 forwarding request”的\u0026hellip;-CSDN 博客\n1、远程连接 Linux 的原理 # 在互联网企业环境中，最常用的提供 Linux 远程连接服务的工具是 SSH 软件，其又分为 SSH 客户端和 SSH 服务端两部分。SSH 服务端包含的软件程序主要有 openssh (提供 SSH 服务的程序）和 openssl（为 SSH 提供连接加密的程序）。在 Linux 系统中查询 SSH 服务端工具的命令为：\nrpm -qa openssh openssl 启动 Linux 系统时，默认启动 SSH 服务器端程序，其是一个守护进程（daemon），在系统后台永久运行并时刻响应来自所有 SSH 客户端的连接请求。SSH 服务端的进程名为 sshd，负责实时监听远程 SSH 客户端的连接请求并进行处理，包括公共密钥认证、密钥交换、对称密钥加密和非安全连接等。SSH 服务是 Linux 系统优化时需要保留开机自启动的服务之一。\n最常用的 SSH 客户端是 windows 平台上运行的 SecureCRT。另外还有 Xshell、putty 以及 Linux 下的 SSH 等客户端软件。\nSSH 服务端和客户端之间的交流是通过 SSH 协议（Secure Shell Protocol）来实现的。在进行数据传输之前，SSH 通过加密技术对联机数据包进行加密处理，再进行数据传输，这样就可以确保传递的数据安全。SSH 是专为远程登陆会话和其他网络服务提供的安全性协议，利用该协议可以有效防止远程管理中的信息泄露。\nSSH 协议有两个不兼容的版本，分别是 SSH 1.x 和 SSH 2.x。openssh 同时支持 SSH 1.x 和 SSH 2.x。SSH 2.x 比 SSH 1.x 更安全，默认情况下服务端通过 SSH 2.x 协议提供服务。\n2、工具的选择 # 根据实际情况决定，Xshell 一般更适合个人和学生学习使用。SecureCRT 应用时间更久，简单，用户基数大，但是收费。\n参考：Linux 服务器远程工具选择 SecureCRT 还是 Xshell 对比-腾讯云开发者社区-腾讯云\nXshell 安装说明\n用户界面如下\n点击工具栏中的第一个“+”号按钮，需要先查询到本机的 IP 地址。\n点击连接后会弹出的界面如下\n点击“接受并保存”后输入登陆用户名（超级管理员 root）\n保存登陆密码，自动验证登录。\n3、调整 Xshell 里的设置 # 4、配置记录 SSH 操作日志及输出 # 日志文件保存路径：I:\\SSH%n*%Y-%m-%d*%t.log\n5、配置本地机器上传下载目录 # 上传和下载的路径可以设置为同一个，当所选择的路径必须存在于系统中。\n设置完毕后，可以通过 Xshell 连接的 Linux 命令行经由 rz 上传文件到 Linux 系统，通过“sz 文件名”即可下载文件到上述配置的路径里，从而实现客户端电脑和 Linux 主机的文件传输。\na、rz、sz 命令的安装方法 # 第一种：安装系统时选择包含 rz、sz 命令的包组“Dial-up Networking Support”\n第二种：安装系统后，通过执行 yum install lrzsz -y 或者 yum groupinstall “Dial-up Networking Support” -y 命令来安装。\nb、上传命令 rz # 输入 rz -y 命令可以覆盖本地的同名内容，执行后会打开一个上传文件的窗口，从这个窗口找到所需文件（客户端电脑上的）进行上传到 Linux 系统。\nc、下载命令 sz # 执行命令 “sz -y filename”可以覆盖本地的同名内容进行下载，filename 是命令行 Linux 主机当前目录下的文件。默认的客户端下载路径就是先前设置的下载路径地址 I:\\SSH\\download\nd、注意事项 # 只能上传和下载文件而不是目录，如果是目录则需要打包成文件。\n上传文件是，不要勾选最下方的“以 ASCII 方式上传文件”。\ne、其他工具 # 还可以使用 ftp、sftp、winscp 等工具来传输文件。\n6、批量部署和管理 # 首先确保所有的标签是在同一个 Xshell 窗口中打开的。\n然后，在任一个窗口中，右键选择最后一个选项\u0026quot;发送键输入到所有会话\u0026quot;\n开启批量输入模式后，操作批量管理命令：\n小规模批量部署或执行任务的服务器为数十台，可以使用 Xshell 的这个小功能。大规模服务器数量的部署，可以使用 ansiable 等批量管理工具。\n7、配置 Xshell 标签路径 # 通过“工具”里面的“选项”指定一个新的配置目录来实现备份\n8、配置标签模版 # 方法 1：对一个已经配置更好的标签实施复制、粘贴来新建标签，这样它就继承了老标签的配置。只需要再修改相应的特殊配置即可，如 IP、会话名字等。\n方法 2：在全局选项里配置各种功能设置。\n9、SSH 远程连接故障排查 # a、首先查看远端服务是否正常。 # 利用 ping 命令检查（客户端执行，也就是客户端电脑 DOS 命令行或者 Xshell 界面）\nDOS 是 Disk Operating System 的缩写，意为“磁盘操作系统”。\nWin 键+R，输入 cmd，回车，直接进入 dos 界面。\n在任意文件夹下面，按住 shift 键+鼠标右键，点击 Powershell 界面，即可进入 dos 界面。\n参考：DOS 操作系统详解：打开及基本指令指南-CSDN 博客\nping 192.168.120.129 b、检查 firewalld 等防火墙策略是否阻挡了连接(服务端执行) # systemctl status firewalld c、利用 telnet 或 nmap 命令检查（客户端执行） # telnet 192.168.120.129 22\r或\rnmap 192.168.120.129 -p 22 参考：(26 封私信 / 52 条消息) 两步解决 yum 无法安装软件问题：Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 - 知乎\ntelnet 卡住了，键盘敲 CTRL+]，然后输入 quit\nd、系统中的 SSHD 服务是否正常开启，端口是否正确 # netstat 是一个用于监控 TCP/IP 网络的命令行工具，它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。在 CentOS 7 系统中，netstat 命令通常已经作为系统必备的网络工具包的一部分存在了，不需要额外安装。\nnetstat -Intup | grep sshd 参考：CentOS 7 下轻松安装与配置 netstat 命令详解 - 云原生实践\n检查 netstat 是否已经安装：\n使用 yum 安装 net-tools:\nsudo yum install net-tools 安装完成后进行检查\n五、克隆 VMware 下的虚拟机 # 对于完成配置操作的 Linux 主机，进行快照，可以当作模版机（temp）永久保留。\n关闭当前模版机后，右键左边菜单栏的模版机标签，选择“管理”项进行克隆。\n克隆的虚拟机信息，\n","date":"2025-04-15","externalUrl":null,"permalink":"/archives/vmware-workstation-%E5%AE%89%E8%A3%85%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%8C%87%E5%8D%97/","section":"历史文档","summary":"","title":"VMware Workstation 安装虚拟机指南","type":"archives"},{"content":"前言：本文主要介绍 CentOS 7 的安装使用，学习过程跟随“老男孩”老师，因此本文也有部分学习笔记可供参考。\n一、创建一个新的虚拟机 # 1、使用快捷键 ctrl+N 会弹出新建虚拟机向导的窗口。\n2、使用自定义，继续下一步，接着默认下一步。\n3、这里选择稍后安装系统，在创建虚拟机后，手动选择镜像或光盘放入虚拟光驱进行安装。\n如果选择“安装程序光盘印象文件”，则会在创建完虚拟机后自动安装系统，虽然方便，但是会增加太多的安装包，并且会自动分区，这样不符合企业环境安装的标准。\n4、这里选择 Linux 系统，版本为“CentOS 7 64 位”，接着下一步。\n5、为虚拟机命名并选择程序安装路径。\n6、配置虚拟机处理器。\n7、为虚拟机选择内存资源的大小。\n8、为虚拟机选择网络类型。\n这里使用 NAT（地址转换）进行网络连接。虚拟机借助 NAT (网络地址转换)功能，通过宿主机所在的网络来访问公网。采用 NAT 模式最大的优势是虚拟系统接入互联网非常简单，你不需要进行任何其他的配置，只需要宿主机器能访问互联网即可。\n参考链接：\n桥接、NAT、Host-only 上网方式的区别-腾讯云开发者社区-腾讯云\n三种连接方式：bridge，NAT,host-only 的区别_hostonly nat-CSDN 博客\n9、选择虚拟机的 I/O 控制器类型，一般使用默认的。\n10、磁盘类型选择推荐的类型。\n11、采用默认的“创建新虚拟磁盘”。\n12、采用默认的 20GB 的大小。\n13、指定磁盘文件存储位置，路径为：I:\\VMwareALL\\clusters\\CentOS_7_OldboyCoreBasis\\CentOS_7_OldboyCoreBasis.vmdk。\n14、检查配置的虚拟机的所有选项信息。点击“自定义硬件”按钮可以进行修改。\n15、创建虚拟机后的界面信息，左边是虚拟机的名称，右边是虚拟机的实际配置。\n16、将 ISO 镜像文件载入光驱\n二、下载 CentOS 系统 ISO 镜像 # 访问 CentOS 的官方站点（不挂梯子） The CentOS Project\n其他国内的下载站点 centos 安装包下载_开源镜像站-阿里云\n三、安装 CentOS 操作系统 # 1、选择系统引导方式 # 共三种方式，选择第一个直接安装\n第三种 Troubleshooting 是系统故障恢复。\n2、修改网卡名为 eth0 的形式，按 Tab 键进入内核参数配置界面，并手动输入如下参数： # net.ifnames=0 biosdevname=0 3、进入图形安装界面，默认选择安装过程的语言为英语。 # 4、进入到安装摘要界面（Installation Summary） # 5、配置系统时区和时间（上海） # 6、选择额外的语言支持 # 7、系统软件包选择，一般选择最小化安装。 # 8、配置网络和主机名，激活右上角的网卡按钮“ON”，然后配置左下角的主机名为“www”。 # 不建议保留默认的“Host name”主机名，设置一个规范的主机名，会显得更加专业。\n9、选择磁盘设备，配置分区。 # 10、按企业生产标准定制磁盘分区，将 LVM 分区改为更优秀的标准分区模式“Standard Partition”。 # Linux 系统磁盘分区知识简介：\n1、磁盘在使用之前一般要先分区（买房分居室）\n2、分区有主分区、扩展分区和逻辑分区。一块磁盘最多可以拥有 4 个分区，其中一个主分区的位置可以用一个扩展分区来替换，在这个扩展分区内可以划分多个逻辑分区。\n3、如果规划的分区数量超过 4 个，则分区组合可为 3primary(p)+1extend(e)或 2p+1e 或 1p+1e。\n4、一块磁盘最多只能有一个扩展分区，扩展分区不能直接使用，必须在扩展分区上划分逻辑分区，然后格式化（创建文件系统)，之后才能存取数据或装系统。\n磁盘分区命名及编号方式：\n（1）以设备名命名 在 Linux 系统中，磁盘设备对应于系统中的特殊文件，这些特殊的文件放在“/dev”目录中，不同的设备对应的设备名称具体如下。 *系统的第一块 IDE 接口的硬盘称为/dev/hda。 *系统的第二块 IDE 接口的硬盘称为/dev/hdb。\n*系统的第一块 SCSI 接口的硬盘称为/dev/sda ​ *系统的第二块 SCSI 接口的硬盘称为/dev/sdb。 （2）使用数字编号 ​ 为了表示不同的分区，通常会使用数字进行编号，比如如下示例名称。 ​ *系统的第一块 IDE 接口硬盘的第 1 个分区称为/dev/hda1 ​ *系统的第一块 IDE 接口硬盘的第 5 个分区称为/dev/hda5 ​ *系统的第二块 SCSI 接口硬盘的第 1 个分区称为/dev/sdb1。 ​ *系统的第二块 SCSI 接口硬盘的第 5 个分区称为/dev/sdb5 ​ 需要注意的是，在对分区进行编号时，数字 1~4 只能留给主分区或扩展分区使用， 逻辑分区(在扩展分区基础之上）的编号只能从 5 开始。 ​ 在对 Linux 系统设置了分区之后，还要在分区上创建文件系统才能安装系统，这个在安装时可由系统自行完成创建。\nLinux 系统对分区的基本要求 1）最少要有一个根（ / ）分区，用来存放系统文件及程序。其大小至少在 5GB 以上。\n2）要有一个 swap（交换）分区， 它的作用相当于 Windows 里的虚拟内存，swap 分区的大小一般为物理内存容量的 1.5 倍(内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时， 则对 swap 分区配置 8-16GB 即可， 太大无用，浪费磁盘空间。swap 分区不是必须的, 但是大多数情况下还是设置一下比较好，个别企业的数据库应用场景不分 swap 。\n3）/boot 分区，这是 Linux 系统的引导分区，用于存放系统引导文件， 如 Linux 内核等。对于 CentOS7 而言，其要比以前的版本大一些。因此， 该分区可以设置为 1024MB,这个分区也不是必须的。\n企业生产场景中 Linux 系统的分区方案 常规的分区方案如下。 方案 1：针对网站集群架构中的某个节点服务器分区，该服务器上的数据包含多份（其他节点也有）且数据不太重要，建议的分区方案如下。\n/boot: 设置为 512~1024MB\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 剩余硬盘空间大小(/usr、/home、/var 等分区和“ / ”共用一个分区，这就相当于是在 Windows 系统中只有一个 C 盘一样，所有数据和系统文件都存放在一起)。\n方案 2: 针对数据库及存储角色的服务器分区，该服务器的业务包含了大量重要的数据，建议分区方案如下。\n/boot: 设置为 512~1024MB。\n/: 大小设置为 50-200GB,只存放系统相关文件，网站等的业务数据不放在这里。\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时，分配 8~16GB 即可。\n/data:剩余硬盘空间大小，存放数据库及存储服务等重要数据。当然,data 的名称也可以换成别的名字。\n本方案其实就是将重要数据单独分区,以便于备份和管理。\n方案 3: 针对大网站或门户级别企业的服务器进行分区 /boot: 大小设置为 512~1024MB。\n/swap: 物理内存的 1.5 倍，当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 大小设置为 50~200GB,只存放系统相关文件,网站等的业务数据不放在这里。\n保留剩余的磁盘空间，不再进行分区，将来分配给不同的使用部门，由他们自己根据需求再分!\n此种分区方案更灵活，比较适合业务线比较多且需求不确定的大企业使用。 对于分区，有网友还给出了如下的方案:\n/boot、swap、/、/usr、/home、/var\n这种分区方案的特点是典型的没有主见的被动式的分区,分了太多的额外分区(/usr、/home、/var)，没有必要不说，管理起来也更麻烦了， 这就类似于一个家庭就 2~3 口人，买了 100 平米的房子，却非要隔成好几个房间是一个道理的， 笔者极不推荐这样的分区方案。\n如果说是怕某个分区满了会影响系统运行，那么这样的分区想法就更错了。第一， 硬盘空间是固定的，分区多了，比只分一个区肯定更容易满；第二，在企业应用里业务不可用和服务器宕机的危害几乎差不多，因此，分区少一些，然后对所有分区进行监控报警，这是目前大多数规范企业的选择。\n本文采用常规的服务器分区方案，即分为/boot、swap、/ 三个分区，注意分区的先后顺序。\n11、开始增加分区 # Mount Point（挂载点）是 Linux 下访问磁盘分区的入口，往 /boot 分区（ /dev/sda1 ）里写入数据，则必须通过 /boot 入口来写入。\n**Linux 文件系统类型：**xfs 作为 CentOS 7 中的默认文件系统类型替代了 CentOS 6 中默认使用的 ext4。\nswap：内存交换空间。由于 swap 并不会使用到目录树的挂载，因此不需要指定挂载点。\n搞懂 Linux 文件系统，99%的操作不求人_linux 文件系统-CSDN 博客\nswap 分区配置说明 1）swap 分区不配置 Mount point 挂载点,swap 不需要人为访问,交给系统自动处理即可。 2）swap 分区的大小一般为物理内存容量的 1.5 倍（内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时，swap 分区配置 8-16GB 即可,太大无用,还会浪费磁盘空间。 3）如果是学习环境，为了节省空间，swap 设置得小一点也没有问题。\n**注意：**Linux 系统分区时，常规的分区方案为“/”、/boot、swap，其中 swap 不是挂载点（ “/”、/boot 都是挂载点)，而是分区类型，类似 ext4 的一个文件系统，如果在挂载点输入框处输入 /swap 创建 swap 分区那就错了。\n分区设置后的提示界面，注意分区的顺序是：/boot、swap、/\n提示: 这里采用的是生产环境中集群节点下的节点服务器的分区方式， 即系统坏掉后硬盘数据不需要保留。此分区方式也适合用于大多数生产环境的服务器， 如果是数据库以及存储等有重要数据的特殊业务服务, 那么一般会单独划分存放数据的分区如“/data” 。\n除了/boot、swap 和“/”三个分区外，还可以加/usr、/home、 /var 等分区,具体情况需要根据服务器的需求来决定，一般情况下，只配置这三个分区就足够了。\n这种分区方案最大的优点就是简单，使用方便，可批量安装部署， 而且不会存在有的分区满了， 有的分区还剩余了很多空间又不能被利用的情况(LVM 的情况这里我们先不阐述)。\n该分区方案的缺点是:如果系统坏了，那么重新装系统时， 因为数据都在“/”(根) 分区，这就导致了数据备份很麻烦；如果设置了/usr、 /home、/var 等分区，那么即使系统出了故障,也可以直接在“/”(根）分区装系统,这样并不会破坏其他分区的数据。当然,刚才也说了,如果是不存在备份数据的集群节点,那么采用这种分区方案就是很明智的，不用特别担心某个分区爆满的问题。\n12、开始系统安装 # 设置管理员 root安全密码\n这里的登陆账户名是：root\n13、系统安装后的基本配置 # 登录界面中的英文内容为 CentOS 的版本以及内核的当前版本。显示的 www 为主机名，login 为登陆提示。\n当前 Linux 内核版本号为：\n这里的“＃”为超级管理员 root 输入命令的提示符。\n配置网卡设置网络联网\n这里已经事先在前面的安装步骤设置完成。\n故障排除方法：\na、查看网卡信息\nip add 该命令是 Linux 系统中用于显示和管理网络接口地址的命令之一。它可以列出系统中所有的网络接口，包括物理网卡和虚拟网卡，并显示其 IP 地址、MAC 地址、网关、网络掩码等信息。\nb、查看网卡配置文件以及网卡配置项的含义：\ncat /etc/sysconfig/network-scripts/ifcfg-ens33 c、重启网卡的命令\nsystemctl restart network 查看默认网关设置的命令\nip route 查看 DNS 设置的命令\ncat /etc/resolv.conf 14、使用 VMware 为新系统创建快照 # 创建快照的目的是将来能将系统随时还原到做快照时候的系统状态。关闭系统后再创建快照，可以节省磁盘空间。\n15、更新系统打补丁到最新 # yum 是 Linux 下安装软件的优秀工具，是 CentOS Linux 下最好用的包管理器和安装软件包的工具，用起来很方便。Linux 的二进制软件包一般是 rpm 包，类似于 windows 下的 exe 程序。需要将默认获取 rpm 包的地址改成国内的 yum 源地址。\n参考：CentOS 停服后如何配置国内 yum 源镜像 | 丰盘 ECM 帮助中心\n先备份系统原始 yum 源配置文件\n将系统内置或手工配置的 yum 源配置文件移动至至新的目录，例如 /etc/yum.repos.d/bak240712/ ，这样后续如果想恢复或者重置也比较方便。注意，如果不移走的话，最后步骤「重建本地缓存」的时候，有可能会受到老配置文件的影响而失败。\n# 创建备份文件夹（sudo使用的是root权限，root登陆状态下可以省略）\rsudo mkdir -p /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;)\r# 将源配置移动至备份文件夹\rsudo mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;) 修改更新 yum 源的命令为：\ncurl -s -o /etc/yum.repos.d/Centos-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 下载 epel 源配置文件。\ncurl -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 运行一下两行命令重建本地缓存即可生效\nyum clean all \u0026amp;\u0026amp; yum makecache 测试安装软件包是否正常\nyum install curl wget 使用如下命令将系统更新到最新状态：\nyum update -y （也可以使用 yum upgrade -y） 16、额外安装一些有用的软件包 # CentOS 6 和 CentOS 7 都要安装的企业运维常用的基础工具包：\nyum install tree nmap dos2unix lrzsz nc lsof wget tcpdump htop iftop iotop sysstat nethogs -y centos 7 需要安装的企业运维常用的基础工具包：\nyum install psmisc net-tools bash-completiom vim-enhanced -y 四、远程连接管理 Linux # **IDC 机房：**互联网数据中心（Internet Data Center）简称 IDC，就是电信部门利用已有的互联网通信线路、带宽资源，建立标准化的电信专业级机房环境，为企业、政府提供服务器托管、租用以及相关增值等方面的全方位服务。\n遇到的问题：远程 ssh 服务器拒绝了 x11 转发请求,彻底解决用 Xshell 连接 linux ssh 时出现“The remote SSH server rejected X11 forwarding request”的\u0026hellip;-CSDN 博客\n1、远程连接 Linux 的原理 # 在互联网企业环境中，最常用的提供 Linux 远程连接服务的工具是 SSH 软件，其又分为 SSH 客户端和 SSH 服务端两部分。SSH 服务端包含的软件程序主要有 openssh (提供 SSH 服务的程序）和 openssl（为 SSH 提供连接加密的程序）。在 Linux 系统中查询 SSH 服务端工具的命令为：\nrpm -qa openssh openssl 启动 Linux 系统时，默认启动 SSH 服务器端程序，其是一个守护进程（daemon），在系统后台永久运行并时刻响应来自所有 SSH 客户端的连接请求。SSH 服务端的进程名为 sshd，负责实时监听远程 SSH 客户端的连接请求并进行处理，包括公共密钥认证、密钥交换、对称密钥加密和非安全连接等。SSH 服务是 Linux 系统优化时需要保留开机自启动的服务之一。\n最常用的 SSH 客户端是 windows 平台上运行的 SecureCRT。另外还有 Xshell、putty 以及 Linux 下的 SSH 等客户端软件。\nSSH 服务端和客户端之间的交流是通过 SSH 协议（Secure Shell Protocol）来实现的。在进行数据传输之前，SSH 通过加密技术对联机数据包进行加密处理，再进行数据传输，这样就可以确保传递的数据安全。SSH 是专为远程登陆会话和其他网络服务提供的安全性协议，利用该协议可以有效防止远程管理中的信息泄露。\nSSH 协议有两个不兼容的版本，分别是 SSH 1.x 和 SSH 2.x。openssh 同时支持 SSH 1.x 和 SSH 2.x。SSH 2.x 比 SSH 1.x 更安全，默认情况下服务端通过 SSH 2.x 协议提供服务。\n2、工具的选择 # 根据实际情况决定，Xshell 一般更适合个人和学生学习使用。SecureCRT 应用时间更久，简单，用户基数大，但是收费。\n参考：Linux 服务器远程工具选择 SecureCRT 还是 Xshell 对比-腾讯云开发者社区-腾讯云\nXshell 安装说明\n用户界面如下\n点击工具栏中的第一个“+”号按钮，需要先查询到本机的 IP 地址。\n点击连接后会弹出的界面如下\n点击“接受并保存”后输入登陆用户名（超级管理员 root）\n保存登陆密码，自动验证登录。\n3、调整 Xshell 里的设置 # 4、配置记录 SSH 操作日志及输出 # 日志文件保存路径：I:\\SSH%n*%Y-%m-%d*%t.log\n5、配置本地机器上传下载目录 # 上传和下载的路径可以设置为同一个，当所选择的路径必须存在于系统中。\n设置完毕后，可以通过 Xshell 连接的 Linux 命令行经由 rz 上传文件到 Linux 系统，通过“sz 文件名”即可下载文件到上述配置的路径里，从而实现客户端电脑和 Linux 主机的文件传输。\na、rz、sz 命令的安装方法 # 第一种：安装系统时选择包含 rz、sz 命令的包组“Dial-up Networking Support”\n第二种：安装系统后，通过执行 yum install lrzsz -y 或者 yum groupinstall “Dial-up Networking Support” -y 命令来安装。\nb、上传命令 rz # 输入 rz -y 命令可以覆盖本地的同名内容，执行后会打开一个上传文件的窗口，从这个窗口找到所需文件（客户端电脑上的）进行上传到 Linux 系统。\nc、下载命令 sz # 执行命令 “sz -y filename”可以覆盖本地的同名内容进行下载，filename 是命令行 Linux 主机当前目录下的文件。默认的客户端下载路径就是先前设置的下载路径地址 I:\\SSH\\download\nd、注意事项 # 只能上传和下载文件而不是目录，如果是目录则需要打包成文件。\n上传文件是，不要勾选最下方的“以 ASCII 方式上传文件”。\ne、其他工具 # 还可以使用 ftp、sftp、winscp 等工具来传输文件。\n6、批量部署和管理 # 首先确保所有的标签是在同一个 Xshell 窗口中打开的。\n然后，在任一个窗口中，右键选择最后一个选项\u0026quot;发送键输入到所有会话\u0026quot;\n开启批量输入模式后，操作批量管理命令：\n小规模批量部署或执行任务的服务器为数十台，可以使用 Xshell 的这个小功能。大规模服务器数量的部署，可以使用 ansiable 等批量管理工具。\n7、配置 Xshell 标签路径 # 通过“工具”里面的“选项”指定一个新的配置目录来实现备份\n8、配置标签模版 # 方法 1：对一个已经配置更好的标签实施复制、粘贴来新建标签，这样它就继承了老标签的配置。只需要再修改相应的特殊配置即可，如 IP、会话名字等。\n方法 2：在全局选项里配置各种功能设置。\n9、SSH 远程连接故障排查 # a、首先查看远端服务是否正常。 # 利用 ping 命令检查（客户端执行，也就是客户端电脑 DOS 命令行或者 Xshell 界面）\nDOS 是 Disk Operating System 的缩写，意为“磁盘操作系统”。\nWin 键+R，输入 cmd，回车，直接进入 dos 界面。\n在任意文件夹下面，按住 shift 键+鼠标右键，点击 Powershell 界面，即可进入 dos 界面。\n参考：DOS 操作系统详解：打开及基本指令指南-CSDN 博客\nping 192.168.120.129 b、检查 firewalld 等防火墙策略是否阻挡了连接(服务端执行) # systemctl status firewalld c、利用 telnet 或 nmap 命令检查（客户端执行） # telnet 192.168.120.129 22\r或\rnmap 192.168.120.129 -p 22 参考：(26 封私信 / 52 条消息) 两步解决 yum 无法安装软件问题：Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 - 知乎\ntelnet 卡住了，键盘敲 CTRL+]，然后输入 quit\nd、系统中的 SSHD 服务是否正常开启，端口是否正确 # netstat 是一个用于监控 TCP/IP 网络的命令行工具，它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。在 CentOS 7 系统中，netstat 命令通常已经作为系统必备的网络工具包的一部分存在了，不需要额外安装。\nnetstat -Intup | grep sshd 参考：CentOS 7 下轻松安装与配置 netstat 命令详解 - 云原生实践\n检查 netstat 是否已经安装：\n使用 yum 安装 net-tools:\nsudo yum install net-tools 安装完成后进行检查\n五、克隆 VMware 下的虚拟机 # 对于完成配置操作的 Linux 主机，进行快照，可以当作模版机（temp）永久保留。\n关闭当前模版机后，右键左边菜单栏的模版机标签，选择“管理”项进行克隆。\n克隆的虚拟机信息，\n","date":"2025-04-15","externalUrl":null,"permalink":"/naivelearnings/vmware-workstation-%E5%AE%89%E8%A3%85%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%8C%87%E5%8D%97/","section":"新手入门教程集合","summary":"","title":"VMware Workstation 安装虚拟机指南","type":"naivelearnings"},{"content":"前言：本文主要介绍 CentOS 7 的安装使用，学习过程跟随“老男孩”老师，因此本文也有部分学习笔记可供参考。\n一、创建一个新的虚拟机 # 1、使用快捷键 ctrl+N 会弹出新建虚拟机向导的窗口。\n2、使用自定义，继续下一步，接着默认下一步。\n3、这里选择稍后安装系统，在创建虚拟机后，手动选择镜像或光盘放入虚拟光驱进行安装。\n如果选择“安装程序光盘印象文件”，则会在创建完虚拟机后自动安装系统，虽然方便，但是会增加太多的安装包，并且会自动分区，这样不符合企业环境安装的标准。\n4、这里选择 Linux 系统，版本为“CentOS 7 64 位”，接着下一步。\n5、为虚拟机命名并选择程序安装路径。\n6、配置虚拟机处理器。\n7、为虚拟机选择内存资源的大小。\n8、为虚拟机选择网络类型。\n这里使用 NAT（地址转换）进行网络连接。虚拟机借助 NAT (网络地址转换)功能，通过宿主机所在的网络来访问公网。采用 NAT 模式最大的优势是虚拟系统接入互联网非常简单，你不需要进行任何其他的配置，只需要宿主机器能访问互联网即可。\n参考链接：\n桥接、NAT、Host-only 上网方式的区别-腾讯云开发者社区-腾讯云\n三种连接方式：bridge，NAT,host-only 的区别_hostonly nat-CSDN 博客\n9、选择虚拟机的 I/O 控制器类型，一般使用默认的。\n10、磁盘类型选择推荐的类型。\n11、采用默认的“创建新虚拟磁盘”。\n12、采用默认的 20GB 的大小。\n13、指定磁盘文件存储位置，路径为：I:\\VMwareALL\\clusters\\CentOS_7_OldboyCoreBasis\\CentOS_7_OldboyCoreBasis.vmdk。\n14、检查配置的虚拟机的所有选项信息。点击“自定义硬件”按钮可以进行修改。\n15、创建虚拟机后的界面信息，左边是虚拟机的名称，右边是虚拟机的实际配置。\n16、将 ISO 镜像文件载入光驱\n二、下载 CentOS 系统 ISO 镜像 # 访问 CentOS 的官方站点（不挂梯子） The CentOS Project\n其他国内的下载站点 centos 安装包下载_开源镜像站-阿里云\n三、安装 CentOS 操作系统 # 1、选择系统引导方式 # 共三种方式，选择第一个直接安装\n第三种 Troubleshooting 是系统故障恢复。\n2、修改网卡名为 eth0 的形式，按 Tab 键进入内核参数配置界面，并手动输入如下参数： # net.ifnames=0 biosdevname=0 3、进入图形安装界面，默认选择安装过程的语言为英语。 # 4、进入到安装摘要界面（Installation Summary） # 5、配置系统时区和时间（上海） # 6、选择额外的语言支持 # 7、系统软件包选择，一般选择最小化安装。 # 8、配置网络和主机名，激活右上角的网卡按钮“ON”，然后配置左下角的主机名为“www”。 # 不建议保留默认的“Host name”主机名，设置一个规范的主机名，会显得更加专业。\n9、选择磁盘设备，配置分区。 # 10、按企业生产标准定制磁盘分区，将 LVM 分区改为更优秀的标准分区模式“Standard Partition”。 # Linux 系统磁盘分区知识简介：\n1、磁盘在使用之前一般要先分区（买房分居室）\n2、分区有主分区、扩展分区和逻辑分区。一块磁盘最多可以拥有 4 个分区，其中一个主分区的位置可以用一个扩展分区来替换，在这个扩展分区内可以划分多个逻辑分区。\n3、如果规划的分区数量超过 4 个，则分区组合可为 3primary(p)+1extend(e)或 2p+1e 或 1p+1e。\n4、一块磁盘最多只能有一个扩展分区，扩展分区不能直接使用，必须在扩展分区上划分逻辑分区，然后格式化（创建文件系统)，之后才能存取数据或装系统。\n磁盘分区命名及编号方式：\n（1）以设备名命名 在 Linux 系统中，磁盘设备对应于系统中的特殊文件，这些特殊的文件放在“/dev”目录中，不同的设备对应的设备名称具体如下。 *系统的第一块 IDE 接口的硬盘称为/dev/hda。 *系统的第二块 IDE 接口的硬盘称为/dev/hdb。\n*系统的第一块 SCSI 接口的硬盘称为/dev/sda ​ *系统的第二块 SCSI 接口的硬盘称为/dev/sdb。 （2）使用数字编号 ​ 为了表示不同的分区，通常会使用数字进行编号，比如如下示例名称。 ​ *系统的第一块 IDE 接口硬盘的第 1 个分区称为/dev/hda1 ​ *系统的第一块 IDE 接口硬盘的第 5 个分区称为/dev/hda5 ​ *系统的第二块 SCSI 接口硬盘的第 1 个分区称为/dev/sdb1。 ​ *系统的第二块 SCSI 接口硬盘的第 5 个分区称为/dev/sdb5 ​ 需要注意的是，在对分区进行编号时，数字 1~4 只能留给主分区或扩展分区使用， 逻辑分区(在扩展分区基础之上）的编号只能从 5 开始。 ​ 在对 Linux 系统设置了分区之后，还要在分区上创建文件系统才能安装系统，这个在安装时可由系统自行完成创建。\nLinux 系统对分区的基本要求 1）最少要有一个根（ / ）分区，用来存放系统文件及程序。其大小至少在 5GB 以上。\n2）要有一个 swap（交换）分区， 它的作用相当于 Windows 里的虚拟内存，swap 分区的大小一般为物理内存容量的 1.5 倍(内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时， 则对 swap 分区配置 8-16GB 即可， 太大无用，浪费磁盘空间。swap 分区不是必须的, 但是大多数情况下还是设置一下比较好，个别企业的数据库应用场景不分 swap 。\n3）/boot 分区，这是 Linux 系统的引导分区，用于存放系统引导文件， 如 Linux 内核等。对于 CentOS7 而言，其要比以前的版本大一些。因此， 该分区可以设置为 1024MB,这个分区也不是必须的。\n企业生产场景中 Linux 系统的分区方案 常规的分区方案如下。 方案 1：针对网站集群架构中的某个节点服务器分区，该服务器上的数据包含多份（其他节点也有）且数据不太重要，建议的分区方案如下。\n/boot: 设置为 512~1024MB\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 剩余硬盘空间大小(/usr、/home、/var 等分区和“ / ”共用一个分区，这就相当于是在 Windows 系统中只有一个 C 盘一样，所有数据和系统文件都存放在一起)。\n方案 2: 针对数据库及存储角色的服务器分区，该服务器的业务包含了大量重要的数据，建议分区方案如下。\n/boot: 设置为 512~1024MB。\n/: 大小设置为 50-200GB,只存放系统相关文件，网站等的业务数据不放在这里。\nswap: 物理内存的 1.5 倍,当内存大于等于 8GB 时，分配 8~16GB 即可。\n/data:剩余硬盘空间大小，存放数据库及存储服务等重要数据。当然,data 的名称也可以换成别的名字。\n本方案其实就是将重要数据单独分区,以便于备份和管理。\n方案 3: 针对大网站或门户级别企业的服务器进行分区 /boot: 大小设置为 512~1024MB。\n/swap: 物理内存的 1.5 倍，当内存大于等于 8GB 时,分配 8~16GB 即可。\n/: 大小设置为 50~200GB,只存放系统相关文件,网站等的业务数据不放在这里。\n保留剩余的磁盘空间，不再进行分区，将来分配给不同的使用部门，由他们自己根据需求再分!\n此种分区方案更灵活，比较适合业务线比较多且需求不确定的大企业使用。 对于分区，有网友还给出了如下的方案:\n/boot、swap、/、/usr、/home、/var\n这种分区方案的特点是典型的没有主见的被动式的分区,分了太多的额外分区(/usr、/home、/var)，没有必要不说，管理起来也更麻烦了， 这就类似于一个家庭就 2~3 口人，买了 100 平米的房子，却非要隔成好几个房间是一个道理的， 笔者极不推荐这样的分区方案。\n如果说是怕某个分区满了会影响系统运行，那么这样的分区想法就更错了。第一， 硬盘空间是固定的，分区多了，比只分一个区肯定更容易满；第二，在企业应用里业务不可用和服务器宕机的危害几乎差不多，因此，分区少一些，然后对所有分区进行监控报警，这是目前大多数规范企业的选择。\n本文采用常规的服务器分区方案，即分为/boot、swap、/ 三个分区，注意分区的先后顺序。\n11、开始增加分区 # Mount Point（挂载点）是 Linux 下访问磁盘分区的入口，往 /boot 分区（ /dev/sda1 ）里写入数据，则必须通过 /boot 入口来写入。\n**Linux 文件系统类型：**xfs 作为 CentOS 7 中的默认文件系统类型替代了 CentOS 6 中默认使用的 ext4。\nswap：内存交换空间。由于 swap 并不会使用到目录树的挂载，因此不需要指定挂载点。\n搞懂 Linux 文件系统，99%的操作不求人_linux 文件系统-CSDN 博客\nswap 分区配置说明 1）swap 分区不配置 Mount point 挂载点,swap 不需要人为访问,交给系统自动处理即可。 2）swap 分区的大小一般为物理内存容量的 1.5 倍（内存\u0026lt;8GB)。但当系统物理内存大于 8GB 时，swap 分区配置 8-16GB 即可,太大无用,还会浪费磁盘空间。 3）如果是学习环境，为了节省空间，swap 设置得小一点也没有问题。\n**注意：**Linux 系统分区时，常规的分区方案为“/”、/boot、swap，其中 swap 不是挂载点（ “/”、/boot 都是挂载点)，而是分区类型，类似 ext4 的一个文件系统，如果在挂载点输入框处输入 /swap 创建 swap 分区那就错了。\n分区设置后的提示界面，注意分区的顺序是：/boot、swap、/\n提示: 这里采用的是生产环境中集群节点下的节点服务器的分区方式， 即系统坏掉后硬盘数据不需要保留。此分区方式也适合用于大多数生产环境的服务器， 如果是数据库以及存储等有重要数据的特殊业务服务, 那么一般会单独划分存放数据的分区如“/data” 。\n除了/boot、swap 和“/”三个分区外，还可以加/usr、/home、 /var 等分区,具体情况需要根据服务器的需求来决定，一般情况下，只配置这三个分区就足够了。\n这种分区方案最大的优点就是简单，使用方便，可批量安装部署， 而且不会存在有的分区满了， 有的分区还剩余了很多空间又不能被利用的情况(LVM 的情况这里我们先不阐述)。\n该分区方案的缺点是:如果系统坏了，那么重新装系统时， 因为数据都在“/”(根) 分区，这就导致了数据备份很麻烦；如果设置了/usr、 /home、/var 等分区，那么即使系统出了故障,也可以直接在“/”(根）分区装系统,这样并不会破坏其他分区的数据。当然,刚才也说了,如果是不存在备份数据的集群节点,那么采用这种分区方案就是很明智的，不用特别担心某个分区爆满的问题。\n12、开始系统安装 # 设置管理员 root安全密码\n这里的登陆账户名是：root\n13、系统安装后的基本配置 # 登录界面中的英文内容为 CentOS 的版本以及内核的当前版本。显示的 www 为主机名，login 为登陆提示。\n当前 Linux 内核版本号为：\n这里的“＃”为超级管理员 root 输入命令的提示符。\n配置网卡设置网络联网\n这里已经事先在前面的安装步骤设置完成。\n故障排除方法：\na、查看网卡信息\nip add 该命令是 Linux 系统中用于显示和管理网络接口地址的命令之一。它可以列出系统中所有的网络接口，包括物理网卡和虚拟网卡，并显示其 IP 地址、MAC 地址、网关、网络掩码等信息。\nb、查看网卡配置文件以及网卡配置项的含义：\ncat /etc/sysconfig/network-scripts/ifcfg-ens33 c、重启网卡的命令\nsystemctl restart network 查看默认网关设置的命令\nip route 查看 DNS 设置的命令\ncat /etc/resolv.conf 14、使用 VMware 为新系统创建快照 # 创建快照的目的是将来能将系统随时还原到做快照时候的系统状态。关闭系统后再创建快照，可以节省磁盘空间。\n15、更新系统打补丁到最新 # yum 是 Linux 下安装软件的优秀工具，是 CentOS Linux 下最好用的包管理器和安装软件包的工具，用起来很方便。Linux 的二进制软件包一般是 rpm 包，类似于 windows 下的 exe 程序。需要将默认获取 rpm 包的地址改成国内的 yum 源地址。\n参考：CentOS 停服后如何配置国内 yum 源镜像 | 丰盘 ECM 帮助中心\n先备份系统原始 yum 源配置文件\n将系统内置或手工配置的 yum 源配置文件移动至至新的目录，例如 /etc/yum.repos.d/bak240712/ ，这样后续如果想恢复或者重置也比较方便。注意，如果不移走的话，最后步骤「重建本地缓存」的时候，有可能会受到老配置文件的影响而失败。\n# 创建备份文件夹（sudo使用的是root权限，root登陆状态下可以省略）\rsudo mkdir -p /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;)\r# 将源配置移动至备份文件夹\rsudo mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak$(date +\u0026#34;%y%m%d\u0026#34;) 修改更新 yum 源的命令为：\ncurl -s -o /etc/yum.repos.d/Centos-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 下载 epel 源配置文件。\ncurl -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 运行一下两行命令重建本地缓存即可生效\nyum clean all \u0026amp;\u0026amp; yum makecache 测试安装软件包是否正常\nyum install curl wget 使用如下命令将系统更新到最新状态：\nyum update -y （也可以使用 yum upgrade -y） 16、额外安装一些有用的软件包 # CentOS 6 和 CentOS 7 都要安装的企业运维常用的基础工具包：\nyum install tree nmap dos2unix lrzsz nc lsof wget tcpdump htop iftop iotop sysstat nethogs -y centos 7 需要安装的企业运维常用的基础工具包：\nyum install psmisc net-tools bash-completiom vim-enhanced -y 四、远程连接管理 Linux # **IDC 机房：**互联网数据中心（Internet Data Center）简称 IDC，就是电信部门利用已有的互联网通信线路、带宽资源，建立标准化的电信专业级机房环境，为企业、政府提供服务器托管、租用以及相关增值等方面的全方位服务。\n遇到的问题：远程 ssh 服务器拒绝了 x11 转发请求,彻底解决用 Xshell 连接 linux ssh 时出现“The remote SSH server rejected X11 forwarding request”的\u0026hellip;-CSDN 博客\n1、远程连接 Linux 的原理 # 在互联网企业环境中，最常用的提供 Linux 远程连接服务的工具是 SSH 软件，其又分为 SSH 客户端和 SSH 服务端两部分。SSH 服务端包含的软件程序主要有 openssh (提供 SSH 服务的程序）和 openssl（为 SSH 提供连接加密的程序）。在 Linux 系统中查询 SSH 服务端工具的命令为：\nrpm -qa openssh openssl 启动 Linux 系统时，默认启动 SSH 服务器端程序，其是一个守护进程（daemon），在系统后台永久运行并时刻响应来自所有 SSH 客户端的连接请求。SSH 服务端的进程名为 sshd，负责实时监听远程 SSH 客户端的连接请求并进行处理，包括公共密钥认证、密钥交换、对称密钥加密和非安全连接等。SSH 服务是 Linux 系统优化时需要保留开机自启动的服务之一。\n最常用的 SSH 客户端是 windows 平台上运行的 SecureCRT。另外还有 Xshell、putty 以及 Linux 下的 SSH 等客户端软件。\nSSH 服务端和客户端之间的交流是通过 SSH 协议（Secure Shell Protocol）来实现的。在进行数据传输之前，SSH 通过加密技术对联机数据包进行加密处理，再进行数据传输，这样就可以确保传递的数据安全。SSH 是专为远程登陆会话和其他网络服务提供的安全性协议，利用该协议可以有效防止远程管理中的信息泄露。\nSSH 协议有两个不兼容的版本，分别是 SSH 1.x 和 SSH 2.x。openssh 同时支持 SSH 1.x 和 SSH 2.x。SSH 2.x 比 SSH 1.x 更安全，默认情况下服务端通过 SSH 2.x 协议提供服务。\n2、工具的选择 # 根据实际情况决定，Xshell 一般更适合个人和学生学习使用。SecureCRT 应用时间更久，简单，用户基数大，但是收费。\n参考：Linux 服务器远程工具选择 SecureCRT 还是 Xshell 对比-腾讯云开发者社区-腾讯云\nXshell 安装说明\n用户界面如下\n点击工具栏中的第一个“+”号按钮，需要先查询到本机的 IP 地址。\n点击连接后会弹出的界面如下\n点击“接受并保存”后输入登陆用户名（超级管理员 root）\n保存登陆密码，自动验证登录。\n3、调整 Xshell 里的设置 # 4、配置记录 SSH 操作日志及输出 # 日志文件保存路径：I:\\SSH%n*%Y-%m-%d*%t.log\n5、配置本地机器上传下载目录 # 上传和下载的路径可以设置为同一个，当所选择的路径必须存在于系统中。\n设置完毕后，可以通过 Xshell 连接的 Linux 命令行经由 rz 上传文件到 Linux 系统，通过“sz 文件名”即可下载文件到上述配置的路径里，从而实现客户端电脑和 Linux 主机的文件传输。\na、rz、sz 命令的安装方法 # 第一种：安装系统时选择包含 rz、sz 命令的包组“Dial-up Networking Support”\n第二种：安装系统后，通过执行 yum install lrzsz -y 或者 yum groupinstall “Dial-up Networking Support” -y 命令来安装。\nb、上传命令 rz # 输入 rz -y 命令可以覆盖本地的同名内容，执行后会打开一个上传文件的窗口，从这个窗口找到所需文件（客户端电脑上的）进行上传到 Linux 系统。\nc、下载命令 sz # 执行命令 “sz -y filename”可以覆盖本地的同名内容进行下载，filename 是命令行 Linux 主机当前目录下的文件。默认的客户端下载路径就是先前设置的下载路径地址 I:\\SSH\\download\nd、注意事项 # 只能上传和下载文件而不是目录，如果是目录则需要打包成文件。\n上传文件是，不要勾选最下方的“以 ASCII 方式上传文件”。\ne、其他工具 # 还可以使用 ftp、sftp、winscp 等工具来传输文件。\n6、批量部署和管理 # 首先确保所有的标签是在同一个 Xshell 窗口中打开的。\n然后，在任一个窗口中，右键选择最后一个选项\u0026quot;发送键输入到所有会话\u0026quot;\n开启批量输入模式后，操作批量管理命令：\n小规模批量部署或执行任务的服务器为数十台，可以使用 Xshell 的这个小功能。大规模服务器数量的部署，可以使用 ansiable 等批量管理工具。\n7、配置 Xshell 标签路径 # 通过“工具”里面的“选项”指定一个新的配置目录来实现备份\n8、配置标签模版 # 方法 1：对一个已经配置更好的标签实施复制、粘贴来新建标签，这样它就继承了老标签的配置。只需要再修改相应的特殊配置即可，如 IP、会话名字等。\n方法 2：在全局选项里配置各种功能设置。\n9、SSH 远程连接故障排查 # a、首先查看远端服务是否正常。 # 利用 ping 命令检查（客户端执行，也就是客户端电脑 DOS 命令行或者 Xshell 界面）\nDOS 是 Disk Operating System 的缩写，意为“磁盘操作系统”。\nWin 键+R，输入 cmd，回车，直接进入 dos 界面。\n在任意文件夹下面，按住 shift 键+鼠标右键，点击 Powershell 界面，即可进入 dos 界面。\n参考：DOS 操作系统详解：打开及基本指令指南-CSDN 博客\nping 192.168.120.129 b、检查 firewalld 等防火墙策略是否阻挡了连接(服务端执行) # systemctl status firewalld c、利用 telnet 或 nmap 命令检查（客户端执行） # telnet 192.168.120.129 22\r或\rnmap 192.168.120.129 -p 22 参考：(26 封私信 / 52 条消息) 两步解决 yum 无法安装软件问题：Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 - 知乎\ntelnet 卡住了，键盘敲 CTRL+]，然后输入 quit\nd、系统中的 SSHD 服务是否正常开启，端口是否正确 # netstat 是一个用于监控 TCP/IP 网络的命令行工具，它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息。在 CentOS 7 系统中，netstat 命令通常已经作为系统必备的网络工具包的一部分存在了，不需要额外安装。\nnetstat -Intup | grep sshd 参考：CentOS 7 下轻松安装与配置 netstat 命令详解 - 云原生实践\n检查 netstat 是否已经安装：\n使用 yum 安装 net-tools:\nsudo yum install net-tools 安装完成后进行检查\n五、克隆 VMware 下的虚拟机 # 对于完成配置操作的 Linux 主机，进行快照，可以当作模版机（temp）永久保留。\n关闭当前模版机后，右键左边菜单栏的模版机标签，选择“管理”项进行克隆。\n克隆的虚拟机信息，\n","date":"2025-04-15","externalUrl":null,"permalink":"/posts/vmware-workstation-%E5%AE%89%E8%A3%85%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%8C%87%E5%8D%97/","section":"Posts","summary":"","title":"VMware Workstation 安装虚拟机指南","type":"posts"},{"content":" 第二部分 pandas 入门 # 第四章 NumPy 基础 # NumPy 是 Python 科学计算的关键包，为数组运算和线性代数运算提供了支持。因为 pandas 是在 NumPy 之上建立起来的，所以本章会先介绍 NumPy 的基础知识。在解释了什么是 NumPy 数组之后，我们会学习向量化和广播这两个重要概念。利用向量化和广播，我们可以写出简洁的数学运算代码，并且它们在 pandas 中也有广泛运用。之后，介绍为什么 NumPy 会提供叫作“全局函数”的特殊函数。最后，通过解释 NumPy 视图和副本之间的区别，学习如何存取 NumPy 数组的值。\n4.1 NumPy 入门 # 介绍一维和二维的 NumPy 数组，以及向量化、广播和通用函数的背景知识。\n4.1.1 NumPy 数组 # 对嵌套列表进行数组运算，可以使用循环来完成。要为嵌套列表中的每一个元素都加上 1，可以使用下面的嵌套列表推导式：\nIn [1]: matrix = [[1, 2, 3],\r[4, 5, 6],\r[7, 8, 9]]\rIn [2]: [[i + 1 for i in row] for row in matrix]\rOut[2]: [[2, 3, 4], [5, 6, 7], [8, 9, 10]] 但是这样的代码可读性很低。更关键的是，在面对更大的数组时，遍历整个数组会非常慢。如果你的用例和数组大小合适的话，那么使用 NumPy 数组进行运算会比 Python 列表快上几百倍。为了达到如此高的性能，NumPy 利用了用 C 和 Fortran（它们都是编译型语言，比 Python 要快得多）编写的代码。NumPy 数组是保存同构数据（homogenous data）的 N 维数组。“同构”意味着数组中的所有数据都必须是相同类型。最常见的情况就是处理一维和二维的浮点数数组。\n下面来创建一个一维数组和一个二维数组：\nIn [3]: # 首先导入NumPy\rimport numpy as np\rIn [4]: # 使用列表构造一个一维数组\rarray1 = np.array([10, 100, 1000.])\rIn [5]: # 使用嵌套列表构造一个二维数组\rarray2 = np.array([[1., 2., 3.],\r[4., 5., 6.]]) 数组维度：要注意一维数组和二维数组之间的区别。一维数组只有一个轴，因此不区分行数组和列数组。\n即使 array1 除了最后一个元素（浮点数）之外全是整数，但由于 NumPy 对同构的要求，这个数组的数据类型依然是 float64，这个类型足以容纳所有的元素。要想了解一个数组的数据类型，可以访问它的 dtype 属性：\nIn [6]: array1.dtype\rOut[6]: dtype(\u0026#39;float64\u0026#39;) 如果需要显式地将 NumPy 数据类型转换成 Python 的基本数据类型，只需使用对应的构造器即可：\nIn [7]: float(array1[0])\rOut[7]: 10.0 4.1.2 向量化和广播 # 如果你对一个标量和 NumPy 数组求和，那么 NumPy 会执行按元素的操作。也就是说，你不用亲自遍历每一个元素。NumPy 社区称之为向量化（vectorization）。向量化可以让代码更简洁，更接近于数学记法。\nIn [8]: array2 + 1\rOut[8]: array([[2., 3., 4.],\r[5., 6., 7.]]) 标量：标量（scalar）指的是某种 Python 基本数据类型，比如浮点型和字符串。这是为了将其和列表及字典一类的多元素数据结构，以及一维和二维的 NumPy 数组区分开来。\n在处理两个数组时也是同样的道理，NumPy 会执行按元素的运算：\nIn [9]: array2 * array2\rOut[9]: array([[ 1., 4., 9.],\r[16., 25., 36.]]) 如果你在算术运算中使用了两个形状不同的数组，那么 NumPy 在可能的情况下会自动将较小的数组扩展成较大的数组的形状。这就是广播（broadcasting）：\nIn [10]: array2 * array1\rOut[10]: array([[ 10., 200., 3000.],\r[ 40., 500., 6000.]]) 要求矩阵的点积，需要使用 @ 运算符：\nIn [11]: array2 @ array2.T # array2.T是array2.transpose()的缩写形式\rOut[11]: array([[14., 32.],\r[32., 77.]]) 拓展：矩阵的点积，也称为内积或标量积，在数学中是一种重要的矩阵运算。它涉及两个矩阵中对应元素的乘积和随后的求和，结果是一个单一的标量值。对于两个向量 a 和 b，它们的点积是这样计算的：a ⋅ b = a1b1 + a2b2 + \u0026hellip; + anbn，其中 a1, a2, \u0026hellip;, an 和 b1, b2, \u0026hellip;, bn 是向量 a 和 b 的对应元素。如果将这个概念扩展到矩阵，矩阵的点积就是两个矩阵对应元素乘积的总和。\n4.1.3 通用函数 # 通用函数（universal function，简称 ufunc）会对 NumPy 数组中的每个元素执行操作。如果在 NumPy 数组中使用 Python 标准库 math 模块中的开平方函数，那么你会得到一个错误：\nIn [12]: import math\rIn [13]: math.sqrt(array2) # 这里会发生错误\r---------------------------------------------------------------------------\rTypeError Traceback (most recent call last)\r\u0026lt;ipython-input-13-5c37e8f41094\u0026gt; in \u0026lt;module\u0026gt;\r----\u0026gt; 1 math.sqrt(array2) # 这里会发生错误\rTypeError: only size-1 arrays can be converted to Python scalars 可以写一个嵌套循环来计算每个元素的平方根，然后再把结果构造成一个 NumPy 数组：\nIn [14]: np.array([[math.sqrt(i) for i in row] for row in array2])\rOut[14]: array([[1. , 1.41421356, 1.73205081],\r[2. , 2.23606798, 2.44948974]]) NumPy 有这样一个 ufunc，直接用它，除了更容易输入和阅读，在处理大型数组时 ufunc 会快得多：\nIn [15]: np.sqrt(array2)\rOut[15]: array([[1. , 1.41421356, 1.73205081],\r[2. , 2.23606798, 2.44948974]]) NumPy 的一些 ufunc 也可以用作数组的方法。以 sum 为例，如果你想求出每一列的总和，那么可以像下面这样做：\nIn [16]: array2.sum(axis=0) # 返回一维数组\rOut[16]: array([5., 7., 9.]) 参数 axis=0 表示以行为轴，参数 axis=1 表示以列为轴。省略 axis 参数会将整个数组加起来：\nIn [17]: array2.sum()\rOut[17]: 21.0 4.2 创建和操作数组 # 4.2.1 存取元素 # 在处理本章开头例子中的 matrix 这类嵌套列表时，可以使用链式索引（chained indexing）：matrix[0] [0]会得到第一行的第一个元素。不过在 NumPy 数组中，你要在一对方括号中同时提供两个维度的索引和切片参数：\nnumpy_array[row_selection, column_selection] 对于一维数组，上述代码简化成了 numpy_array[selection]。在选取单个元素时，你会得到一个标量，否则得到的就是一维或二维的数组。对二维数组的行或列进行切片，得到的是一个一维数组，而不是二维列向量或行向量。\nIn [18]: array1[2] # 返回标量\rOut[18]: 1000.0\rIn [19]: array2[0, 0] # 返回标量\rOut[19]: 1.0\rIn [20]: array2[:, 1:] # 返回二维数组\rOut[20]: array([[2., 3.],\r[5., 6.]])\rIn [21]: array2[:, 1] # 返回一维数组\rOut[21]: array([2., 5.])\rIn [22]: array2[1, :2] # 返回一维数组\rOut[22]: array([4., 5.]) 4.2.2 方便的数组构造器 # 通过 arange 和 reshape，可以快速生成指定维度的数组：\nIn [23]: np.arange(2 * 5).reshape(2, 5) # 2行，5列\rOut[23]: array([[0, 1, 2, 3, 4],\r[5, 6, 7, 8, 9]]) 以蒙特卡罗模拟为例，一个常见需求是生成服从正态分布的伪随机数数组。NumPy 可以轻松做到：\nIn [24]: np.random.randn(2, 3) # 2行，3列\rOut[24]: array([[-0.30047275, -1.19614685, -0.13652283],\r[ 1.05769357, 0.03347978, -1.2153504 ]]) 还有一些方便的构造器值得去发掘，比如 np.ones 和 np.zeros，它们分别可以创建全是 1 和 0 的数组。np.eye 可以创建单位矩阵。\n4.2.3 视图和副本 # 在对 NumPy 数组切片时，其返回值是视图（view）。这就意味着你是在操作原数组的一个子集，而没有发生数据的复制。因而设置视图的值也会改变原数组中的值：\nIn [25]: array2\rOut[25]: array([[1., 2., 3.],\r[4., 5., 6.]])\rIn [26]: subset = array2[:, :2]\rsubset\rOut[26]: array([[1., 2.],\r[4., 5.]])\rIn [27]: subset[0, 0] = 1000\rIn [28]: subset\rOut[28]: array([[1000., 2.],\r[ 4., 5.]])\rIn [29]: array2\rOut[29]: array([[1000., 2., 3.],\r[ 4., 5., 6.]]) 如果不想要这样的结果，那么可以把 In [26] 的代码改成下面这样：\nsubset = array2[:, :2].copy() 对副本进行操作不会影响原数组。\n第五章 使用 pandas 进行数据分析 # pandas，即 Python 数据分析库（Python data analysis library），pandas 最主要的超能力就是向量化和数据对齐。首先会介绍如何清理和准备数据，然后你会了解到如何通过聚合、描述性统计量和可视化让大型数据集更易于理解。本章在结尾部分会介绍如何用 pandas 导入和导出数据。不过首先，先来了解一下 pandas 最主要的数据结构：DataFrame 和 Series。\n5.1 DataFrame 和 Series # DataFrame（数据帧）和 Series（序列）是 pandas 的核心数据结构。本节会对 DataFrame 的主要组件——索引、列和数据逐一介绍。DataFrame 和二维的 NumPy 数组类似，但是它的行和列有对应的标签，并且每一列都可以存储不同类型的数据。从 DataFrame 中提取一行或一列时，你会得到一个一维的 Series。类似地，Series 相当于带标签的一维 NumPy 数组。\n从工作表到 DataFrame 的过渡非常简单，下图的 Excel 表格中展示了网课学员的基本信息及其分数。你可以在配套代码库的 xl 文件夹中找到对应的 course_participants.xlsx 文件。\n为了能在 Python 中使用这个 Excel 表格，首先要导入 pandas，然后使用 read_excel 函数通过 Excel 文件构造一个 DataFrame。\nIn [1]: import pandas as pd\rIn [2]: pd.read_excel(\u0026#34;xl/course_participants.xlsx\u0026#34;)\rOut[2]: user_id name age country score continent\r0 1001 Mark 55 Italy 4.5 Europe\r1 1000 John 33 USA 6.7 America\r2 1002 Tim 41 USA 3.9 America\r3 1003 Jenny 12 Germany 9.0 Europe 在 Python 3.9 中使用 read_excel 函数如果你在 Python 3.9 或者更高版本中使用 pd.read_excel 函数，那么一定要确保 pandas 版本在 1.2 以上，否则会在读取 xlsx 文件时发生错误。\n参考：https://geek-docs.com/python/python-ask-answer/346_hk_1709853930.html\n通过 Python 代码查看 Pandas 版本：\nimport pandas as pd\rprint(pd.__version__) 这里的报错处理如下：修改已经弃用的 np.float 为 float。\n创建 DataFrame 的方法之一是利用嵌套列表来提供数据，除了数据本身，还需要提供 columns 参数和 index 参数：\nIn [3]: data=[[\u0026#34;Mark\u0026#34;, 55, \u0026#34;Italy\u0026#34;, 4.5, \u0026#34;Europe\u0026#34;],\r[\u0026#34;John\u0026#34;, 33, \u0026#34;USA\u0026#34;, 6.7, \u0026#34;America\u0026#34;],\r[\u0026#34;Tim\u0026#34;, 41, \u0026#34;USA\u0026#34;, 3.9, \u0026#34;America\u0026#34;],\r[\u0026#34;Jenny\u0026#34;, 12, \u0026#34;Germany\u0026#34;, 9.0, \u0026#34;Europe\u0026#34;]]\rdf = pd.DataFrame(data=data,\rcolumns=[\u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;country\u0026#34;,\r\u0026#34;score\u0026#34;, \u0026#34;continent\u0026#34;],\rindex=[1001, 1000, 1002, 1003])\rdf\rOut[3]:\tname\tage\tcountry\tscore\tcontinent\r1001\tMark\t55\tItaly\t4.5\tEurope\r1000\tJohn\t33\tUSA\t6.7\tAmerica\r1002\tTim\t41\tUSA\t3.9\tAmerica\r1003\tJenny\t12\tGermany\t9.0\tEurope 调用 info 方法可以获得 DataFrame 的一些基本信息，其中最重要的是数据点数量和每一列的数据类型：\nIn [4]: df.info() \u0026lt;class \u0026#39;pandas.core.frame.DataFrame\u0026#39;\u0026gt;\rInt64Index: 4 entries, 1001 to 1003\rData columns (total 5 columns):\r# Column Non-Null Count Dtype\r--- ------ -------------- -----\r0 name 4 non-null object\r1 age 4 non-null int64\r2 country 4 non-null object\r3 score 4 non-null float64\r4 continent 4 non-null object\rdtypes: float64(1), int64(1), object(3)\rmemory usage: 192.0+ bytes 如果只对列的数据类型感兴趣，那么可以执行 df.dtypes。如果列含有字符串或者混合了不同数据类型，那么它的数据类型就是 object。\n5.1.1 索引 # DataFrame 的行标签被称为索引（index）。如果你找不到一个有意义的索引，那么在构造 DataFrame 时可以直接省略，pandas 会自动创建一个从 0 开始的整数索引。\n获取索引对象：\nIn [5]: df.index\rOut[5]: Int64Index([1001, 1000, 1002, 1003], dtype=\u0026#39;int64\u0026#39;) 可以的话，应该给索引取一个名字。根据 Excel 表格对应的列名，我们给索引取名为 user_id：\nIn [6]: df.index.name = \u0026#34;user_id\u0026#34;\rdf\rOut[6]: name age country score continent\ruser_id\r1001 Mark 55 Italy 4.5 Europe\r1000 John 33 USA 6.7 America\r1002 Tim 41 USA 3.9 America\r1003 Jenny 12 Germany 9.0 Europe 和数据库中的主键不同，DataFrame 的索引可以重复，但是这种情况下查询速度可能会变慢。要将索引还原成普通的列，可以使用 reset_index，而 set_index 可以设置一个新的索引。如果在设置新索引时不想丢掉原本的索引，那么一定要先重置索引：\nIn [7]: # reset_index会将索引还原为普通列，同时用默认索引替换当前索引\r# 最终结果就和刚从Excel文件中得到的DataFrame一样\rdf.reset_index()\rOut[7]: user_id name age country score continent\r0 1001 Mark 55 Italy 4.5 Europe\r1 1000 John 33 USA 6.7 America\r2 1002 Tim 41 USA 3.9 America\r3 1003 Jenny 12 Germany 9.0 Europe\rIn [8]: # reset_index会将user_id还原成普通列\r# set_index会将\u0026#34;name\u0026#34;列设置为索引\rdf.reset_index().set_index(\u0026#34;name\u0026#34;)\rOut[8]: user_id age country score continent\rname\rMark 1001 55 Italy 4.5 Europe\rJohn 1000 33 USA 6.7 America\rTim 1002 41 USA 3.9 America\rJenny 1003 12 Germany 9.0 Europe df.reset_index().set_index(\u0026ldquo;name\u0026rdquo;) 这种形式的代码被称为链式方法调用（method chaining）：reset_index() 会返回一个 DataFrame，你可以直接在这个 DataFrame 上调用另一个方法而无须写出中间值。\nDataFrame 的方法返回的是副本：每当以 df.method_name() 的形式调用 DataFrame 的方法时，你都会得到一个应用了该方法的 DataFrame 副本，而原来的 DataFrame 没有任何变化。刚刚调用的 df.reset_index() 就是这样的。如果你想改变原来的 DataFrame，那么可以把返回值赋值给原来的变量：\ndf = df.reset_index() 用 reindex 方法更换索引：\nIn [9]: df.reindex([999, 1000, 1001, 1004])\rOut[9]: name age country score continent\ruser_id\r999 NaN NaN NaN NaN NaN\r1000 John 33.0 USA 6.7 America\r1001 Mark 55.0 Italy 4.5 Europe\r1004 NaN NaN NaN NaN NaN reindex 会接管所有能够匹配新索引的行，而无法匹配的索引会引入含有空值（NaN）的行。被忽略的索引所对应的行会被直接丢弃。最后，使用 sort_index 可以按索引进行排序：\nIn [10]: df.sort_index()\rOut[10]: name age country score continent\ruser_id\r1000 John 33 USA 6.7 America\r1001 Mark 55 Italy 4.5 Europe\r1002 Tim 41 USA 3.9 America\r1003 Jenny 12 Germany 9.0 Europe 如果你想按一列或多列进行排序，可以使用 sort_values：\nIn [11]: df.sort_values([\u0026#34;continent\u0026#34;, \u0026#34;age\u0026#34;])\rOut[11]: name age country score continent\ruser_id\r1000 John 33 USA 6.7 America\r1002 Tim 41 USA 3.9 America\r1003 Jenny 12 Germany 9.0 Europe\r1001 Mark 55 Italy 4.5 Europe 如果只想按某一列进行排序，那么也可以用列名字符串作为参数：\ndf.sort_values(\u0026#34;continent\u0026#34;) 5.1.2 列 # 执行如下代码可以获得 DataFrame 列的信息：\nIn [12]: df.columns\rOut[12]: Index([\u0026#39;name\u0026#39;, \u0026#39;age\u0026#39;, \u0026#39;country\u0026#39;, \u0026#39;score\u0026#39;, \u0026#39;continent\u0026#39;], dtype=\u0026#39;object\u0026#39;) 如果在构造 DataFrame 时没有提供列名，那么 pandas 会用从 0 开始的数字为列编号。不过在处理列的时候这并不是一个好主意，列代表着各种变量，要取个名字并非难事。为列命名与命名索引类似：\nIn [13]: df.columns.name = \u0026#34;properties\u0026#34;\rdf\rOut[13]: properties name age country score continent\ruser_id\r1001 Mark 55 Italy 4.5 Europe\r1000 John 33 USA 6.7 America\r1002 Tim 41 USA 3.9 America\r1003 Jenny 12 Germany 9.0 Europe 如果不喜欢某些列的列名，可以进行重命名：\nIn [14]: df.rename(columns={\u0026#34;name\u0026#34;: \u0026#34;First Name\u0026#34;, \u0026#34;age\u0026#34;: \u0026#34;Age\u0026#34;})\rOut[14]: properties First Name Age country score continent\ruser_id\r1001 Mark 55 Italy 4.5 Europe\r1000 John 33 USA 6.7 America\r1002 Tim 41 USA 3.9 America\r1003 Jenny 12 Germany 9.0 Europe 如果想删除某些列，可以使用如下语法（这个例子还体现了如何在删除列的同时删除索引）：\nIn [15]: df.drop(columns=[\u0026#34;name\u0026#34;, \u0026#34;country\u0026#34;], index=[1000, 1003])\rOut[15]: properties age score continent\ruser_id\r1001 55 4.5 Europe\r1002 41 3.9 America DataFrame 的列和索引都是由 Index 对象表示的，通过转置（transpose）DataFrame 可以将行和列对调：\nIn [16]: df.T # df.transpose()的简写 要记住的是，我们的 DataFrame df 仍然原封不动，因为并没有将方法返回的 DataFrame 赋值给原来的 df 变量。如果需要更改 DataFrame 列的顺序，那么也可以使用用在索引上的 reindex 方法，不过直接给出所需要的列顺序通常会更直观：\nIn [17]: df.loc[:, [\u0026#34;continent\u0026#34;, \u0026#34;country\u0026#34;, \u0026#34;name\u0026#34;, \u0026#34;age\u0026#34;, \u0026#34;score\u0026#34;]] 5.2 数据操作 # 在使用数据之前，需要对其进行清理，使其更易于理解。如何从 DataFrame 中选取数据，如何修改数据，以及如何处理缺失和重复的数据。然后再对 DataFrame 进行一些运算，看看如何处理文本数据。\n5.2.1 选取数据 # 1. 使用标签选取数据 # 访问 DataFrame 数据的最常见方式是用它的标签来引用数据。使用 loc 属性（代表 location，位置）指定你想获取的行和列：\ndf.loc[row_selection, column_selection] loc 支持切片语法，因此可以用冒号来选取所有的行或者列。你既可以提供保存标签的列表作为参数，也可以只提供单个行或者列的名称作为参数。\n从 df 这个 DataFrame 中选取部分数据的方法：\n标签切片是闭区间：和 Python 内置的切片语法以及 pandas 的其他地方不同，在使用标签切片时，标签的区间包含区间首尾的两个标签。\nIn [18]: # 行和列都使用标量来选择，返回值也是标量\rdf.loc[1001, \u0026#34;name\u0026#34;]\rIn [19]: # 只用标量选择行或列，返回值是Series\rdf.loc[[1001, 1002], \u0026#34;age\u0026#34;]\rIn [20]: # 选取多行或多列，返回值是DataFrame\rdf.loc[:1002, [\u0026#34;name\u0026#34;, \u0026#34;country\u0026#34;]] DataFrame（无论是一列还是多列）与 Series 之间是有区别的，理解这一点至关重要。即使只包含一列，DataFrame 也是二维的数据结构，而 Series 永远是一维的。DataFrame 和 Series 都有索引，但只有 DataFrame 有列标题。当你选取一列生成 Series 时，列标题就变成了 Series 的名称。\n列选择的捷径: 列的选取是十分常见的操作，pandas 为其提供了更简单的写法。除了这样写：\ndf.loc[:, column_selection] 也可以这样写：\ndf[column_selection] 例 如，df[\u0026ldquo;country\u0026rdquo;] 会从我们的示例 DataFrame 中返回一个 Series， 而 df[[\u0026ldquo;name\u0026rdquo;, \u0026ldquo;country\u0026rdquo;]] 会返回一个包含两列的 DataFrame。\n2. 通过位置选取数据 # 通过位置选取 DataFrame 的子集类似于本章开头在 NumPy 数组上进行的操作。不过对于 DataFrame 来说，需要使用 iloc 属性，它的意思是整数位置（integer location）：\ndf.iloc[row_selection, column_selection] 在使用切片时，iloc 使用的是标准的半开半闭区间。\nIn [21]: df.iloc[0, 0] # 返回标量\rIn [22]: df.iloc[[0, 2], 1] # 返回Series\rIn [23]: df.iloc[:3, [0, 2]] # 返回DataFrame 3. 使用布尔索引选取数据 # 布尔索引（boolean indexing）是借助只包含 True 或 False 的 Series 或 DataFrame 来选取一个 DataFrame 的子集。布尔 Series 可以用来选取 DataFrame 的特定列和行，布尔 DataFrame 则用来选取整个 DataFrame 中的某些值。布尔索引最常见的用例是用来筛选 DataFrame 的行。\nIn [24]: tf = (df[\u0026#34;age\u0026#34;] \u0026gt; 40) \u0026amp; (df[\u0026#34;country\u0026#34;] == \u0026#34;USA\u0026#34;)\rtf # 这个Series中只有True和False\rIn [25]: df.loc[tf, :] 第一，由于技术上的限制，你无法在 DataFrame 中使用第 3 章讲到的 Python 布尔运算符。需要使用表 5-3 中的这些符号。\n第二，如果你的筛选条件不止一条，那么一定要在每条布尔表达式之间加上圆括号，这样可以防止运算符优先级造成的问题：例如，\u0026amp; 运算符的优先级比 == 高。\n对索引进行筛选，那么可以用 df.index 来引用索引对象：\nIn [26]: df.loc[df.index \u0026gt; 1001, :] Python 的基本数据结构（如列表）可以使用 in 运算符判断是否包含某些对象，如果要在 Series 中进行类似的操作，就需要使用 isin 方法。可以像下面这样筛选出所有来自意大利和德国的学员：\nIn [27]: df.loc[df[\u0026#34;country\u0026#34;].isin([\u0026#34;Italy\u0026#34;, \u0026#34;Germany\u0026#34;]), :] DataFrame 还提供了一种特殊的语法，可以在不使用 loc 的情况下传递一整个布尔 DataFrame 作为参数：\ndf[boolean_df] 在 DataFrame 只包含数字时这种语法特别有用。当提供这样一个布尔 DataFrame 作为参数时，返回的 DataFrame 会在原 DataFrame 的基础上，把对应着 False 的地方变成 NaN。下面先来创建一个新的示例 DataFrame，命名为 rainfall，它只包含数字：\nIn [28]: # 当作以毫米为单位的年降雨量\rrainfall = pd.DataFrame(data={\u0026#34;City 1\u0026#34;: [300.1, 100.2],\r\u0026#34;City 2\u0026#34;: [400.3, 300.4],\r\u0026#34;City 3\u0026#34;: [1000.5, 1100.6]})\rrainfall\rIn [29]: rainfall \u0026lt; 400\rIn [30]: rainfall[rainfall \u0026lt; 400] 要注意在这个例子中，我使用了字典来构造一个新的 DataFrame。如果数据本身就是这种形式的话，这是很方便的。布尔值的这种用法经常被用来排除某些值，比如异常值。\n4. 使用 MultiIndex 选取数据 # MultiIndex 是一种多级索引。它可以将数据按层次分组，这样你就可以更方便地访问 DataFrame 的子集。如果将 continent 和 country 一起设置为 df 这个 DataFrame 的索引，那么你就可以轻松地通过某个大洲的名称来选取对应的所有行：\nIn [31]: # 待排序的MultiIndex\rdf_multi = df.reset_index().set_index([\u0026#34;continent\u0026#34;, \u0026#34;country\u0026#34;])\rdf_multi = df_multi.sort_index()\rdf_multi\rIn [32]: df_multi.loc[\u0026#34;Europe\u0026#34;, :] 通过多级索引选取数据需要提供一个元组作为参数：\nIn [33]: df_multi.loc[(\u0026#34;Europe\u0026#34;, \u0026#34;Italy\u0026#34;), :] 想选择性地重置一部分 MultiIndex，那么可以为 reset_index 提供索引级别参数。索引级别从左至右从 0 开始：\nIn [34]: df_multi.reset_index(level=0) 5.2.2 设置数据 # 修改 DataFrame 数据的最简单的方法是通过 loc 和 iloc 属性为某些元素赋值。\n1. 通过标签或位置设置值 # 当你以 df.reset_index() 的形式调用 DataFrame 的方法时，方法总是会被应用到一个副本上，而原本的 DataFrame 是原封不动的。然而通过 loc 属性和 iloc 属性赋值时，原本的 DataFrame 是会被修改的。由于不想修改 df 这个 DataFrame，因此在这里我创建了一个名为 df2 的副本。如果你想修改某一个值，那么可以像下面这样做：\nIn [35]: # 先复制DataFrame，保持原本的DataFrame不变\rdf2 = df.copy() 下面是同时修改 ID 为 1000 和 1001 的两名用户分数的一种方法，这里使用了一个列表作为参数：\nIn [37]: df2.loc[[1000, 1001], \u0026#34;score\u0026#34;] = [3, 4]\rdf2 2. 通过布尔索引设置数据 # 用来筛选行的布尔索引也可以用来为 DataFrame 赋值。假设你需要将所有来自美国或年龄在 20 岁以下的学员匿名：\nIn [38]: tf = (df2[\u0026#34;age\u0026#34;] \u0026lt; 20) | (df2[\u0026#34;country\u0026#34;] == \u0026#34;USA\u0026#34;)\rdf2.loc[tf, \u0026#34;name\u0026#34;] = \u0026#34;xxx\u0026#34;\rdf2 有时可能需要将整个数据集中的某个值完全替换，而不是只涉及特定的列。在这种情况下，可以再一次利用这种特殊语法，将一个布尔 DataFrame 作为参数（示例中再一次用到了 rainfall 这个 DataFrame）：\nIn [39]: # 先复制DataFrame，保持原本的DataFrame不变\rrainfall2 = rainfall.copy()\rrainfall2\rIn [40]: # 将小于400的值用0替换\rrainfall2[rainfall2 \u0026lt; 400] = 0\rrainfall2 3. 通过替换值设置数据 # 如果想将整个 DataFrame（或者指定列）中的某个值全部替换成另一个值，那么可以使用 replace 方法：\nIn [41]: df2.replace(\u0026#34;USA\u0026#34;, \u0026#34;U.S.\u0026#34;) 如果只想在 country 列上进行操作，则可以用这种语法：\ndf2.replace({\u0026#34;country\u0026#34;: {\u0026#34;USA\u0026#34;: \u0026#34;U.S.\u0026#34;}}) 4. 通过添加新列设置数据 # 为一个新的列名赋值时会为 DataFrame 添加一个新列。例如，利用一个标量或者列表可以为 DataFrame 添加新列：\nIn [42]: df2.loc[:, \u0026#34;discount\u0026#34;] = 0\rdf2.loc[:, \u0026#34;price\u0026#34;] = [49.9, 49.9, 99.9, 99.9]\rdf2 添加新列时经常涉及向量化运算：\nIn [43]: df2 = df.copy() # 从一个新的副本开始\rdf2.loc[:, \u0026#34;birth year\u0026#34;] = 2021 - df2[\u0026#34;age\u0026#34;]\rdf2 5.2.3 缺失数据 # 数据的缺失可能会对数据分析的结果造成影响，数据集中有空白是很常见的情况，并且你还不得不对其进行处理。在 Excel 中，你通常必须用空白单元格或者 #N/A 错误进行处理，不过 pandas 使用 NumPy 的 np.nan 代表缺失数据，显示为 NaN。NaN 是浮点数标准中的 Not-a-Number（非数字）。对于时间戳，则是使用 pd.NaT，而文本使用的是 None。可以使用 None 或者 np.nan 来表示缺失的值：\nIn [44]: df2 = df.copy() # 从一个新的副本开始\rdf2.loc[1000, \u0026#34;score\u0026#34;] = None\rdf2.loc[1003, :] = None\rdf2 在清理 DataFrame 时，你可能想要移除所有包含缺失数据的行。就这么简单：\nIn [45]: df2.dropna() 如果只想移除所有值都缺失了的行，那么可以使用 how 参数：\nIn [46]: df2.dropna(how=\u0026#34;all\u0026#34;) 想获得一个反映对应位置上是否是 NaN 的布尔 DataFrame 或 Series，可以使用 isna 方法：\nIn [47]: df2.isna() 使用 fillna 来填补缺失的值。例如，将数据点数量列中的 NaN 替换为平均分：\nIn [48]: df2.fillna({\u0026#34;score\u0026#34;: df2[\u0026#34;score\u0026#34;].mean()}) 5.2.4 重复数据 # 和缺失数据一样，重复数据也会对数据分析的可靠性造成负面影响。可以使用 drop_duplicates 方法来清理重复的行。也可以提供列的子集作为参数：\nIn [49]: df.drop_duplicates([\u0026#34;country\u0026#34;, \u0026#34;continent\u0026#34;]) 在默认情况下，第一次出现的数据会得以保留。is_unique 用于确认某一列是否包含重复数据，unique 则可以获得去重后的值。（如果想对索引进行此类操作，那么可以将 df[\u0026ldquo;country\u0026rdquo;] 换成 df.index。）\nIn [50]: df[\u0026#34;country\u0026#34;].is_unique\rIn [51]: df[\u0026#34;country\u0026#34;].unique() 通过 duplicated 方法可以知道哪些行是重复的，它的返回值是一个布尔 Series。keep 参数的默认值是 \u0026ldquo;first\u0026rdquo;，意思是会保留第一次出现的数据，只将重复数据标记为 True。将 keep 设置为 False 时，所有的重复数据（包括第一次出现时）都会被标记为 True，这样就可以方便地得到一个包含所有重复行的 DataFrame。在下面的例子中，我们在找 country 列的重复数据，但在实际工作中，通常都是找重复的索引或者整行的重复数据。这个时候就要使用 df.index.duplicated() 或 df.duplicated()：\nIn [52]: # 在默认情况下，只有重复的行会被标记为True，\r# 即数据第一次出现时不会被标记为True\rdf[\u0026#34;country\u0026#34;].duplicated()\rIn [53]: # 要找到所有\u0026#34;country\u0026#34;发生重复的行，\r# 可以将参数设置为keep=False\rdf.loc[df[\u0026#34;country\u0026#34;].duplicated(keep=False), :] 5.2.5 算术运算 # 和 NumPy 数组一样，DataFrame 和 Series 也利用了向量化技术。例如，要为 rainfall 这个 DataFrame 中的每一个值加上一个数，只需像下面这样做：\nIn [54]: rainfall\rIn [55]: rainfall + 100 不过 pandas 真正的强大之处是它的自动数据对齐（data alignment）机制：当你对多个 DataFrame 使用算术运算符时，pandas 会自动将它们按照列或行索引对齐。下面再创建一个和 rainfall 有相同行列标签的 DataFrame。然后求两者之和：\nIn [56]: more_rainfall = pd.DataFrame(data=[[100, 200], [300, 400]],\rindex=[1,2],\rcolumns=[\u0026#34;City 1\u0026#34;, \u0026#34;City 4\u0026#34;])\rmore_rainfall\rIn [57]: rainfall + more_rainfall 结果 DataFrame 的索引和列是两个 DataFrame 的并集：两个 DataFrame 中都有的字段会被相加，而其他的部分会显示为 NaN。要让 pandas 和 Excel 以同样的方式处理这个问题，可以使用 add 方法，并将 fill_value 参数设置为 0 以代替默认的 NaN：\nIn [58]: rainfall.add(more_rainfall, fill_value=0) 当算式的操作数是一个 DataFrame 和一个 Series 时，默认情况下 Series 会按索引进行广播：\nIn [59]: # 用一行数据生成一个Series\rrainfall.loc[1, :]\rIn [60]: rainfall + rainfall.loc[1, :] 如果要按列加上一个 Series，则需要在调用 add 方法时显式地提供 axis 参数：\nIn [61]: # 用一列数据生成一个Series\rrainfall.loc[:, \u0026#34;City 2\u0026#34;]\rIn [62]: rainfall.add(rainfall.loc[:, \u0026#34;City 2\u0026#34;], axis=0) 5.2.6 处理文本列 # 含有文本数据的列和含有不同类型数据的列的数据类型是 object。要在含有文本字符串的列上执行相关操作，需要使用 str 属性。str 属性可以访问 Python 的字符串方法。要移除字符串首尾的空白，可以使用 strip 方法；要将首字母大写，可以使用 capitalize 方法。将这些方法组合起来之后，可以将人工输入的乱七八糟的数据清理干净：\nIn [63]: # 来创建一个新的DataFrame\rusers = pd.DataFrame(data=[\u0026#34; mArk \u0026#34;, \u0026#34;JOHN \u0026#34;, \u0026#34;Tim\u0026#34;, \u0026#34; jenny\u0026#34;],\rcolumns=[\u0026#34;name\u0026#34;])\rusers\rIn [64]: users_cleaned = users.loc[:,\u0026#34;name\u0026#34;].str.strip().str.capitalize()\rusers_cleaned 可以像下面这样找到所有以“J”开头的名字：\nIn [65]: users_cleaned.str.startswith(\u0026#34;J\u0026#34;) 字符串方法很好用，但是有时候要对 DataFrame 进行的操作可能并没有在对应的内置函数上。在这种情况下，你可以创建自己的函数，再将其应用到 DataFrame 上。\n5.2.7 应用函数 # DataFrame 提供了 applymap 方法，它会将一个函数应用到每一个元素上，在 NumPy 没有提供所需的 ufunc 时，这是非常有用的。例如，NumPy 并没有提供字符串格式化的 ufunc，但可以像下面这样为 DataFrame 的每一个元素进行格式化：\nIn [66]: rainfall\rIn [67]: def format_string(x):\rreturn f\u0026#34;{x:,.2f}\u0026#34;\rIn [68]: # 注意，我们并没有调用作为参数的函数，\r# 也就是说，这里写的是format_string而非format_string()！\rrainfall.applymap(format_string) 这个 f 字符串会将 x 以字符串的形式返回：f\u0026quot;{x}\u0026quot;。要对其进行格式化，需要在变量后面加一个冒号，然后跟上具体的格式化字符串，这里使用的是 ,.2f。这个逗号是千位上的分隔符，而 .2f 的意思是以浮点数格式显示，小数点后保留两位。\n在这样的用例中会经常用到 lambda 表达式（参见“lambda 表达式”）。lambda 表达式可以让你在一行代码中编写一个函数，而不用单独去定义一个函数。通过 lambda 表达式，可以将前面的例子改写成下面这样。\nIn [69]: rainfall.applymap(lambda x: f\u0026#34;{x:,.2f}\u0026#34;) lambda 表达式：lambda 表达式是一种匿名函数，也就是一种没有名称的函数。假设有这样一个函数：\ndef function_name(arg1, arg2, ...):\rreturn return_value 可以用 lambda 表达式重写这个函数：\nlambda arg1, arg2, ...: return_value 简而言之，把 def 换成 lambda，省去 return 关键字，然后将函数的所有内容写到一行。\n5.2.8 视图和副本 # 由于修改视图和修改副本有着本质的区别，因此当 pandas 认为你在无意中修改数据时，它会发出警告：SettingWithCopyWarning。关于如何规避这个相当难以捉摸的警告，下面是一些建议。\n• 在原本的 DataFrame 中设置值，而不是在切片生成的 DataFrame 中操作。\n• 如果你想在切片后获得一个单独的 DataFrame，则应该显式地调用 copy。\nselection = df.loc[:, [\u0026#34;country\u0026#34;, \u0026#34;continent\u0026#34;]].copy() 虽然 loc 和 iloc 的情况很复杂，但是记得一点，诸如 df.dropna() 或 df.sort_value(\u0026ldquo;column_name\u0026rdquo;) 这样的 DataFrame 方法总是返回副本。\n","date":"2024-07-18","externalUrl":null,"permalink":"/posts/excel-python%E9%A3%9E%E9%80%9F%E6%90%9E%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%84%E7%90%86%E4%B9%8B-pandas-%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/","section":"Posts","summary":"","title":"Excel Python:飞速搞定数据分析与处理之 Pandas 入门笔记","type":"posts"},{"content":"","date":"2024-07-18","externalUrl":null,"permalink":"/tags/pandas/","section":"标签","summary":"","title":"Pandas","type":"tags"},{"content":"","date":"2024-07-18","externalUrl":null,"permalink":"/tags/python/","section":"标签","summary":"","title":"Python","type":"tags"},{"content":"","date":"2024-07-18","externalUrl":null,"permalink":"/tags/%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86/","section":"标签","summary":"","title":"数据处理","type":"tags"},{"content":"","date":"2024-07-18","externalUrl":null,"permalink":"/categories/%E6%88%91%E7%9A%84%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/","section":"分类列表","summary":"","title":"我的学习笔记","type":"categories"},{"content":"\r第一部分 Python 入门 # 前言：本系列文章为作者个人学习 Python 数据处理的学习笔记，其中对于书上的一些案例进行了本地实现，以及在实现过程中对出现的一些问题进行了解决和知识拓展，希望可以为阅读笔记的朋友们提供一些帮助。\n第一章 为什么要用 Python 为 Excel 编程 # 1.1 Excel 作为一门编程语言 # 1.1.2 编程最佳实践 # 最重要的编程最佳实践，涉及关注点分离、DRY 原则、测试和版本控制。\n1. 关注点分离 # 编程最重要的设计原则之一就是关注点分离（separation of concerns），有时候也称作模块化（modularity）。一系列相关的功能应当被视作程序中一个独立的部分来处 理，从而可以在不影响应用程序其他部分的情况下，轻松地替换这一部分.\n一个应用程序通常被分为如下 3 层:\n• 表示层（presentation layer）：这一层是你可以看到并与之交互的部分，也就是所谓的用户界面。\n• 业务层（business layer）：这一层负责特定应用程序的逻辑。\n• 数据层（data layer）：这一层负责访问数据。\n2. DRY 原则 # 意思是“不要自我重复”（don’t repeat yourself），没有重复的代码意味着代码行数更少，错误也更少，代码自然也就更容易维护。\n3. 测试 # 专业软件开发人员测试代码，会写单元测试（unit test）。 这是一种可以测试程序各个组件的机制。单元测试会确保程序中的每一个函数都正常工作。大部分编程语言会提供一种自动执行单元测试的方法。执行自动测试可以使代码库的可靠性大幅提升，并且在一定程度上，测试会确保在编辑代码时不会破坏当前正常工作的代码。\n通常程序员会对单元测试进行配置，每当代码被提交到版本控制系统的时候，它就会自动运行。\n4. 版本控制 # 专业程序员会使用版本控制（version control）系统，或者称为源代码控制（source control）系统。版本控制系统（version control system，VCS）会不断跟踪源代码的更改，让你能够看到是谁进行了更改，更改了什么，什么时候更改的，为什么更改， 并且在任何时候都能还原到过去的版本。当今最受欢迎的版本控制系统是 Git。\n通常专业程序员都会结合像GitHub、GitLab、Bitbucket 和 Azure DevOps 这样的 Web 平台来使用 Git，这些平台可以让你提出所谓的拉取请求 （pull request）和合并请求（merge request）。这些操作可以让开发者正式地请求负责人将他 们的更改合并到主数据库中。一次拉取请求会提供如下信息：\n• 更改的作者； • 更改发生的时间； • 在提交信息（commit message）中描述的更改目的； • 在 diff 视图（其中新代码以绿色高亮显示，删掉的代码以红色高亮显示）中展示的更改细节。\n1.1.3 现代 Excel # 1. Power Query 和 Power Pivot # Power Query 可以连接各种数据源，包括 Excel 工作簿、CSV 文件、SQL 数据库，等等。核心功能是处理一张工作表装不下的数据集。在加载数据之后，你还可以通过额外的操作来清理、操作数据，使之成为 Excel 可用的形式。\nPower Pivot 和 Power Query 联系密切，利用 Power Query 获取和清理数据之后，就该 Power Pivot 上场了。Power Pivot 以一种引人入胜的方式直接在 Excel 中分析和呈现数据。可以把它视作一种传统意义上的数据透视表。和 Power Query 一样， 它也可以处理大型数据集。Power Pivot 可以用关系和层次来定义形式上的数据模型， 并且可以通过 DAX 公式语言添加计算列。\n2. Power BI # Power BI 是在 2015 年发布的一个独立应用程序。Power BI 通过在交互式仪表板中可视化巨大的数据集使其更容易理解。Power BI 的商业版可以让你在线和他人合作，并共享仪表板。Power BI 自 2018 年起就支持 Python 脚本了。\n1.2 用在 Excel 上的 Python # Excel 的主要功能是存储数据、分析数据和可视化数据。而 Python 在科学计算方面也极其\n强大，天生就适合搭配 Excel 工作。\n1.2.1 可读性和可维护性 # 良好的可读性使得发现错误和维护代码更加容易，Python 会强制将视觉缩进和代码逻辑对齐，从而避免可读性问题。当你在 if 语句或 for 循环中使用代码块时，Python 依靠缩进来定义代码块。\n使用缩进定义代码块的原因在于，编程时大部分时间是花费在维护代码而不是现写新的代码上。可读性好的代码可以帮助新进程序员回顾过去、了解现状。\n1.2.2 标准库和包管理器 # Python 通过标准库提供了丰富的内置工具。Python 社群喜欢称之为“自带电池”。尽管 Python 标准库涵盖了大量的功能，但还是有一些功能难以编写，又或是使用标准库来实现效率很低。这个时候就该 PyPI 上场了。PyPI 代表 Python Package Index（Python 包目录），它是任何人（包括你！）都可以上传开源 Python 包的巨大仓库，利用这些包可以扩展 Python 的功能。\n如果想更方便地从互联网上获取数据，可以安装 Requests 包来获取一系列强大又好用的命令。要安装一个包，需要在命令提示符或者终端中使用 Python 的包管理器，即 pip。pip 是 pip installs packages 的递归缩写。\n为什么包管理器如此重要。一个主要原因是，任何优质的包可能不仅依赖于 Python 标准库，还会依赖于 PyPI 上的其他开源包。而这些依赖项又可能会依赖其他的包，层层递进。pip 会递归地检查一个包的依赖项和子依赖项，并逐一下载安装。你还可以使用 pip 轻松地更新包，以保持各个依赖项都是最新版本。pip 让你能够坚守 DRY 原则，因为不用重新发明轮子或者复制粘贴 PyPI 上已有的包。有了 pip 和 PyPI，你就有了一套统一的机制来分发和安装依赖项——这正是 Excel 的插件所欠缺的。\n1.2.3 科学计算 # 诸如 NumPy、SciPy 和 pandas 之类的科学计算库提供了一种简洁的方式来表达数学问题。\n1.2.5 跨平台兼容性 # 即便在一台运行着 Windows 或者 macOS 的本地计算机上开发，在某个时候你也可能会想让代码在一台服务器或者云端上运行。服务器会通过其运算能力，让代码按计划执行，并使应用程序可以从任何地方访问。\n第二章 开发环境 # 先安装好 Anaconda Python 发行版。除了安装 Python，Anaconda 还会安装 Anaconda Prompt 和 Jupyter 笔记本。它们是贯穿本书的两种关键工具。Anaconda Prompt 是一种特殊的命令提示符（用 Windows 的话来说）或者终端（用 macOS 的话来说），我们可以通过它来运行 Python 脚本和一些本书中会用到的命令行工具。Jupyter 笔记本让我们可以交互地处理数据、代码和图表，可以说它是 Excel 工作簿的强力竞争者。在体验了 Jupyter 笔记本之后，我们会安装一个强大的文本编辑器——Visual Studio Code（VS Code）。VS Code 内置了集成终端，用它来编写、执行和调试 Python 代码非常方便。\n2.1 Anaconda Python 发行版 # 2.1.2 Anaconda Prompt # Anaconda Prompt 实际上就是 Windows 中的一个命令提示符或者 macOS 中的终端，只不过它配置好了 Python 解释器和第三方包。Anaconda Prompt 是执行 Python 代码的最基本的工具，本书会大量使用它来执行 Python 脚本和各种包提供的命令行工具。\n在 Windows 中，输入 dir 并按回车键。命令提示符会打印出当前所在目录的内容。\n输入 cd Down 并按 tab 键。cd 代表切换目录。如果位于 home 文件夹中，那么 Anaconda Prompt 极有可能会将刚才输入的内容自动补全为 cd Downloads。\n注意，如果路径以你当前所在目录中的文件夹名或文件名开始，那么你用的就是相对路径，比如 cd Downloads。如果想离开当前目录，可以输入绝对路径，比如在 Windows 中输入 cd C:\\Users。\n切换至父目录（上一级目录），需要输入 cd .. 然后按回车键（确保在 cd 和两点之间有一个空格）。将这个命令和目录名相结合，如果你想先返回上一级目录，然后进入 Desktop，可以输入 cd ..\\Desktop。\n2.1.3 Python REPL：交互式 Python 会话 # 交互式 Python 会话也被称为 REPL，意思是读取 – 求值 – 输出循环（read-eval-print loop），Python 会读取你的输入，对其求值，然后立即输出结果并等待下一次输入。\n要退出 Python 会话，需要输入 quit() 并按回车键。也可以在 Windows 中按下快捷键\nCtrl+Z，然后按回车键。\n2.1.4 包管理器：Conda 和 pip # Python 的包管理器 pip，它负责下载、安装、更新和卸载 Python 包及其依赖项和子依赖项。虽然 Anaconda 也可以配合 pip 工作，但是它还有一个名为 Conda 的内置包管理器。Conda 的一大优势是不仅可以安装 Python 包，还可以安装多种版本的 Python 解释器。一言以蔽之：软件包可以为 Python 添加标准库中所没有的功能。\n在使用 Anaconda 的情况下，应该尽可能地用 Conda 安装各种软件包。而 pip 只是用来安装那些在 Conda 中找不到的软件包。不然的话 Conda 可能会覆盖你用 pip 安装的包。\n表 2-2 列出了最常用的命令。这些命令必须在 Anaconda Prompt 中输入，可以让你安装、更新和卸载第三方包。\n查看安装的 Anaconda 发行版中已经安装了哪些包，可以输入以下代码：\n(base)\u0026gt; conda list 安装 Plotly 和 xlutils，这两个包都可以在 Conda 中找到：\n(base)\u0026gt; conda install plotly xlutils 执行这条命令之后，Conda 会向你表明它要干些什么，你需要输入 y 并按回车键表示确认。\n通过 pip 来安装 pyxlsb 和 pytrends，这两个包 Conda 中没有：\n(base)\u0026gt; pip install pyxlsb pytrends 和 Conda 不一样，pip 在你按回车键之后会立即开始安装而不需要确认。\n2.1.5 Conda 环境 # Anaconda Prompt 每行开头的 (base) 到底是什么。它是当前激活的 Conda 环境的名称。Conda 环境是一个被隔离的“Python 世界”，有着特定版本的 Python 和一系列安装好的包。为什么非要这么做呢？当你同时开发多个项目的时候，各个项目会有不同的需求：一个项目可能需要 Python 3.8 和 pandas 0.25.0，而另一个项目可能需要 Python 3.9 和 pandas 1.0.0。由于为 pandas 0.25.0 编写的代码往往需要进行修改才能用到 pandas 1.0.0 上，因此不能只更新 Python 和 pandas 而保持代码原封不动。为每个项目都配置一个 Conda 环境可以保证它们使用正确的依赖项运行。Conda 环境虽然是 Anaconda 发行版的专有概念，但虚拟环境是所有 Python 发行版的通用概念。相比之下 Conda 环境更加强大，因为它不仅可以管理多个版本的软件包，还可以轻松管理不同版本的 Python 解释器。\n创建新项目时，为每个项目使用单独的 Conda 环境或者虚拟环境是很好的实践方式，这可以让你规避不同项目之间的依赖冲突。\n详情可见附录 A\n2.2 Jupyter 笔记本 # 在数据科学领域，人们热衷于使用 Jupyter 笔记本来运行代码。它把格式规整的可执行 Python 代码、图片和图表融合到一个交互式笔记本中，并且这个笔记本是运行在浏览器中的。Jupyter 笔记本对初学者很友好，在教学、原型开发、研究等领域极为受欢迎，极大地方便了可重现的研究。\nJupyter 笔记本可以快速准备、分析和可视化数据，这和工作簿的用例几乎相同。它已然成了 Excel 的竞争者。但和 Excel 不同，Jupyter 笔记本是用 Python 代码来完成这些工作的，而不是用鼠标在 Excel 中点来点去。Jupyter 笔记本的另一个优势是，它不会把数据和业务逻辑混在一起。Jupyter 笔记本会负责代码和图表，使用来自外部 CSV 文件或者数据库中的数据。Jupyter 笔记本在本地和远程服务器上都可以运行，一般来说，服务器要比本地机器性能更强，它可以在无人值守的情况下运行代码。\n2.2.1 运行 Jupyter 笔记本 # 在 Anaconda Prompt 中，切换至配套代码库所在目录，这里使用创建的虚拟环境 xl38，然后启动 Jupyter 笔记本服务器：\n(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; F:\r(xl38)\u0026gt; cd F:\\Python\\python-for-excel-1st-edition\r(xl38)\u0026gt; jupyter notebook 打开的 Jupyter 仪表板会显示执行命令时所在目录中的文件。在 Jupyter 仪表板的右上方，点击新建，在下拉列表中选择 xl38，这里需要激活连接新建的虚拟环境 xl38（具体可见文档：Python 开发环境安装流程.md 中的 Jupyter 代码编辑器的虚拟环境连接 Jupyter），过程如下：\n(xl38) C:\\Users\\SHY\u0026gt;pip install ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simple\r(xl38) C:\\Users\\SHY\u0026gt;python -m ipykernel install --user --name=xl38 浏览器会为你的第一个空白笔记本打开新的标签页：\n点击 Jupyter logo 旁边的 Untitled，为工作簿取一个更有意义的名字，比如 first_notebook。\n2.2.2 笔记本单元格 # 输入 3 + 4，然后点击上面菜单栏中的运行按钮，或者用更方便的快捷键：Shift+ 回车。单元格中的代码将会执行，并把结果输出到单元格下方，然后跳到下一个单元格。由于目前我们只有一个单元格，因此笔记本会在下面插入一个空白单元格。现在再仔细看一下，当单元格正在计算时，会显示 In [*]；在计算完成时，星号就变成了数字，也就是 In [1]。在这个单元格下方你会看到对应的输出单元格，而且和输入单元格有相同的编号：Out [1]。每当你运行一个单元格，编号就会加 1，这个编号可以帮助你识别单元格执行的顺序。\n**注意：**如果单元格的最后一行返回了一个值，那么它会自动输出到 Jupyter 笔记本的 Out [ ] 单元格中。然而，如果你使用的是 print 函数或者发生了异常，则相应的输出会直接显示在 In 单元格下方而没有 Out [ ] 标签。\n单元格有不同的类型，我们需要关注以下两种。\n1、代码：默认类型。需要执行 Python 代码时就会用到它。\n2、Markdown：Markdown 是一种格式化语法，它使用标准的文本字符来格式化文本。可以用它在笔记本中添加格式规整的解释和说明。\n要把单元格的类型切换为 Markdown，先选中单元格，然后在单元格模式下拉菜单中选 Markdown，\n在将一个空单元格切换为 Markdown 单元格后，输入下列文本，这是对 Markdown 语法规则的介绍\n# 这是一级标题\r## 这是二级标题\r你可以让你的文本变成*斜体*、**粗体**或`等宽字体`\r* 这是项目符号\r* 又一个项目符号 按下快捷键 Shift+ 回车之后，这段文本会被渲染成格式规整的 HTML。Markdown 单元格还可以添加图片、视频或公式。\n2.2.3 编辑模式与命令模式 # 当和 Jupyter 笔记本中的单元格互动时，你要么处于编辑模式（editing mode），要么处于命令模式（command mode）。\n编辑模式：点击一个单元格以启动编辑模式。被选中的单元格边缘会变成绿色，单元格中的光标也会开始闪烁。除了点击单元格，还可以在选中单元格时按回车键。\n命令模式：要切换至命令模式，需要按下 Esc 键。被选中的单元格边缘会变成蓝色且不会出现光标。\n2.2.4 执行顺序很重要 # 假设你的笔记本中有下面这样几个单元格，从上往下执行：\nIn [2]: a = 1\rIn [3]: a\rOut[3]: 1\rIn [4]: a = 2 单元格 Out[3] 会按照预期输出 1。然而，如果你回去再一次执行 In[3]，就会得到下面的结果：\nIn [2]: a = 1\rIn [5]: a\rOut[5]: 2\rIn [4]: a = 2 2.2.5 关闭 Jupyter 笔记本 # 每个笔记本都在一个独立的 Jupyter 内核中运行。内核是运行单元格中 Python 代码的“引擎”。每个内核都会消耗操作系统提供的 CPU 和 RAM 资源。在关闭笔记本时，还需要关闭它的内核，以便内核所占用的资源可以被其他任务重用——从而防止系统变慢。\n最简单的方法是选择菜单中的“文件 \u0026gt; 关闭”。如果只是关闭了浏览器标签页，那么内核并不会自动关闭。另外，在 Jupyter 仪表板中，也可以从运行标签页中关闭正在运行的笔记本。\n要关闭整个 Jupyter 服务器，可以点击 Jupyter 仪表板右上方的退出按钮（logout）。如果已经关闭了浏览器，可以在运行笔记本服务器的 Anaconda Prompt 中按两次快捷键 Ctrl+C，或者连同 Anaconda Prompt 一起关闭。\n2.3 VS Code # 安装并配置 VS Code，它是微软开发的一个免费且开源的文本编辑器。\nJupyter 笔记本虽然对于研究、教学和实验这类互动型的工作流程来说很好用，但是如果想编写针对生产环境的 Python 脚本（这类脚本用不到笔记本的可视化功能），Jupyter 笔记本并非理想之选。对于一些涉及大量文件和多位开发者的复杂项目，Jupyter 笔记本也不是那么好用。\n理论上来讲，可以使用任何文本编辑器（哪怕是记事本也行），但实际上你需要的是一个可以“理解”Python 的编辑器。这样的编辑器至少应该有如下特性。\n1、语法高亮：编辑器会为具有不同语义（函数、字符串、数字，等等）的单词赋予不同的颜色，从而使得代码更容易阅读和理解。\n2、自动补全：自动补全（autocomplete），或者用微软的话来讲叫智能感知（intelliSense），可以为文本组件提供建议，以便你少打字、少打错字。\nVS Code 自 2015 年发布以来就深受开发者喜爱，其融合了纯文本编辑器和全功能 IDE：VS Code 是一个迷你 IDE，囊括了编程所需要的所有工具。除此之外，它还具有如下特性。\n1、跨平台：VS Code 可以在 Windows、macOS 和 Linux 中运行，也有像 GitHub Codespaces 这样的云托管版本。\n2、集成工具：VS Code 内置调试器，支持 Git 版本控制，还有可以用作 Anaconda Prompt 的集成终端。\n3、扩展：包括 Python 支持在内的其他所有功能，都可以以扩展的形式一键安装。\n4、轻量：根据操作系统的不同，VS Code 的安装包仅有 50MB~100MB 大小。\nVS Code 和 Visual Studio\n不要把 VS Code 和名为 Visual Studio 的 IDE 搞混了！虽然也可以用 Visual Studio 来进行 Python 开 发 [Visual Studio 有 PTVS（Python Tools for Visual Studio，适用于 Visual Studio 的 Python 工具）]，但是需要安装很多东西。传统上 Visual Studio 是用来做 .NET 语言（如 C#）开发的。\n2.3.1 安装和配置 # 下载官网：Visual Studio Code - Code Editing. Redefined\n安装的时候注意安装位置，避免安装到 C 盘。VS Code 确实是一个开箱即用的优秀文本编辑器，但是要让它完美配合 Python，还需要进行一些配置。点击活动栏上的扩展图标，然后搜索 Python。安装作者显示为微软（Microsoft）的官方 Python 插件。待其安装完成之后，可以点击需要重新加载按钮来完成安装。或者也可以完全重启 VS Code。\n命令面板：按下 F1 键或者快捷键：Ctrl+Shift+P（Windows 系统）或者 Command-Shift-P（macOS 系统），可以打开命令面板。如果对某些东西拿不准，你首先就应该想到命令面板。VS Code 所有功能的快捷入口都在其中。\nWindows 中，打开命令面板，输入 default profile。选择“终端：选择默认配置文件”这一项，然后按回车键。在下拉菜单中，选择命令提示符并按回车键确认。我们需要这样设置，以便 VS Code 正常激活 Conda 环境。\n2.3.2 执行 Python 脚本 # 虽然可以从 Windows 的开始菜单或者 macOS 的启动台打开 VS Code，但是直接从 Anaconda Prompt 中打开会更快——可以直接用 code 命令启动 VS Code。接下来，打开一个新的 Anaconda Prompt，通过 cd 命令将目录切换到你希望进行操作的地方，然后让 VS Code 打开当前目录（用点表示）：\n(base) C:\\Users\\SHY\u0026gt;conda activate xl38\r(xl38) C:\\Users\\SHY\u0026gt;cd ..\r(xl38) C:\\Users\u0026gt;cd ..\r(xl38) C:\\\u0026gt;D:\r(xl38) D:\\\u0026gt;cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38) D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\u0026gt; 以这种方式启动 VS Code 可以让活动栏中的资源浏览器自动显示启动目录中的内容。\n把鼠标悬停在活动栏的资源管理器中的文件上时，会看到新建文件按钮。点击新建文件，取名为 hello_world.py，然后按回车键。当文件在编辑器中打开之后，输入下面这行代码：\nprint(\u0026#34;hello world!\u0026#34;) 状态栏中，应该可以看到 Python 的版本，比如“Python 3.8.5 64-bit (conda)”。如果点一下，命令面板会显示让你选择一个不同的 Python 解释器（如果你有好几个的话），也包括不同的 Conda 环境。\n在执行脚本之前，一定要先保存。在 Windows 中可以按快捷键 Ctrl+S 进行保存。\n在 VS Code 中，可以通过 Anaconda Prompt 运行，也可以直接点运行按钮。当你要执行一个服务器上的脚本时，可能更多地还是从 Anaconda Prompt 中执行，所以有必要知道具体如何操作。\nAnaconda Prompt：打开 Anaconda Prompt，将 cd 放入脚本所在的文件夹中，按如下方式运行脚本：\n(xl38)\u0026gt; cd cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38)\u0026gt; python hello_world.py\rhello world! 注意，如果你当前不在 Python 文件所在的目录，则需要使用完整路径。\n1、VS Code 中的 Anaconda Prompt：\n不必为了使用 Anaconda Prompt 而从 VS Code 中切换出去。在 VS Code 中可以直接通过快捷键 Ctrl+` 或者“查看 \u0026gt; 终端”菜单项显示集成终端。由于集成终端会在项目所在文件夹中打开，因此也不需要切换目录\n2、VS Code 中的运行按钮\n在 VS Code 中，有一种无须使用 Anaconda Prompt 也能运行代码的简单方法。在编辑 Python 文件时，你会在右上方看到一个播放图标，这就是运行文件按钮。点击这个按钮会自动在底部打开终端并运行代码。\n3、在 VS Code 中打开文件\n当你在资源管理器（位于活动栏）中单击一个文件时，VS Code 会有一些令人意外的默认行为。单击文件后，文件会以预览模式打开，意思就是说如果没有对这个文件进行更改，那么你下一次单击打开的文件会替换掉这个文件的标签页。如果想关掉单击操作的这种行为（变成单击选定文件，双击打开），可以在“首选项 \u0026gt; 设置”中（或者用快捷键，在 Windows 中是 Ctrl+,，在 macOS 中是 Command-,）将“工作台 \u0026gt;‘List: Open Mode’”设置为“doubleClick”。\n拓展：\n第三章 Python 入门 # 本章首先会介绍 Python 的基本数据类型，比如整型和字符串。然后会介绍 Python 的核心概念——索引和切片，使你可以访问一个序列的指定元素。接下来会讲到列表和字典等数据结构，它们可以保存多个对象。之后会介绍 Python 中的控制流：if 语句、for 循环和 while 循环。紧接着是函数和模块的相关知识，它们可以用来组织和架构你的代码。最后会展示应该如何正确格式化 Python 代码。\n3.1 数据类型 # 最常用的数据类型有整型、浮点型、布尔值和字符串。要理解什么是数据类型，需要先解释一下什么是对象。\n3.1.1 对象 # 在 Python 中，一切皆对象（object）。数字、字符串、函数，以及我们会在本章中见到的其他所有东西，它们都是对象。通过提供一系列变量和函数，对象可以让复杂的东西简单化。先来看看变量和函数。\n1、变量：\n在 Python 中，变量（variable）是通过等号给对象赋予的一个名字。 Python 中，可以通过给变量赋值一个新的对象来改变变量的类型。这种行为被称作动态类型：\nIn [2]: a = 3\rprint(a)\ra = \u0026#34;three\u0026#34;\rprint(a)\r3\rthree Python 是区分大小写的，因此 a 和 A 是不同的变量。变量名必须遵守下列规则：\n• 必须以字母或下划线开头；\n• 只能由字母、数字和下划线组成。\n2、函数\n要调用一个函数，需要在函数名后跟上一对圆括号，并在圆括号中提供参数，和数学记法几乎一模一样：\nfunction_name(argument1, argument2, ...) 3、属性和方法\n谈到对象时，变量被称作属性（attribute）1 ，函数被称作方法（method）。你可以通过属性来访问对象的数据，而方法可以用来执行某种操作。你可以通过点号来访问属性和方法，比如 myobject.attribute 和 myobject.method()。\n如果你在写一个赛车游戏，那么很可能需要表示车的对象。car 对象应该有一个 speed 属性，这样你就可以通过 car.speed 来获取车辆的当前速度。或许还可以通过调用加速方法 car.acc.accelerate(10) 来让车辆加速，即让车速增加到每小时 10 英里。\n对象的类型及其行为是由类（class）定义的，因此在前面的例子中，你可能需要编写一个 Car 类。从 Car 类构造 car 对象的过程叫作实例化（instantiation）。要实例化一个对象，需要像调用函数那样去调用类：car = Car()。\n3.1.2 数值类型 # int 和 float 分别表示整数（integer）和浮点数（floating-point number）。通过内置的 type 函数可以获得指定对象的类型：\nIn [3]: type(4)\rOut[3]: int\rIn [4]: type(4.4)\rOut[4]: float 强制让一个数字成为 float 类型而不是 int 类型，可以在后面加一个小数点，或者使用 float 构造器：\nIn [5]: type(4.)\rOut[5]: float\rIn [6]: float(4)\rOut[6]: 4.0 对于整型也是一样的，int 构造器可以将一个 float 值转换为 int。如果小数部分不为零，那么转换时会直接舍去。\nIn [7]: int(4.9)\rOut[7]: 4 Excel 单元格永远保存的是浮点数：从 Excel 单元格读取数字的时候，可能需要先把 float 转换为 int，然后才能把它传给一个需要整型参数的函数。原因是即使 Excel 显示的是整数，但在背后它总是以浮点数形式存储。\n3.1.3 布尔值 # Python 中，布尔类型只有 True 和 False 两种取值，Python 中的布尔运算符 and、or 和 not 全是小写形式。每个 Python 对象都可以被视作 True 或 False。大部分的对象会被视作 True，但 None、False、0 或空数据类型 [ 比如空字符串（下一节中会讲到字符串）] 会被视作 False。\nNone 是一个内置的常量，按照官方文档的说法，它代表“没有值”（the absence of a value）。如果一个函数没有显式地返回值，那么它实际上返回的就是 None。None 可以用来表示 Excel 中的空单元格。\n3.1.4 字符串 # Python 中的字符串既可以用双引号（\u0026quot;）来表示，也可以用单引号（\u0026rsquo;）来表示。唯一的要求是字符串的首尾必须是同一种引号。可以用 + 来拼接字符串，或者用 * 来重复字符串的内容。如果发现字符串的内容还是需要转义，可以用反斜杠来转义字符：\nIn [31]: print(\u0026#34;Don\u0026#39;t wait! \u0026#34; + \u0026#39;Learn how to \u0026#34;speak\u0026#34; Python.\u0026#39;)\rDon\u0026#39;t wait! Learn how to \u0026#34;speak\u0026#34; Python.\rIn [32]: print(\u0026#34;It\u0026#39;s easy to \\\u0026#34;escape\\\u0026#34; characters with a leading \\\\.\u0026#34;)\rIt\u0026#39;s easy to \u0026#34;escape\u0026#34; characters with a leading \\. 当字符串中包含变量的值时，通常可以使用 f 字符串（f-string，格式化字符串字面量，formatted string literal 的缩写）来处理。\nIn [33]: # 注意Python如何在一行中为多个变量赋予多个值\rfirst_adjective, second_adjective = \u0026#34;free\u0026#34;, \u0026#34;open source\u0026#34;\rf\u0026#34;Python is {first_adjective} and {second_adjective}.\u0026#34;\rOut[33]: \u0026#39;Python is free and open source.\u0026#39; 转换大小写：\nIn [34]: \u0026#34;PYTHON\u0026#34;.lower()\rOut[34]: \u0026#39;python\u0026#39;\rIn [35]: \u0026#34;python\u0026#34;.upper()\rOut[35]: \u0026#39;PYTHON\u0026#39; 获取帮助：在 Jupyter 笔记本中，敲入对象后面的点之后按 Tab 键，比如 \u0026ldquo;python\u0026rdquo;.。画面上会出现一个下拉菜单，其中包含了这个对象提供的所有属性和方法。如果你的光标停在一个方法上，比如停在 \u0026ldquo;python\u0026rdquo;.upper() 的括号中，按下快捷键 Shift+Tab 就可以获得这个函数的描述信息。VS Code 会以提示的形式自动显示这些信息。如果你在 Anaconda Prompt 中运行 Python REPL，使用 dir(\u0026ldquo;python\u0026rdquo;) 可以获得可用的属性，而使用 help(\u0026ldquo;python\u0026rdquo;,upper) 可以打印 upper 方法的描述信息。除此之外，也应该经常看一下 Python 的在线文档。如果你在找 pandas 之类的第三方包的文档，可以在 PyPI（Python 包索引）中搜索对应的包，在这里可以找到这些包的主页和文档的链接。\n3.2 索引和切片 # 索引和切片让你可以访问一个序列的指定元素。\n3.2.1 索引 # Python 的索引从 0 开始，意思就是说序列的第一个元素通过 0 来引用。负索引从 -1 开始，你可以用负索引从序列末端引用元素。\n索引的语法如下：\nsequence[index] 访问字符串的指定元素：\nIn [36]: language = \u0026#34;PYTHON\u0026#34;\rIn [37]: language[0]\rOut[37]: \u0026#39;P\u0026#39;\rIn [38]: language[1]\rOut[38]: \u0026#39;Y\u0026#39;\rIn [39]: language[-1]\rOut[39]: \u0026#39;N\u0026#39;\rIn [40]: language[-2]\rOut[40]: \u0026#39;O\u0026#39; 3.2.2 切片 # 如果你想从一个序列中获取一个以上的元素，就要用到切片（slicing）语法：\nsequence[start:stop:step] Python 使用的是左闭右开区间，意思是切片区间包含 start，但不包含 stop。如果省略了 start 或者 stop，则切片会分别包含从头开始或者从末尾开始的所有元素。step 决定了切片的方向和步长。如果令步长为 2，那么切片就会从左到右每两个元素取一个值；如果令步长为 -3，则切片会从右到左每 3 个元素取一个值。默认步长为 1:\nIn [41]: language[:3] # 同language[0:3]\rOut[41]: \u0026#39;PYT\u0026#39;\rIn [42]: language[1:3]\rOut[42]: \u0026#39;YT\u0026#39;\rIn [43]: language[-3:] # 同language[-3:6]\rOut[43]: \u0026#39;HON\u0026#39;\rIn [44]: language[-3:-1]\rOut[44]: \u0026#39;HO\u0026#39;\rIn [45]: language[::2] # 每两个元素取一个\rOut[45]: \u0026#39;PTO\u0026#39;\rIn [46]: language[-1:-4:-1] # 负步长从右到左\rOut[46]: \u0026#39;NOH\u0026#39; Python 也可以将多次索引和切片操作串联起来。如果你想获得最后 3 个字符中的第二个，可以像下面这样做：\nIn [47]: language[-3:][1]\rOut[47]: \u0026#39;O\u0026#39; 上述代码和 language[-2] 是等价的，连续索引并不会简单到哪儿去。但是在索引和切片列表的时候，连续索引会显得更有条理一些。\n3.3 数据结构 # Python 提供了强大的数据结构以便于处理对象集合。本节会介绍列表、字典、元组和集合。虽然每种数据结构有各自的特点，但它们有一个共同特点，即都能存储多个对象。\n3.3.1 列表 # 列表（list）可以存储不同数据类型的多个对象。用途广泛，可以随时使用。创建列表的语法如下：\n[element1, element2, ...] 实例，下面是两个列表，一个保存了一些 Excel 文件的名称，另一个保存了几个数字：\nIn [48]: file_names = [\u0026#34;one.xlsx\u0026#34;, \u0026#34;two.xlsx\u0026#34;, \u0026#34;three.xlsx\u0026#34;]\rnumbers = [1, 2, 3] 和字符串一样，列表也可以用加号进行拼接。下面的代码还体现了列表的一个特性，那就是它可以保存不同类型的对象：\nIn [49]: file_names + numbers\rOut[49]: [\u0026#39;one.xlsx\u0026#39;, \u0026#39;two.xlsx\u0026#39;, \u0026#39;three.xlsx\u0026#39;, 1, 2, 3] 列表也是对象，也可以包含其他列表作为元素。我称之为嵌套列表（nested list）：\nIn [50]: nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 把这种嵌套列表写成多行，你就会发现列表可以很好地表示矩阵和工作表单元格。注意，这些方括号会隐式地让代码跨行（参见“跨行”）。通过索引和切片，你可以获得想要的任何元素。\nIn [51]: cells = [[1, 2, 3],\r[4, 5, 6],\r[7, 8, 9]]\rIn [52]: cells[1] # 第二行\rOut[52]: [4, 5, 6]\rIn [53]: cells[1][1:] # 第二行的第二列和第三列\rOut[53]: [5, 6] 更改列表中的元素：\nIn [56]: users = [\u0026#34;Linda\u0026#34;, \u0026#34;Brian\u0026#34;]\rIn [57]: users.append(\u0026#34;Jennifer\u0026#34;) # 最常用的操作是向列表末尾追加元素\rusers\rOut[57]: [\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;]\rIn [58]: users.insert(0, \u0026#34;Kim\u0026#34;) # 在索引0处插入\u0026#34;Kim\u0026#34;\rusers\rOut[58]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;] 要删除一个元素，可以使用 pop 或者 del。pop 是一个方法，而 del 是一种 Python 语句：\nIn [59]: users.pop() # 在默认情况下，移除并返回最后一个元素\rOut[59]: \u0026#39;Jennifer\u0026#39;\rIn [60]: users\rOut[60]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [61]: del users[0] # del会移除指定索引处的元素 可以对列表进行以下操作：\nIn [62]: len(users) # 长度\rOut[62]: 2\rIn [63]: \u0026#34;Linda\u0026#34; in users # 检查users是否包含\u0026#34;Linda\u0026#34;\rOut[63]: True\rIn [64]: print(sorted(users)) # 返回新的排好序的列表\rprint(users) # 原列表保持不变\r[\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;]\r[\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [65]: users.sort() # 对原列表进行排序\rusers\rOut[65]: [\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;] 也可以把 len 和 in 用在字符串上：\nIn [66]: len(\u0026#34;Python\u0026#34;)\rOut[66]: 6\rIn [67]: \u0026#34;free\u0026#34; in \u0026#34;Python is free and open source.\u0026#34;\rOut[67]: True 要访问列表中的元素，可以通过元素的**位置（索引）**来引用一个元素——但并非任何时候都能知道元素的位置。\n3.3.2 字典 # 字典（dictionary）是键到值的映射。你会经常遇到键 – 值对。创建字典最简单的方法如下：\n{key1: value1, key2: value2, ...} 和索引一样，键也被放在方括号中。下面的代码中，一对货币（键）映射到了汇率（值）：\nIn [68]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rIn [69]: exchange_rates[\u0026#34;EURUSD\u0026#34;] # 访问EURUSD的汇率\rOut[69]: 1.1152 下面的代码展示了如何修改既存的值以及添加新的键 – 值对：\nIn [70]: exchange_rates[\u0026#34;EURUSD\u0026#34;] = 1.2 # 修改已经存在的值\rexchange_rates\rOut[70]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161}\rIn [71]: exchange_rates[\u0026#34;CADUSD\u0026#34;] = 0.714 # 添加新的键–值对\rexchange_rates\rOut[71]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161, \u0026#39;CADUSD\u0026#39;: 0.714} 合并两个或多个字典的最简单的办法是将字典解包（unpack）后再合并到一个新的字典中。在字典前加上两个星号就可以进行解包。如果第二个字典包含第一个字典中的键，那么第一个字典中对应的值会被覆盖。\nIn [72]: {**exchange_rates, **{\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222}}\rOut[72]: {\u0026#39;EURUSD\u0026#39;: 1.2,\r\u0026#39;GBPUSD\u0026#39;: 1.2222,\r\u0026#39;AUDUSD\u0026#39;: 0.6161,\r\u0026#39;CADUSD\u0026#39;: 0.714,\r\u0026#39;SGDUSD\u0026#39;: 0.7004} Python 3.9 引入了管道符号 作为专门的字典合并运算符。上面的表达式可以简化成如下代码：\nexchange_rates | {\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222} get 方法可以在键不存在时返回一个默认值：\nIn [75]: # currencies[100]会引发异常\r# 除了100，还可以尝试任何不存在的键\rcurrencies.get(100, \u0026#34;N/A\u0026#34;)\rOut[75]: \u0026#39;N/A\u0026#39; 3.3.3 元组 # 元组（tuple）和列表类似，只不过它们是不可变的（immutable）：一旦被创建，它们的元素就无法被修改。虽然很多时候元组和列表可以互换使用，但对于那些在整个程序中都不会发生改变的集合来说，元组是不二之选。元组是通过多个被逗号分隔的值创建的：\nmytuple = element1, element2, ... 使用圆括号通常更易于阅读：\nIn [76]: currencies = (\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;) 可以使用访问数组的方法来访问元组，只是不能修改元组的元素。拼接元组会在“暗地里”创建一个新的元组，然后再把新元组绑定到你的变量上：\nIn [77]: currencies[0] # 访问第一个元素\rOut[77]: \u0026#39;EUR\u0026#39;\rIn [78]: # 拼接元组会返回一个新元组\rcurrencies + (\u0026#34;SGD\u0026#34;,)\rOut[78]: (\u0026#39;EUR\u0026#39;, \u0026#39;GBP\u0026#39;, \u0026#39;AUD\u0026#39;, \u0026#39;SGD\u0026#39;) 附录 C 中会解释可变对象和不可变对象之间的区别。\n3.3.4 集合 # 集合（set）是一种没有重复元素的集合（collection）。你自然可以把集合用于集合论的运算中，但在实践中它们经常被用于列表去重或者元组去重。使用花括号创建集合：\n{element1, element2, ...} 要对列表或者元组进行去重，可以像下面这样使用 set 构造器：\nIn [79]: set([\u0026#34;USD\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;])\rOut[79]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;} 还可以进行像交集和并集之类的集合论运算：\nIn [80]: portfolio1 = {\u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CHF\u0026#34;}\rportfolio2 = {\u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CAD\u0026#34;}\rIn [81]: # 同 portfolio2.union(portfolio1)\rportfolio1.union(portfolio2)\rOut[81]: {\u0026#39;CAD\u0026#39;, \u0026#39;CHF\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;}\rIn [82]: # 同 portfolio2.intersection(portfolio1)\rportfolio1.intersection(portfolio2)\rOut[82]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;} 回顾一下刚刚认识的 4 种数据结构，使用前面用过的字面量（literal）记法。另外，列出它们的构造器。和字面量一样，构造器可以创建对应的数据结构，并且通常用于数据结构之间的相互转换。例如，要把元组转换为列表，可以执行以下操作：\nIn [83]: currencies = \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;CHF\u0026#34;\rcurrencies\rOut[83]: (\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;)\rIn [84]: list(currencies)\rOut[84]: [\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;] 3.4 控制流 # 介绍 if 语句、for 循环和 while 循环。if 只会在满足特定条件时执行特定的代码，for 循环和 while 循环会反复执行代码块中的代码。\n3.4.1 代码块和 pass 语句 # 代码块（code block）界定了一段源代码，这段代码会用于一些特定的目的。在 Python 中，代码块通过缩进来体现，而不像包括 VBA 在内的大部分编程语言那样——使用花括号。这就是所谓的有特殊含义的空白（significant white space）。Python 社区坚持使用 4 个空格作为缩进，不过你通常只需要敲一次 Tab 键就行了。Jupyter 笔记本和 VS Code 都会自动将 Tab 键转换为 4 个空格。代码块的前一行总是会以冒号结尾。一旦某一行没有被缩进，代码块就自然结束了。\n3.4.2 if 语句和条件表达式 # 在 Python 中，if 语句本身不需要任何的圆括号。要检查一个值是否为 True，并不需要显式地写这样一个表达式。\n条件表达式（conditional expression）或者三元运算符（ternary operator）可以以一种更紧凑的形式编写 if/else 语句：\nIn [88]: is_important = False\rprint(\u0026#34;important\u0026#34;) if is_important else print(\u0026#34;not important\u0026#34;)\rnot important 3.4.3 for 循环和 while 循环 # for 循环会对一个序列 [ 比如列表、元组、字符串（记住，字符串就是字符的序列）] 进行迭代。\nIn [89]: currencies = [\u0026#34;USD\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;]\rfor currency in currencies:\rprint(currency)\rUSD\rGBP\rAUD 在 Python 中，如果你在 for 循环中需要一个计数器变量，那么可以用内置的 range 函数和enumerate 函数。先来看看 range，它会提供一连串的数字。你可以只提供一个 stop 参数，也可以同时提供 start 参数和 stop 参数，还可以提供一个可选的 step 参数。和切片类似，range 产生的区间包含 start，但不包含 stop，step 决定了步长，默认为 1：\nrange(stop)\rrange(start, stop, step) range 会延迟求值，意思就是说只要你不明确要求求值，它就不会产生指定的序列：\nIn [90]: range(5)\rOut[90]: range(0, 5) 将 range 转换为列表可以解决这个问题：\nIn [91]: list(range(5)) # stop参数\rOut[91]: [0, 1, 2, 3, 4]\rIn [92]: list(range(2, 5, 2)) # start、stop和step 3个参数\rOut[92]: [2, 4] 不过大部分时候没必要把 range 包装成一个列表：\nfor i in range(3):\rprint(i)\r# 输出结果\r0\r1\r2 如果在迭代序列时需要一个计数器变量，那么可以使用 enumerate。它会返回一系列 (index, element) 元组。 在默认情况下，索引从 0 开始，每次循环加 1。在循环中可以这样使用 enumerate：\nfor i, currency in enumerate(currencies):\rprint(i, currency)\r# 输出结果\r0 USD\r1 GBP\r2 AUD 在元组和集合中进行循环与在列表中类似。在字典中进行循环时，Python 会按照键进行循环：\nexchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rfor currency_pair in exchange_rates:\rprint(currency_pair)\r# 输出结果\rEURUSD\rGBPUSD\rAUDUSD items 方法可以以元组的形式同时获得键和对应的值：\nfor currency_pair, exchange_rate in exchange_rates.items():\rprint(currency_pair, exchange_rate)\r# 输出结果\rEURUSD 1.1152\rGBPUSD 1.2454\rAUDUSD 0.6161 break 语句可以跳出循环：\nfor i in range(15):\rif i == 2:\rbreak\relse:\rprint(i)\r# 输出结果\r0\r1 可以使用 continue 语句跳过本轮循环的剩余部分。即程序会使用下一个元素进入下一轮迭代：\nfor i in range(4):\rif i == 2:\rcontinue\relse:\rprint(i)\r# 输出结果\r0\r1\r3 使用 while 循环，循环会在条件不满足时停止：\nn = 0\rwhile n \u0026lt;= 2:\rprint(n)\rn += 1\r# 输出结果\r0\r1\r2 增强赋值：上一个例子中使用了增强赋值（augmented assignment）的写法：n += 1。这和 n = n + 1 是一样的。前面介绍过的其他算术运算符也可以采用同样的写法，比如，可以写成 n -= 1。\n3.4.4 列表、字典和集合推导式 # 假设有如下的货币名称对，你想把美元在后面的元素挑出来。你可能会写下面这样一个 for 循环：\ncurrency_pairs = [\u0026#34;USDJPY\u0026#34;, \u0026#34;USDGBP\u0026#34;, \u0026#34;USDCHF\u0026#34;,\r\u0026#34;USDCAD\u0026#34;, \u0026#34;AUDUSD\u0026#34;, \u0026#34;NZDUSD\u0026#34;]\rusd_quote = []\rfor pair in currency_pairs:\rif pair[3:] == \u0026#34;USD\u0026#34;:\rusd_quote.append(pair[:3])\rusd_quote、\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 这种情况用列表推导式（list comprehension）会更简单。列表推导式是一种更简洁的列表创建方法。\n[pair[:3] for pair in currency_pairs if pair[3:] == \u0026#34;USD\u0026#34;]\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 字典也有字典推导式：\nIn [105]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\r{k: v * 100 for (k, v) in exchange_rates.items()}\rOut[105]: {\u0026#39;EURUSD\u0026#39;: 111.52, \u0026#39;GBPUSD\u0026#39;: 124.54, \u0026#39;AUDUSD\u0026#39;: 61.61} 集合也有集合推导式：\nIn [106]: {s + \u0026#34;USD\u0026#34; for s in [\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;NZD\u0026#34;, \u0026#34;NZD\u0026#34;]}\rOut[106]: {\u0026#39;EURUSD\u0026#39;, \u0026#39;GBPUSD\u0026#39;, \u0026#39;NZDUSD\u0026#39;} 3.5 组织代码 # 如何让代码形成可维护的结构：首先会介绍函数的核心知识，然后如何将代码分成不同的 Python 模块。\n3.5.1 函数 # 即使只是用 Python 来写一些简单的脚本，你仍然会经常编写函数。函数是所有编程语言中最重要的构造，它们可以让你在程序的任何地方重用同样的代码。\n1. 定义函数 # 在 Python 中，需要使用 def 关键字来自定义函数，def 代表函数定义。函数定义的第一行以冒号结束，函数的主体需要缩进。\ndef function_name(required_argument, optional_argument=default_value, ...):\rreturn value1, value2, ... 必需参数：必需参数（required argument）没有默认值。参数之间用逗号隔开。\n可选参数：为参数提供默认值之后，它就成了可选参数（optional argument）。如果没有有意义的默认值，则通常用 None 作为可选参数的默认值。\n返回值：return 语句定义了函数的返回值。如果省略了返回值，那么函数就会自动返回 None。Python 允许你返回以逗号隔开的多个返回值，这很方便。\n来定义一个函数练习一下，这个函数可以将华氏度或者开氏度转换为摄氏度：\nIn [107]: def convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;):\rif source.lower() == \u0026#34;fahrenheit\u0026#34;:\rreturn (degrees-32) * (5/9)\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34; 字符串的 lower 方法可以将给定字符串转换为小写，这样就可以在保持比较字符串的代码照常工作的前提下，接受任何大小写形式的 source 字符串了。完成 convert_to_celsius 的定义后，来看看如何调用它。\n2. 调用函数 # 调用一个函数，可以在函数名后加上一对圆括号，并在其中给出参数。\nvalue1, value2, ... = function_name(positional_arg, arg_name=value, ...) 位置参数：如果将一个值作为位置参数（positional argument，即上面的 positional_arg）传递，那么这个值会被传递给对应位置上的参数。\n关键字参数：以 arg_name=value 这种形式传递的参数，就是关键字参数（keyword argument）。关键字参数的好处是可以以任意顺序传递参数，并且对于读者来说更加直观易懂。如果函数被定义成 f(a, b)，则可以像这样调用：f(b=1, a=2)。\n下面来尝试一下 convert_to_celsius 函数，看看它是如何工作的：\nIn [108]: convert_to_celsius(100, \u0026#34;fahrenheit\u0026#34;) # 位置参数\rOut[108]: 37.77777777777778\rIn [109]: convert_to_celsius(50) # 使用默认值（fahrenheit）\rOut[109]: 10.0\rIn [110]: convert_to_celsius(source=\u0026#34;kelvin\u0026#34;, degrees=0) # 关键字参数\rOut[110]: -273.15 3.5.2 模块和 import 语句 # 为大型项目编写代码时，在一定的时候会需要将代码分成不同的文件，从而保持一种可维护的结构。\nPython 文件的扩展名为 .py，通常我们会把主要的文件称作脚本（script）。如果你想让你的主脚本获得来自其他文件的概念，则需要先导入（import）那个功能。在这种情况下，Python 源文件被称为模块（module）。\n模块只会被导入一次：如果再一次运行 import temperature 单元格，你会注意到 print 函数不会输出任何内容。这是因为 Python 模块在每个会话中只会被导入一次。如果你要导入的模块发生了更改，则需要重启 Python 解释器才能让更改体现出来。在 Jupyter 笔记本中，需要点击“内核 \u0026gt; 重启”。\n在使用 import x from y 这样的语法时，你只导入了指定的对象。这些对象被直接导入主脚本的命名空间（namespace）中，也就是说，如果不看这些 import 语句，你就说不清被导入的对象是在你的 Python 脚本（或者 Jupyter 笔记本）中还是在另一个模块中定义的。\n不要让你的脚本和既存的包重名：一个常见的错误根源是给你的 Python 文件取一个和既存的包同样的名字。如果你要创建一个测试 pandas 功能的文件，那么不要将其命名为 pandas.py，因为这会造成冲突。\n3.5.3 datetime 类 # 要在 Python 中处理日期和时间，可以导入标准库中的 datetime 模块。这个模块包含了一个也叫 datetime 的类，可用于创建 datetime 对象。由于这个类和它所在的模块同名，可能会造成混淆，因此在本书中我会遵循这样的导入规则：import datetime as dt。这样可以更容易区分模块（dt）和类（datetime）。\n到目前为止，我们大部分时候是用字面量（literal）来创建列表和字典之类的对象。字面量指的是一种会被 Python 识别为特定类型对象的语法。对于列表来说就是像 [1, 2, 3] 这种写法。然而，大部分的对象需要调用对应的类来创建——这个过程被称为实例化（instantiation），因此对象也被称作类实例（class instance）。和调用函数一样，调用类也需要在类名后跟上一对圆括号，并在圆括号中提供参数。要实例化 datetime 对象，需要像下面这样调用对应的类：\nimport datetime as dt\rdt.datetime(year, month, day, hour, minute, second, microsecond, timezone) In [118]: # 将datetime模块导入为dt\rimport datetime as dt\rIn [119]: # 调用timestamp以创建datetime对象\rtimestamp = dt.datetime(2020, 1, 31, 14, 30)\rtimestamp\rOut[119]: datetime.datetime(2020, 1, 31, 14, 30)\rIn [120]: # datetime对象提供了多种属性，比如，想要知道它是几号\rtimestamp.day\rOut[120]: 31\rIn [121]: # 两个datetime对象求差会返回一个timedelta对象\rtimestamp - dt.datetime(2020, 1, 14, 12, 0)\rOut[121]: datetime.timedelta(days=17, seconds=9000)\rIn [122]: # 也可以对timedelta进行同样的操作\rtimestamp + dt.timedelta(days=1, hours=4, minutes=11)\rOut[122]: datetime.datetime(2020, 2, 1, 18, 41) 要将 datetime 对象格式化（format）成字符串，可以使用 strftime 方法；要解析（parse）字符串并将其转换为 datetime 对象，可以使用 strptime 函数：\nIn [123]: # 以特定方式格式化datetime对象\r# 也可以使用f字符串: f\u0026#34;{timestamp:%d/%m/%Y %H:%M}\u0026#34;\rtimestamp.strftime(\u0026#34;%d/%m/%Y %H:%M\u0026#34;)\rOut[123]: \u0026#39;31/01/2020 14:30\u0026#39;\rIn [124]: # 将字符串解析为datetime对象\rdt.datetime.strptime(\u0026#34;12.1.2020\u0026#34;, \u0026#34;%d.%m.%Y\u0026#34;)\rOut[124]: datetime.datetime(2020, 1, 12, 0, 0) 3.6 PEP 8：Python 风格指南 # Python 使用所谓的 Python 改进提案（Python Enhancement Proposals，PEP）来讨论新语言特性的引入。Python 代码的风格指南就是其中之一。这些提案一般用数字来表示，代码风格指南就被称作 PEP 8。PEP 8 是一系列提供给 Python 社区的风格建议。如果使用相同代码的所有人都遵循相同的代码风格，那么写出的代码可读性就会更高。在开源的世界中，会有很多互不相识的程序员开发同一个项目，此时遵循相同的代码风格会显得尤为重要。\n\u0026#34;\u0026#34;\u0026#34;这个脚本展示了一些PEP 8的规则 ➊\r\u0026#34;\u0026#34;\u0026#34;\rimport datetime as dt ➋\rTEMPERATURE_SCALES = (\u0026#34;fahrenheit\u0026#34;, \u0026#34;kelvin\u0026#34;,\r\u0026#34;celsius\u0026#34;) ➌\r➍\rclass TemperatureConverter: ➎\rpass # 暂时不做任何事 ➏\rdef convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;): ➐\r\u0026#34;\u0026#34;\u0026#34;这个函数将华氏度或开氏度转化为摄氏度 ➑\r\u0026#34;\u0026#34;\u0026#34;\rif source.lower() == \u0026#34;fahrenheit\u0026#34;: ➒\rreturn (degrees-32) * (5/9) ➓\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34;\rcelsius = convert_to_celsius(44, source=\u0026#34;fahrenheit\u0026#34;)\t11\rnon_celsius_scales = TEMPERATURE_SCALES[:-1]\t12\rprint(\u0026#34;Current time: \u0026#34; + dt.datetime.now().isoformat())\rprint(f\u0026#34;The temperature in Celsius is: {celsius}\u0026#34;) ➊ 在文件顶部用文档字符串（docstring）解释这个脚本或者模块做了些什么。文档字符串是一种特殊的字符串，它用 3 个引号引用。除了作为代码的文档，它还可以用来编写跨越多行的字符串。如果你的字符串中有很多双引号或单引号，那么也可以用文档字符串来避免转义。\n➋ 所有的导入语句都应该放在文件顶部，一行一个导入。从标准库导入的内容放在前面，然后是第三方包，最后是自己编写的模块。\n➌ 用大写字母和下划线表示常量。每行的长度不超过 79 个字符。尽可能地利用圆括号、方括号或花括号隐式跨行。\n➍ 类、函数和其他代码之间用两个空行隔开。\n➎ 尽管很多类像 datetime 一样使用小写字母命名，但是你自己编写的类也应该使用首字母大写的名称（CapitalizedWords）。有关类的更多内容请参见附录 C。\n➏ 行内注释应该和代码间隔至少两个空格。代码块应该用 4 个空格缩进。\n➐ 在能够提高可读性的情况下，函数和参数应该使用小写字母和下划线命名。不要在参数名和默认值之间使用空格。\n➑ 函数的文档字符串应当列出函数参数并解释其意义。\n➒ 冒号前后不要使用空格。\n➓ 可以在算术运算符前后使用空格。如果同时使用了优先级不同的运算符，则应当考虑在优先级最低的运算符前后添加空格。在本例中，由于乘号的优先级最低，因此它的前后被添加了空格。\n11：变量名称使用小写字母。在可以提升可读性的前提下使用下划线。为变量赋值时，在等号前后添加空格。不过在调用函数时，不要在关键字参数前后使用空格。\n12：在进行索引和切片时，不要在方括号前后使用空格。\n3.6.1 PEP 8 和 VS Code # 在使用 VS Code 时，确保代码严格遵循 PEP 8 的最简单方法是使用代码检查器（linter）。代码检查器会检查源代码中的语法和风格错误。vscode 怎么检查代码 • Worktile 社区\n3.6.2 类型提示 # Python 3.5 引入了一个叫作类型提示（type hint）的特性。类型提示也被称为类型标注（type annotation），它允许你声明变量的数据类型。类型提示并不是强制性的，它也不会影响 Python 解释器执行代码。其主要目的是让 VS Code 之类的文本编辑器可以在代码执行前捕获更多错误，不过它也可以增强编辑器的自动补全功能。\nmypy 是用于有类型标注的 Python 代码的最受欢迎的类型检查器，是 VS Code 提供的一种代码检查器。要理解类型标注如何工作，先来看下面这段没有类型提示的代码：\nx = 1\rdef hello(name):\rreturn f\u0026#34;Hello {name}!\u0026#34; 现在加上类型提示：\nx: int = 1\rdef hello(name: str) -\u0026gt; str:\rreturn f\u0026#34;Hello {name}!\u0026#34; 一般来说，类型提示在较大的项目中才会更有用。\n附录 A Conda 环境 # A.1 创建新的 Conda 环境 # 在 Anaconda Prompt 中执行下列命令以创建一个名为 xl38 的新环境，该环境使用了 Python 3.8：\n(base)\u0026gt; conda create --name xl38 python=3.8 安装完成之后，像下面这样激活新的环境：\n(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; 环境名称已从 base 变更为 xl38。现在你可以使用 Conda 或者 pip 在新环境中安装各种包，且不会影响任何其他的环境。（提醒一句：只有在 Conda 中找不到想要的包时才使用 pip。）\n首先，再次确认你处于 xl38 环境中，即 Anaconda Prompt 显示的是 (xl38)，然后像下面这样安装 Conda 包（注意，这里需要更换为国内镜像源更快）：\n(xl38)\u0026gt; conda install lxml=4.6.1 matplotlib=3.3.2 notebook=6.1.4 openpyxl=3.0.5 pandas=1.1.3 pillow=8.0.1 plotly=4.14.1 flake8=3.8.4 python-dateutil=2.8.1 requests=2.24.0 sqlalchemy=1.3.20 xlrd=1.2.0 xlsxwriter=1.3.7 xlutils=2.0.0 xlwings=0.20.8 xlwt=1.3.0 确认安装计划之后，最后再来使用 pip 安装剩下的两个包。\n(xl38)\u0026gt; pip install pyxlsb==1.0.7 pytrends==4.7.3 这里安装时出现问题，更换镜像源不行的话，需要关闭梯子的系统代理，参考如下：\npip 安装 Python 包时的 SSL 错误\n如果不想使用 base 环境而想使用 xl38 环境来运行本书中的所有示例代码，那么每次启动 Anaconda Prompt 时一定要执行如下命令来激活 xl38 环境：\n(base)\u0026gt; conda activate xl38 也就是说，每当本书代码中的 Anaconda Prompt 显示为 (base)\u0026gt; 时，你看到的应该是 (xl38)\u0026gt;。\n要停用环境并回到 base 环境，可以输入如下命令：\n(xl38)\u0026gt; conda deactivate 想彻底删除环境，可以运行以下命令：\n(base)\u0026gt; conda env remove --name xl38 除了按照上面的步骤手动创建 xl38 环境，也可以利用本书配套代码库的 conda 文件夹中的\nxl38.yml 环境文件。执行下面的命令就可以完成所有工作：\n(base)\u0026gt; cd C:\\Users\\username\\python-for-excel\\conda\r(base)\u0026gt; conda env create -f xl38.yml\r(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; A.2 禁用自动激活 # 如果不希望在每次启动 Anaconda Prompt 时自动激活 base 环境，你可以禁用它：这样你就需要在命令提示符（Windows 系统）或终端（macOS 系统）中手动输入 conda activate base 才能使用 Python。\n在 Windows 中，你需要使用一般的命令提示符而不是 Anaconda Prompt。下面的步骤可以在普通的命令提示符中启用 conda 命令。一定要将第一行中的路径替换成你的计算机上的 Anaconda 安装目录：\n\u0026gt; cd C:\\Users\\username\\Anaconda3\\condabin\r\u0026gt; conda init cmd.exe 现在你的普通命令提示符已经配置好 Conda，接下来就可以像下面这样激活 base 环境了。\n\u0026gt; conda activate base\r(base)\u0026gt; 附录 B 高级 VS Code 功能 # B.1 调试器 # 首先在 VS Code 中打开配套代码库的 debugging.py 文件。然后点击第 4 行左边的空白处，你会看到一个红点，这就是断点，代码会在此处暂停执行。接下来按下 F5 键开始调试：命令面板会显示调试配置选项。选择“Python 文件”以调试活动文件，代码会执行到断点处停止。此时这一行代码会高亮显示，代码的执行过程也会暂停。在调试时，状态栏会变成橙色。\n如果变量部分没有自动显示在左边，那么一定要点击运行菜单来查看变量的值。另外，也可以将鼠标指针悬停在源代码中的变量上，你会在提示信息中看到它的值。在顶部，你会看到调试工具栏，上面从左到右有这样几个按钮：继续、单步跳过、单步调试、单步跳出、重启和停止。把鼠标指针悬停在这些按钮上时，你还会看到对应的键盘快捷键。\n按钮的功能：\n1、继续：继续按钮可以让程序继续运行，直到碰到下一个断点或者程序的终点。如果碰到了程序的终点，则调试过程也会停止。\n2、单步跳过：调试器会前进一行。单步跳过意味着调试器在视觉上不会进入不属于当前作用域的那部分代码。例如，它不会进入你在各行中调用的函数，但是这些函数还是会被调用。\n3、单步调试：如果你调用了函数、类，或其他结构，那么单步调试会使调试器进入这个函数或类。如果这个函数或类在不同的文件中，则调试器会为你打开这个文件。\n4、单步跳出：如果你使用单步调试进入了一个函数，则单步跳出会使调试器返回上一层代码，最终你会回到一开始调用单步调试的那一层代码。\n5、重启：停止当前的调试进程并重新启动一个新的调试进程。\n6、停止：停止当前的调试进程。\nB.2 VS Code 中的 Jupyter 笔记本 # 除了在 Web 浏览器中运行 Jupyter 笔记本，也可以直接在 VS Code 中运行 Jupyter 笔记本。除了笔记本的基本功能之外，VS Code 还提供了一个便利的变量浏览器，以及在不丢失单元格功能的前提下将笔记本转换为标准 Python 文件的选项。这样一来调试器的使用就可以更加方便，在不同笔记本之间复制粘贴单元格也会更加便捷。\nB.2.1 运行 Jupyter 笔记本 # 点击活动栏中的资源管理器图标，打开配套代码库中的 ch05.ipynb。接下来，需要在弹出窗口中点击信任以使我们的笔记本成为受信任的笔记本。为了让笔记本的布局和 VS Code 的其他部分更协调，VS Code 中的笔记本看起来和浏览器中的布局会有点儿不一样。不过使用体验依然是一样的，连同快捷键也是如此。我们首先按下快捷键 Shift+Enter 来运行前 3 个单元格。如果 Jupyter 笔记本服务器没有启动，那么此时服务器会随之启动（你会在笔记本的右上方看到服务器的状态）。然后，点击笔记本顶部菜单中的计算器按钮：如图 B-2 所示，此时变量浏览器会显示出来，你可以在其中看到现有的所有变量的值。也就是说，你只会在这里看到来自已运行的单元格的变量。\nVS Code 中保存 Jupyter 笔记本：要在 VS Code 中保存笔记本，需要使用笔记本顶部的保存按钮，或是在 Windows 中按下快捷键 Ctrl+S。\n如果使用了像嵌套列表、NumPy 数组、DataFrame 一类的数据结构，那么可以双击变量来打开数据查看器，你会看到熟悉的表格式视图。下图展示了双击变量 df 后显示的数据查看器。\nB.2.2 带有代码单元格的 Python 脚本 # 为了在标准 Python 文件中使用 Jupyter 笔记本单元格，VS Code 使用了一种特殊的组件来表示单元格：# %%。要转换现有的 Jupyter 笔记本，可以打开该笔记本并点击笔记本顶部的 export 按钮。这样就可以在命令面板中选择“Python 文件”。不过，我们不会转换现有的文件，而是会新建一个叫作 cell.py 的文件，其中有如下内容：\n# %%\r3 + 4\r# %% [markdown]\r# # 这是标题\r#\r# 一些markdown内容 Markdown 单元格需要以 # %% [markdown] 开头，整个单元格必须被标记为注释。如果你想将这样的文件作为笔记本运行，那么可以将鼠标指针悬停在第一个单元格上，点击显示的“运行本单元格及下方单元格”链接。Python 交互式窗口会在右侧打开，如图所示。\n要将文件导出为 ipynb 格式，需要点击 Python 交互式窗口顶部的 save 图标。Python 交互式窗口还在底部提供了一个单元格，你可以在这里交互地执行代码。和 Jupyter 笔记本不同，使用常规的 Python 文件可以利用 VS Code 调试器，并使版本控制更加方便，因为输出单元格会被忽略（在版本发生变化时，输出单元格总是会产生大量烦人的信息）。\n","date":"2024-06-18","externalUrl":null,"permalink":"/archives/excel-python%E9%A3%9E%E9%80%9F%E6%90%9E%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%84%E7%90%86%E4%B9%8B-python-%E5%85%A5%E9%97%A8/","section":"历史文档","summary":"","title":"Excel Python:飞速搞定数据分析与处理之 Python 入门","type":"archives"},{"content":"\r第一部分 Python 入门 # 前言：本系列文章为作者个人学习 Python 数据处理的学习笔记，其中对于书上的一些案例进行了本地实现，以及在实现过程中对出现的一些问题进行了解决和知识拓展，希望可以为阅读笔记的朋友们提供一些帮助。\n第一章 为什么要用 Python 为 Excel 编程 # 1.1 Excel 作为一门编程语言 # 1.1.2 编程最佳实践 # 最重要的编程最佳实践，涉及关注点分离、DRY 原则、测试和版本控制。\n1. 关注点分离 # 编程最重要的设计原则之一就是关注点分离（separation of concerns），有时候也称作模块化（modularity）。一系列相关的功能应当被视作程序中一个独立的部分来处 理，从而可以在不影响应用程序其他部分的情况下，轻松地替换这一部分.\n一个应用程序通常被分为如下 3 层:\n• 表示层（presentation layer）：这一层是你可以看到并与之交互的部分，也就是所谓的用户界面。\n• 业务层（business layer）：这一层负责特定应用程序的逻辑。\n• 数据层（data layer）：这一层负责访问数据。\n2. DRY 原则 # 意思是“不要自我重复”（don’t repeat yourself），没有重复的代码意味着代码行数更少，错误也更少，代码自然也就更容易维护。\n3. 测试 # 专业软件开发人员测试代码，会写单元测试（unit test）。 这是一种可以测试程序各个组件的机制。单元测试会确保程序中的每一个函数都正常工作。大部分编程语言会提供一种自动执行单元测试的方法。执行自动测试可以使代码库的可靠性大幅提升，并且在一定程度上，测试会确保在编辑代码时不会破坏当前正常工作的代码。\n通常程序员会对单元测试进行配置，每当代码被提交到版本控制系统的时候，它就会自动运行。\n4. 版本控制 # 专业程序员会使用版本控制（version control）系统，或者称为源代码控制（source control）系统。版本控制系统（version control system，VCS）会不断跟踪源代码的更改，让你能够看到是谁进行了更改，更改了什么，什么时候更改的，为什么更改， 并且在任何时候都能还原到过去的版本。当今最受欢迎的版本控制系统是 Git。\n通常专业程序员都会结合像GitHub、GitLab、Bitbucket 和 Azure DevOps 这样的 Web 平台来使用 Git，这些平台可以让你提出所谓的拉取请求 （pull request）和合并请求（merge request）。这些操作可以让开发者正式地请求负责人将他 们的更改合并到主数据库中。一次拉取请求会提供如下信息：\n• 更改的作者； • 更改发生的时间； • 在提交信息（commit message）中描述的更改目的； • 在 diff 视图（其中新代码以绿色高亮显示，删掉的代码以红色高亮显示）中展示的更改细节。\n1.1.3 现代 Excel # 1. Power Query 和 Power Pivot # Power Query 可以连接各种数据源，包括 Excel 工作簿、CSV 文件、SQL 数据库，等等。核心功能是处理一张工作表装不下的数据集。在加载数据之后，你还可以通过额外的操作来清理、操作数据，使之成为 Excel 可用的形式。\nPower Pivot 和 Power Query 联系密切，利用 Power Query 获取和清理数据之后，就该 Power Pivot 上场了。Power Pivot 以一种引人入胜的方式直接在 Excel 中分析和呈现数据。可以把它视作一种传统意义上的数据透视表。和 Power Query 一样， 它也可以处理大型数据集。Power Pivot 可以用关系和层次来定义形式上的数据模型， 并且可以通过 DAX 公式语言添加计算列。\n2. Power BI # Power BI 是在 2015 年发布的一个独立应用程序。Power BI 通过在交互式仪表板中可视化巨大的数据集使其更容易理解。Power BI 的商业版可以让你在线和他人合作，并共享仪表板。Power BI 自 2018 年起就支持 Python 脚本了。\n1.2 用在 Excel 上的 Python # Excel 的主要功能是存储数据、分析数据和可视化数据。而 Python 在科学计算方面也极其\n强大，天生就适合搭配 Excel 工作。\n1.2.1 可读性和可维护性 # 良好的可读性使得发现错误和维护代码更加容易，Python 会强制将视觉缩进和代码逻辑对齐，从而避免可读性问题。当你在 if 语句或 for 循环中使用代码块时，Python 依靠缩进来定义代码块。\n使用缩进定义代码块的原因在于，编程时大部分时间是花费在维护代码而不是现写新的代码上。可读性好的代码可以帮助新进程序员回顾过去、了解现状。\n1.2.2 标准库和包管理器 # Python 通过标准库提供了丰富的内置工具。Python 社群喜欢称之为“自带电池”。尽管 Python 标准库涵盖了大量的功能，但还是有一些功能难以编写，又或是使用标准库来实现效率很低。这个时候就该 PyPI 上场了。PyPI 代表 Python Package Index（Python 包目录），它是任何人（包括你！）都可以上传开源 Python 包的巨大仓库，利用这些包可以扩展 Python 的功能。\n如果想更方便地从互联网上获取数据，可以安装 Requests 包来获取一系列强大又好用的命令。要安装一个包，需要在命令提示符或者终端中使用 Python 的包管理器，即 pip。pip 是 pip installs packages 的递归缩写。\n为什么包管理器如此重要。一个主要原因是，任何优质的包可能不仅依赖于 Python 标准库，还会依赖于 PyPI 上的其他开源包。而这些依赖项又可能会依赖其他的包，层层递进。pip 会递归地检查一个包的依赖项和子依赖项，并逐一下载安装。你还可以使用 pip 轻松地更新包，以保持各个依赖项都是最新版本。pip 让你能够坚守 DRY 原则，因为不用重新发明轮子或者复制粘贴 PyPI 上已有的包。有了 pip 和 PyPI，你就有了一套统一的机制来分发和安装依赖项——这正是 Excel 的插件所欠缺的。\n1.2.3 科学计算 # 诸如 NumPy、SciPy 和 pandas 之类的科学计算库提供了一种简洁的方式来表达数学问题。\n1.2.5 跨平台兼容性 # 即便在一台运行着 Windows 或者 macOS 的本地计算机上开发，在某个时候你也可能会想让代码在一台服务器或者云端上运行。服务器会通过其运算能力，让代码按计划执行，并使应用程序可以从任何地方访问。\n第二章 开发环境 # 先安装好 Anaconda Python 发行版。除了安装 Python，Anaconda 还会安装 Anaconda Prompt 和 Jupyter 笔记本。它们是贯穿本书的两种关键工具。Anaconda Prompt 是一种特殊的命令提示符（用 Windows 的话来说）或者终端（用 macOS 的话来说），我们可以通过它来运行 Python 脚本和一些本书中会用到的命令行工具。Jupyter 笔记本让我们可以交互地处理数据、代码和图表，可以说它是 Excel 工作簿的强力竞争者。在体验了 Jupyter 笔记本之后，我们会安装一个强大的文本编辑器——Visual Studio Code（VS Code）。VS Code 内置了集成终端，用它来编写、执行和调试 Python 代码非常方便。\n2.1 Anaconda Python 发行版 # 2.1.2 Anaconda Prompt # Anaconda Prompt 实际上就是 Windows 中的一个命令提示符或者 macOS 中的终端，只不过它配置好了 Python 解释器和第三方包。Anaconda Prompt 是执行 Python 代码的最基本的工具，本书会大量使用它来执行 Python 脚本和各种包提供的命令行工具。\n在 Windows 中，输入 dir 并按回车键。命令提示符会打印出当前所在目录的内容。\n输入 cd Down 并按 tab 键。cd 代表切换目录。如果位于 home 文件夹中，那么 Anaconda Prompt 极有可能会将刚才输入的内容自动补全为 cd Downloads。\n注意，如果路径以你当前所在目录中的文件夹名或文件名开始，那么你用的就是相对路径，比如 cd Downloads。如果想离开当前目录，可以输入绝对路径，比如在 Windows 中输入 cd C:\\Users。\n切换至父目录（上一级目录），需要输入 cd .. 然后按回车键（确保在 cd 和两点之间有一个空格）。将这个命令和目录名相结合，如果你想先返回上一级目录，然后进入 Desktop，可以输入 cd ..\\Desktop。\n2.1.3 Python REPL：交互式 Python 会话 # 交互式 Python 会话也被称为 REPL，意思是读取 – 求值 – 输出循环（read-eval-print loop），Python 会读取你的输入，对其求值，然后立即输出结果并等待下一次输入。\n要退出 Python 会话，需要输入 quit() 并按回车键。也可以在 Windows 中按下快捷键\nCtrl+Z，然后按回车键。\n2.1.4 包管理器：Conda 和 pip # Python 的包管理器 pip，它负责下载、安装、更新和卸载 Python 包及其依赖项和子依赖项。虽然 Anaconda 也可以配合 pip 工作，但是它还有一个名为 Conda 的内置包管理器。Conda 的一大优势是不仅可以安装 Python 包，还可以安装多种版本的 Python 解释器。一言以蔽之：软件包可以为 Python 添加标准库中所没有的功能。\n在使用 Anaconda 的情况下，应该尽可能地用 Conda 安装各种软件包。而 pip 只是用来安装那些在 Conda 中找不到的软件包。不然的话 Conda 可能会覆盖你用 pip 安装的包。\n表 2-2 列出了最常用的命令。这些命令必须在 Anaconda Prompt 中输入，可以让你安装、更新和卸载第三方包。\n查看安装的 Anaconda 发行版中已经安装了哪些包，可以输入以下代码：\n(base)\u0026gt; conda list 安装 Plotly 和 xlutils，这两个包都可以在 Conda 中找到：\n(base)\u0026gt; conda install plotly xlutils 执行这条命令之后，Conda 会向你表明它要干些什么，你需要输入 y 并按回车键表示确认。\n通过 pip 来安装 pyxlsb 和 pytrends，这两个包 Conda 中没有：\n(base)\u0026gt; pip install pyxlsb pytrends 和 Conda 不一样，pip 在你按回车键之后会立即开始安装而不需要确认。\n2.1.5 Conda 环境 # Anaconda Prompt 每行开头的 (base) 到底是什么。它是当前激活的 Conda 环境的名称。Conda 环境是一个被隔离的“Python 世界”，有着特定版本的 Python 和一系列安装好的包。为什么非要这么做呢？当你同时开发多个项目的时候，各个项目会有不同的需求：一个项目可能需要 Python 3.8 和 pandas 0.25.0，而另一个项目可能需要 Python 3.9 和 pandas 1.0.0。由于为 pandas 0.25.0 编写的代码往往需要进行修改才能用到 pandas 1.0.0 上，因此不能只更新 Python 和 pandas 而保持代码原封不动。为每个项目都配置一个 Conda 环境可以保证它们使用正确的依赖项运行。Conda 环境虽然是 Anaconda 发行版的专有概念，但虚拟环境是所有 Python 发行版的通用概念。相比之下 Conda 环境更加强大，因为它不仅可以管理多个版本的软件包，还可以轻松管理不同版本的 Python 解释器。\n创建新项目时，为每个项目使用单独的 Conda 环境或者虚拟环境是很好的实践方式，这可以让你规避不同项目之间的依赖冲突。\n详情可见附录 A\n2.2 Jupyter 笔记本 # 在数据科学领域，人们热衷于使用 Jupyter 笔记本来运行代码。它把格式规整的可执行 Python 代码、图片和图表融合到一个交互式笔记本中，并且这个笔记本是运行在浏览器中的。Jupyter 笔记本对初学者很友好，在教学、原型开发、研究等领域极为受欢迎，极大地方便了可重现的研究。\nJupyter 笔记本可以快速准备、分析和可视化数据，这和工作簿的用例几乎相同。它已然成了 Excel 的竞争者。但和 Excel 不同，Jupyter 笔记本是用 Python 代码来完成这些工作的，而不是用鼠标在 Excel 中点来点去。Jupyter 笔记本的另一个优势是，它不会把数据和业务逻辑混在一起。Jupyter 笔记本会负责代码和图表，使用来自外部 CSV 文件或者数据库中的数据。Jupyter 笔记本在本地和远程服务器上都可以运行，一般来说，服务器要比本地机器性能更强，它可以在无人值守的情况下运行代码。\n2.2.1 运行 Jupyter 笔记本 # 在 Anaconda Prompt 中，切换至配套代码库所在目录，这里使用创建的虚拟环境 xl38，然后启动 Jupyter 笔记本服务器：\n(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; F:\r(xl38)\u0026gt; cd F:\\Python\\python-for-excel-1st-edition\r(xl38)\u0026gt; jupyter notebook 打开的 Jupyter 仪表板会显示执行命令时所在目录中的文件。在 Jupyter 仪表板的右上方，点击新建，在下拉列表中选择 xl38，这里需要激活连接新建的虚拟环境 xl38（具体可见文档：Python 开发环境安装流程.md 中的 Jupyter 代码编辑器的虚拟环境连接 Jupyter），过程如下：\n(xl38) C:\\Users\\SHY\u0026gt;pip install ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simple\r(xl38) C:\\Users\\SHY\u0026gt;python -m ipykernel install --user --name=xl38 浏览器会为你的第一个空白笔记本打开新的标签页：\n点击 Jupyter logo 旁边的 Untitled，为工作簿取一个更有意义的名字，比如 first_notebook。\n2.2.2 笔记本单元格 # 输入 3 + 4，然后点击上面菜单栏中的运行按钮，或者用更方便的快捷键：Shift+ 回车。单元格中的代码将会执行，并把结果输出到单元格下方，然后跳到下一个单元格。由于目前我们只有一个单元格，因此笔记本会在下面插入一个空白单元格。现在再仔细看一下，当单元格正在计算时，会显示 In [*]；在计算完成时，星号就变成了数字，也就是 In [1]。在这个单元格下方你会看到对应的输出单元格，而且和输入单元格有相同的编号：Out [1]。每当你运行一个单元格，编号就会加 1，这个编号可以帮助你识别单元格执行的顺序。\n**注意：**如果单元格的最后一行返回了一个值，那么它会自动输出到 Jupyter 笔记本的 Out [ ] 单元格中。然而，如果你使用的是 print 函数或者发生了异常，则相应的输出会直接显示在 In 单元格下方而没有 Out [ ] 标签。\n单元格有不同的类型，我们需要关注以下两种。\n1、代码：默认类型。需要执行 Python 代码时就会用到它。\n2、Markdown：Markdown 是一种格式化语法，它使用标准的文本字符来格式化文本。可以用它在笔记本中添加格式规整的解释和说明。\n要把单元格的类型切换为 Markdown，先选中单元格，然后在单元格模式下拉菜单中选 Markdown，\n在将一个空单元格切换为 Markdown 单元格后，输入下列文本，这是对 Markdown 语法规则的介绍\n# 这是一级标题\r## 这是二级标题\r你可以让你的文本变成*斜体*、**粗体**或`等宽字体`\r* 这是项目符号\r* 又一个项目符号 按下快捷键 Shift+ 回车之后，这段文本会被渲染成格式规整的 HTML。Markdown 单元格还可以添加图片、视频或公式。\n2.2.3 编辑模式与命令模式 # 当和 Jupyter 笔记本中的单元格互动时，你要么处于编辑模式（editing mode），要么处于命令模式（command mode）。\n编辑模式：点击一个单元格以启动编辑模式。被选中的单元格边缘会变成绿色，单元格中的光标也会开始闪烁。除了点击单元格，还可以在选中单元格时按回车键。\n命令模式：要切换至命令模式，需要按下 Esc 键。被选中的单元格边缘会变成蓝色且不会出现光标。\n2.2.4 执行顺序很重要 # 假设你的笔记本中有下面这样几个单元格，从上往下执行：\nIn [2]: a = 1\rIn [3]: a\rOut[3]: 1\rIn [4]: a = 2 单元格 Out[3] 会按照预期输出 1。然而，如果你回去再一次执行 In[3]，就会得到下面的结果：\nIn [2]: a = 1\rIn [5]: a\rOut[5]: 2\rIn [4]: a = 2 2.2.5 关闭 Jupyter 笔记本 # 每个笔记本都在一个独立的 Jupyter 内核中运行。内核是运行单元格中 Python 代码的“引擎”。每个内核都会消耗操作系统提供的 CPU 和 RAM 资源。在关闭笔记本时，还需要关闭它的内核，以便内核所占用的资源可以被其他任务重用——从而防止系统变慢。\n最简单的方法是选择菜单中的“文件 \u0026gt; 关闭”。如果只是关闭了浏览器标签页，那么内核并不会自动关闭。另外，在 Jupyter 仪表板中，也可以从运行标签页中关闭正在运行的笔记本。\n要关闭整个 Jupyter 服务器，可以点击 Jupyter 仪表板右上方的退出按钮（logout）。如果已经关闭了浏览器，可以在运行笔记本服务器的 Anaconda Prompt 中按两次快捷键 Ctrl+C，或者连同 Anaconda Prompt 一起关闭。\n2.3 VS Code # 安装并配置 VS Code，它是微软开发的一个免费且开源的文本编辑器。\nJupyter 笔记本虽然对于研究、教学和实验这类互动型的工作流程来说很好用，但是如果想编写针对生产环境的 Python 脚本（这类脚本用不到笔记本的可视化功能），Jupyter 笔记本并非理想之选。对于一些涉及大量文件和多位开发者的复杂项目，Jupyter 笔记本也不是那么好用。\n理论上来讲，可以使用任何文本编辑器（哪怕是记事本也行），但实际上你需要的是一个可以“理解”Python 的编辑器。这样的编辑器至少应该有如下特性。\n1、语法高亮：编辑器会为具有不同语义（函数、字符串、数字，等等）的单词赋予不同的颜色，从而使得代码更容易阅读和理解。\n2、自动补全：自动补全（autocomplete），或者用微软的话来讲叫智能感知（intelliSense），可以为文本组件提供建议，以便你少打字、少打错字。\nVS Code 自 2015 年发布以来就深受开发者喜爱，其融合了纯文本编辑器和全功能 IDE：VS Code 是一个迷你 IDE，囊括了编程所需要的所有工具。除此之外，它还具有如下特性。\n1、跨平台：VS Code 可以在 Windows、macOS 和 Linux 中运行，也有像 GitHub Codespaces 这样的云托管版本。\n2、集成工具：VS Code 内置调试器，支持 Git 版本控制，还有可以用作 Anaconda Prompt 的集成终端。\n3、扩展：包括 Python 支持在内的其他所有功能，都可以以扩展的形式一键安装。\n4、轻量：根据操作系统的不同，VS Code 的安装包仅有 50MB~100MB 大小。\nVS Code 和 Visual Studio\n不要把 VS Code 和名为 Visual Studio 的 IDE 搞混了！虽然也可以用 Visual Studio 来进行 Python 开 发 [Visual Studio 有 PTVS（Python Tools for Visual Studio，适用于 Visual Studio 的 Python 工具）]，但是需要安装很多东西。传统上 Visual Studio 是用来做 .NET 语言（如 C#）开发的。\n2.3.1 安装和配置 # 下载官网：Visual Studio Code - Code Editing. Redefined\n安装的时候注意安装位置，避免安装到 C 盘。VS Code 确实是一个开箱即用的优秀文本编辑器，但是要让它完美配合 Python，还需要进行一些配置。点击活动栏上的扩展图标，然后搜索 Python。安装作者显示为微软（Microsoft）的官方 Python 插件。待其安装完成之后，可以点击需要重新加载按钮来完成安装。或者也可以完全重启 VS Code。\n命令面板：按下 F1 键或者快捷键：Ctrl+Shift+P（Windows 系统）或者 Command-Shift-P（macOS 系统），可以打开命令面板。如果对某些东西拿不准，你首先就应该想到命令面板。VS Code 所有功能的快捷入口都在其中。\nWindows 中，打开命令面板，输入 default profile。选择“终端：选择默认配置文件”这一项，然后按回车键。在下拉菜单中，选择命令提示符并按回车键确认。我们需要这样设置，以便 VS Code 正常激活 Conda 环境。\n2.3.2 执行 Python 脚本 # 虽然可以从 Windows 的开始菜单或者 macOS 的启动台打开 VS Code，但是直接从 Anaconda Prompt 中打开会更快——可以直接用 code 命令启动 VS Code。接下来，打开一个新的 Anaconda Prompt，通过 cd 命令将目录切换到你希望进行操作的地方，然后让 VS Code 打开当前目录（用点表示）：\n(base) C:\\Users\\SHY\u0026gt;conda activate xl38\r(xl38) C:\\Users\\SHY\u0026gt;cd ..\r(xl38) C:\\Users\u0026gt;cd ..\r(xl38) C:\\\u0026gt;D:\r(xl38) D:\\\u0026gt;cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38) D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\u0026gt; 以这种方式启动 VS Code 可以让活动栏中的资源浏览器自动显示启动目录中的内容。\n把鼠标悬停在活动栏的资源管理器中的文件上时，会看到新建文件按钮。点击新建文件，取名为 hello_world.py，然后按回车键。当文件在编辑器中打开之后，输入下面这行代码：\nprint(\u0026#34;hello world!\u0026#34;) 状态栏中，应该可以看到 Python 的版本，比如“Python 3.8.5 64-bit (conda)”。如果点一下，命令面板会显示让你选择一个不同的 Python 解释器（如果你有好几个的话），也包括不同的 Conda 环境。\n在执行脚本之前，一定要先保存。在 Windows 中可以按快捷键 Ctrl+S 进行保存。\n在 VS Code 中，可以通过 Anaconda Prompt 运行，也可以直接点运行按钮。当你要执行一个服务器上的脚本时，可能更多地还是从 Anaconda Prompt 中执行，所以有必要知道具体如何操作。\nAnaconda Prompt：打开 Anaconda Prompt，将 cd 放入脚本所在的文件夹中，按如下方式运行脚本：\n(xl38)\u0026gt; cd cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38)\u0026gt; python hello_world.py\rhello world! 注意，如果你当前不在 Python 文件所在的目录，则需要使用完整路径。\n1、VS Code 中的 Anaconda Prompt：\n不必为了使用 Anaconda Prompt 而从 VS Code 中切换出去。在 VS Code 中可以直接通过快捷键 Ctrl+` 或者“查看 \u0026gt; 终端”菜单项显示集成终端。由于集成终端会在项目所在文件夹中打开，因此也不需要切换目录\n2、VS Code 中的运行按钮\n在 VS Code 中，有一种无须使用 Anaconda Prompt 也能运行代码的简单方法。在编辑 Python 文件时，你会在右上方看到一个播放图标，这就是运行文件按钮。点击这个按钮会自动在底部打开终端并运行代码。\n3、在 VS Code 中打开文件\n当你在资源管理器（位于活动栏）中单击一个文件时，VS Code 会有一些令人意外的默认行为。单击文件后，文件会以预览模式打开，意思就是说如果没有对这个文件进行更改，那么你下一次单击打开的文件会替换掉这个文件的标签页。如果想关掉单击操作的这种行为（变成单击选定文件，双击打开），可以在“首选项 \u0026gt; 设置”中（或者用快捷键，在 Windows 中是 Ctrl+,，在 macOS 中是 Command-,）将“工作台 \u0026gt;‘List: Open Mode’”设置为“doubleClick”。\n拓展：\n第三章 Python 入门 # 本章首先会介绍 Python 的基本数据类型，比如整型和字符串。然后会介绍 Python 的核心概念——索引和切片，使你可以访问一个序列的指定元素。接下来会讲到列表和字典等数据结构，它们可以保存多个对象。之后会介绍 Python 中的控制流：if 语句、for 循环和 while 循环。紧接着是函数和模块的相关知识，它们可以用来组织和架构你的代码。最后会展示应该如何正确格式化 Python 代码。\n3.1 数据类型 # 最常用的数据类型有整型、浮点型、布尔值和字符串。要理解什么是数据类型，需要先解释一下什么是对象。\n3.1.1 对象 # 在 Python 中，一切皆对象（object）。数字、字符串、函数，以及我们会在本章中见到的其他所有东西，它们都是对象。通过提供一系列变量和函数，对象可以让复杂的东西简单化。先来看看变量和函数。\n1、变量：\n在 Python 中，变量（variable）是通过等号给对象赋予的一个名字。 Python 中，可以通过给变量赋值一个新的对象来改变变量的类型。这种行为被称作动态类型：\nIn [2]: a = 3\rprint(a)\ra = \u0026#34;three\u0026#34;\rprint(a)\r3\rthree Python 是区分大小写的，因此 a 和 A 是不同的变量。变量名必须遵守下列规则：\n• 必须以字母或下划线开头；\n• 只能由字母、数字和下划线组成。\n2、函数\n要调用一个函数，需要在函数名后跟上一对圆括号，并在圆括号中提供参数，和数学记法几乎一模一样：\nfunction_name(argument1, argument2, ...) 3、属性和方法\n谈到对象时，变量被称作属性（attribute）1 ，函数被称作方法（method）。你可以通过属性来访问对象的数据，而方法可以用来执行某种操作。你可以通过点号来访问属性和方法，比如 myobject.attribute 和 myobject.method()。\n如果你在写一个赛车游戏，那么很可能需要表示车的对象。car 对象应该有一个 speed 属性，这样你就可以通过 car.speed 来获取车辆的当前速度。或许还可以通过调用加速方法 car.acc.accelerate(10) 来让车辆加速，即让车速增加到每小时 10 英里。\n对象的类型及其行为是由类（class）定义的，因此在前面的例子中，你可能需要编写一个 Car 类。从 Car 类构造 car 对象的过程叫作实例化（instantiation）。要实例化一个对象，需要像调用函数那样去调用类：car = Car()。\n3.1.2 数值类型 # int 和 float 分别表示整数（integer）和浮点数（floating-point number）。通过内置的 type 函数可以获得指定对象的类型：\nIn [3]: type(4)\rOut[3]: int\rIn [4]: type(4.4)\rOut[4]: float 强制让一个数字成为 float 类型而不是 int 类型，可以在后面加一个小数点，或者使用 float 构造器：\nIn [5]: type(4.)\rOut[5]: float\rIn [6]: float(4)\rOut[6]: 4.0 对于整型也是一样的，int 构造器可以将一个 float 值转换为 int。如果小数部分不为零，那么转换时会直接舍去。\nIn [7]: int(4.9)\rOut[7]: 4 Excel 单元格永远保存的是浮点数：从 Excel 单元格读取数字的时候，可能需要先把 float 转换为 int，然后才能把它传给一个需要整型参数的函数。原因是即使 Excel 显示的是整数，但在背后它总是以浮点数形式存储。\n3.1.3 布尔值 # Python 中，布尔类型只有 True 和 False 两种取值，Python 中的布尔运算符 and、or 和 not 全是小写形式。每个 Python 对象都可以被视作 True 或 False。大部分的对象会被视作 True，但 None、False、0 或空数据类型 [ 比如空字符串（下一节中会讲到字符串）] 会被视作 False。\nNone 是一个内置的常量，按照官方文档的说法，它代表“没有值”（the absence of a value）。如果一个函数没有显式地返回值，那么它实际上返回的就是 None。None 可以用来表示 Excel 中的空单元格。\n3.1.4 字符串 # Python 中的字符串既可以用双引号（\u0026quot;）来表示，也可以用单引号（\u0026rsquo;）来表示。唯一的要求是字符串的首尾必须是同一种引号。可以用 + 来拼接字符串，或者用 * 来重复字符串的内容。如果发现字符串的内容还是需要转义，可以用反斜杠来转义字符：\nIn [31]: print(\u0026#34;Don\u0026#39;t wait! \u0026#34; + \u0026#39;Learn how to \u0026#34;speak\u0026#34; Python.\u0026#39;)\rDon\u0026#39;t wait! Learn how to \u0026#34;speak\u0026#34; Python.\rIn [32]: print(\u0026#34;It\u0026#39;s easy to \\\u0026#34;escape\\\u0026#34; characters with a leading \\\\.\u0026#34;)\rIt\u0026#39;s easy to \u0026#34;escape\u0026#34; characters with a leading \\. 当字符串中包含变量的值时，通常可以使用 f 字符串（f-string，格式化字符串字面量，formatted string literal 的缩写）来处理。\nIn [33]: # 注意Python如何在一行中为多个变量赋予多个值\rfirst_adjective, second_adjective = \u0026#34;free\u0026#34;, \u0026#34;open source\u0026#34;\rf\u0026#34;Python is {first_adjective} and {second_adjective}.\u0026#34;\rOut[33]: \u0026#39;Python is free and open source.\u0026#39; 转换大小写：\nIn [34]: \u0026#34;PYTHON\u0026#34;.lower()\rOut[34]: \u0026#39;python\u0026#39;\rIn [35]: \u0026#34;python\u0026#34;.upper()\rOut[35]: \u0026#39;PYTHON\u0026#39; 获取帮助：在 Jupyter 笔记本中，敲入对象后面的点之后按 Tab 键，比如 \u0026ldquo;python\u0026rdquo;.。画面上会出现一个下拉菜单，其中包含了这个对象提供的所有属性和方法。如果你的光标停在一个方法上，比如停在 \u0026ldquo;python\u0026rdquo;.upper() 的括号中，按下快捷键 Shift+Tab 就可以获得这个函数的描述信息。VS Code 会以提示的形式自动显示这些信息。如果你在 Anaconda Prompt 中运行 Python REPL，使用 dir(\u0026ldquo;python\u0026rdquo;) 可以获得可用的属性，而使用 help(\u0026ldquo;python\u0026rdquo;,upper) 可以打印 upper 方法的描述信息。除此之外，也应该经常看一下 Python 的在线文档。如果你在找 pandas 之类的第三方包的文档，可以在 PyPI（Python 包索引）中搜索对应的包，在这里可以找到这些包的主页和文档的链接。\n3.2 索引和切片 # 索引和切片让你可以访问一个序列的指定元素。\n3.2.1 索引 # Python 的索引从 0 开始，意思就是说序列的第一个元素通过 0 来引用。负索引从 -1 开始，你可以用负索引从序列末端引用元素。\n索引的语法如下：\nsequence[index] 访问字符串的指定元素：\nIn [36]: language = \u0026#34;PYTHON\u0026#34;\rIn [37]: language[0]\rOut[37]: \u0026#39;P\u0026#39;\rIn [38]: language[1]\rOut[38]: \u0026#39;Y\u0026#39;\rIn [39]: language[-1]\rOut[39]: \u0026#39;N\u0026#39;\rIn [40]: language[-2]\rOut[40]: \u0026#39;O\u0026#39; 3.2.2 切片 # 如果你想从一个序列中获取一个以上的元素，就要用到切片（slicing）语法：\nsequence[start:stop:step] Python 使用的是左闭右开区间，意思是切片区间包含 start，但不包含 stop。如果省略了 start 或者 stop，则切片会分别包含从头开始或者从末尾开始的所有元素。step 决定了切片的方向和步长。如果令步长为 2，那么切片就会从左到右每两个元素取一个值；如果令步长为 -3，则切片会从右到左每 3 个元素取一个值。默认步长为 1:\nIn [41]: language[:3] # 同language[0:3]\rOut[41]: \u0026#39;PYT\u0026#39;\rIn [42]: language[1:3]\rOut[42]: \u0026#39;YT\u0026#39;\rIn [43]: language[-3:] # 同language[-3:6]\rOut[43]: \u0026#39;HON\u0026#39;\rIn [44]: language[-3:-1]\rOut[44]: \u0026#39;HO\u0026#39;\rIn [45]: language[::2] # 每两个元素取一个\rOut[45]: \u0026#39;PTO\u0026#39;\rIn [46]: language[-1:-4:-1] # 负步长从右到左\rOut[46]: \u0026#39;NOH\u0026#39; Python 也可以将多次索引和切片操作串联起来。如果你想获得最后 3 个字符中的第二个，可以像下面这样做：\nIn [47]: language[-3:][1]\rOut[47]: \u0026#39;O\u0026#39; 上述代码和 language[-2] 是等价的，连续索引并不会简单到哪儿去。但是在索引和切片列表的时候，连续索引会显得更有条理一些。\n3.3 数据结构 # Python 提供了强大的数据结构以便于处理对象集合。本节会介绍列表、字典、元组和集合。虽然每种数据结构有各自的特点，但它们有一个共同特点，即都能存储多个对象。\n3.3.1 列表 # 列表（list）可以存储不同数据类型的多个对象。用途广泛，可以随时使用。创建列表的语法如下：\n[element1, element2, ...] 实例，下面是两个列表，一个保存了一些 Excel 文件的名称，另一个保存了几个数字：\nIn [48]: file_names = [\u0026#34;one.xlsx\u0026#34;, \u0026#34;two.xlsx\u0026#34;, \u0026#34;three.xlsx\u0026#34;]\rnumbers = [1, 2, 3] 和字符串一样，列表也可以用加号进行拼接。下面的代码还体现了列表的一个特性，那就是它可以保存不同类型的对象：\nIn [49]: file_names + numbers\rOut[49]: [\u0026#39;one.xlsx\u0026#39;, \u0026#39;two.xlsx\u0026#39;, \u0026#39;three.xlsx\u0026#39;, 1, 2, 3] 列表也是对象，也可以包含其他列表作为元素。我称之为嵌套列表（nested list）：\nIn [50]: nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 把这种嵌套列表写成多行，你就会发现列表可以很好地表示矩阵和工作表单元格。注意，这些方括号会隐式地让代码跨行（参见“跨行”）。通过索引和切片，你可以获得想要的任何元素。\nIn [51]: cells = [[1, 2, 3],\r[4, 5, 6],\r[7, 8, 9]]\rIn [52]: cells[1] # 第二行\rOut[52]: [4, 5, 6]\rIn [53]: cells[1][1:] # 第二行的第二列和第三列\rOut[53]: [5, 6] 更改列表中的元素：\nIn [56]: users = [\u0026#34;Linda\u0026#34;, \u0026#34;Brian\u0026#34;]\rIn [57]: users.append(\u0026#34;Jennifer\u0026#34;) # 最常用的操作是向列表末尾追加元素\rusers\rOut[57]: [\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;]\rIn [58]: users.insert(0, \u0026#34;Kim\u0026#34;) # 在索引0处插入\u0026#34;Kim\u0026#34;\rusers\rOut[58]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;] 要删除一个元素，可以使用 pop 或者 del。pop 是一个方法，而 del 是一种 Python 语句：\nIn [59]: users.pop() # 在默认情况下，移除并返回最后一个元素\rOut[59]: \u0026#39;Jennifer\u0026#39;\rIn [60]: users\rOut[60]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [61]: del users[0] # del会移除指定索引处的元素 可以对列表进行以下操作：\nIn [62]: len(users) # 长度\rOut[62]: 2\rIn [63]: \u0026#34;Linda\u0026#34; in users # 检查users是否包含\u0026#34;Linda\u0026#34;\rOut[63]: True\rIn [64]: print(sorted(users)) # 返回新的排好序的列表\rprint(users) # 原列表保持不变\r[\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;]\r[\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [65]: users.sort() # 对原列表进行排序\rusers\rOut[65]: [\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;] 也可以把 len 和 in 用在字符串上：\nIn [66]: len(\u0026#34;Python\u0026#34;)\rOut[66]: 6\rIn [67]: \u0026#34;free\u0026#34; in \u0026#34;Python is free and open source.\u0026#34;\rOut[67]: True 要访问列表中的元素，可以通过元素的**位置（索引）**来引用一个元素——但并非任何时候都能知道元素的位置。\n3.3.2 字典 # 字典（dictionary）是键到值的映射。你会经常遇到键 – 值对。创建字典最简单的方法如下：\n{key1: value1, key2: value2, ...} 和索引一样，键也被放在方括号中。下面的代码中，一对货币（键）映射到了汇率（值）：\nIn [68]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rIn [69]: exchange_rates[\u0026#34;EURUSD\u0026#34;] # 访问EURUSD的汇率\rOut[69]: 1.1152 下面的代码展示了如何修改既存的值以及添加新的键 – 值对：\nIn [70]: exchange_rates[\u0026#34;EURUSD\u0026#34;] = 1.2 # 修改已经存在的值\rexchange_rates\rOut[70]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161}\rIn [71]: exchange_rates[\u0026#34;CADUSD\u0026#34;] = 0.714 # 添加新的键–值对\rexchange_rates\rOut[71]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161, \u0026#39;CADUSD\u0026#39;: 0.714} 合并两个或多个字典的最简单的办法是将字典解包（unpack）后再合并到一个新的字典中。在字典前加上两个星号就可以进行解包。如果第二个字典包含第一个字典中的键，那么第一个字典中对应的值会被覆盖。\nIn [72]: {**exchange_rates, **{\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222}}\rOut[72]: {\u0026#39;EURUSD\u0026#39;: 1.2,\r\u0026#39;GBPUSD\u0026#39;: 1.2222,\r\u0026#39;AUDUSD\u0026#39;: 0.6161,\r\u0026#39;CADUSD\u0026#39;: 0.714,\r\u0026#39;SGDUSD\u0026#39;: 0.7004} Python 3.9 引入了管道符号 作为专门的字典合并运算符。上面的表达式可以简化成如下代码：\nexchange_rates | {\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222} get 方法可以在键不存在时返回一个默认值：\nIn [75]: # currencies[100]会引发异常\r# 除了100，还可以尝试任何不存在的键\rcurrencies.get(100, \u0026#34;N/A\u0026#34;)\rOut[75]: \u0026#39;N/A\u0026#39; 3.3.3 元组 # 元组（tuple）和列表类似，只不过它们是不可变的（immutable）：一旦被创建，它们的元素就无法被修改。虽然很多时候元组和列表可以互换使用，但对于那些在整个程序中都不会发生改变的集合来说，元组是不二之选。元组是通过多个被逗号分隔的值创建的：\nmytuple = element1, element2, ... 使用圆括号通常更易于阅读：\nIn [76]: currencies = (\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;) 可以使用访问数组的方法来访问元组，只是不能修改元组的元素。拼接元组会在“暗地里”创建一个新的元组，然后再把新元组绑定到你的变量上：\nIn [77]: currencies[0] # 访问第一个元素\rOut[77]: \u0026#39;EUR\u0026#39;\rIn [78]: # 拼接元组会返回一个新元组\rcurrencies + (\u0026#34;SGD\u0026#34;,)\rOut[78]: (\u0026#39;EUR\u0026#39;, \u0026#39;GBP\u0026#39;, \u0026#39;AUD\u0026#39;, \u0026#39;SGD\u0026#39;) 附录 C 中会解释可变对象和不可变对象之间的区别。\n3.3.4 集合 # 集合（set）是一种没有重复元素的集合（collection）。你自然可以把集合用于集合论的运算中，但在实践中它们经常被用于列表去重或者元组去重。使用花括号创建集合：\n{element1, element2, ...} 要对列表或者元组进行去重，可以像下面这样使用 set 构造器：\nIn [79]: set([\u0026#34;USD\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;])\rOut[79]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;} 还可以进行像交集和并集之类的集合论运算：\nIn [80]: portfolio1 = {\u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CHF\u0026#34;}\rportfolio2 = {\u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CAD\u0026#34;}\rIn [81]: # 同 portfolio2.union(portfolio1)\rportfolio1.union(portfolio2)\rOut[81]: {\u0026#39;CAD\u0026#39;, \u0026#39;CHF\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;}\rIn [82]: # 同 portfolio2.intersection(portfolio1)\rportfolio1.intersection(portfolio2)\rOut[82]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;} 回顾一下刚刚认识的 4 种数据结构，使用前面用过的字面量（literal）记法。另外，列出它们的构造器。和字面量一样，构造器可以创建对应的数据结构，并且通常用于数据结构之间的相互转换。例如，要把元组转换为列表，可以执行以下操作：\nIn [83]: currencies = \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;CHF\u0026#34;\rcurrencies\rOut[83]: (\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;)\rIn [84]: list(currencies)\rOut[84]: [\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;] 3.4 控制流 # 介绍 if 语句、for 循环和 while 循环。if 只会在满足特定条件时执行特定的代码，for 循环和 while 循环会反复执行代码块中的代码。\n3.4.1 代码块和 pass 语句 # 代码块（code block）界定了一段源代码，这段代码会用于一些特定的目的。在 Python 中，代码块通过缩进来体现，而不像包括 VBA 在内的大部分编程语言那样——使用花括号。这就是所谓的有特殊含义的空白（significant white space）。Python 社区坚持使用 4 个空格作为缩进，不过你通常只需要敲一次 Tab 键就行了。Jupyter 笔记本和 VS Code 都会自动将 Tab 键转换为 4 个空格。代码块的前一行总是会以冒号结尾。一旦某一行没有被缩进，代码块就自然结束了。\n3.4.2 if 语句和条件表达式 # 在 Python 中，if 语句本身不需要任何的圆括号。要检查一个值是否为 True，并不需要显式地写这样一个表达式。\n条件表达式（conditional expression）或者三元运算符（ternary operator）可以以一种更紧凑的形式编写 if/else 语句：\nIn [88]: is_important = False\rprint(\u0026#34;important\u0026#34;) if is_important else print(\u0026#34;not important\u0026#34;)\rnot important 3.4.3 for 循环和 while 循环 # for 循环会对一个序列 [ 比如列表、元组、字符串（记住，字符串就是字符的序列）] 进行迭代。\nIn [89]: currencies = [\u0026#34;USD\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;]\rfor currency in currencies:\rprint(currency)\rUSD\rGBP\rAUD 在 Python 中，如果你在 for 循环中需要一个计数器变量，那么可以用内置的 range 函数和enumerate 函数。先来看看 range，它会提供一连串的数字。你可以只提供一个 stop 参数，也可以同时提供 start 参数和 stop 参数，还可以提供一个可选的 step 参数。和切片类似，range 产生的区间包含 start，但不包含 stop，step 决定了步长，默认为 1：\nrange(stop)\rrange(start, stop, step) range 会延迟求值，意思就是说只要你不明确要求求值，它就不会产生指定的序列：\nIn [90]: range(5)\rOut[90]: range(0, 5) 将 range 转换为列表可以解决这个问题：\nIn [91]: list(range(5)) # stop参数\rOut[91]: [0, 1, 2, 3, 4]\rIn [92]: list(range(2, 5, 2)) # start、stop和step 3个参数\rOut[92]: [2, 4] 不过大部分时候没必要把 range 包装成一个列表：\nfor i in range(3):\rprint(i)\r# 输出结果\r0\r1\r2 如果在迭代序列时需要一个计数器变量，那么可以使用 enumerate。它会返回一系列 (index, element) 元组。 在默认情况下，索引从 0 开始，每次循环加 1。在循环中可以这样使用 enumerate：\nfor i, currency in enumerate(currencies):\rprint(i, currency)\r# 输出结果\r0 USD\r1 GBP\r2 AUD 在元组和集合中进行循环与在列表中类似。在字典中进行循环时，Python 会按照键进行循环：\nexchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rfor currency_pair in exchange_rates:\rprint(currency_pair)\r# 输出结果\rEURUSD\rGBPUSD\rAUDUSD items 方法可以以元组的形式同时获得键和对应的值：\nfor currency_pair, exchange_rate in exchange_rates.items():\rprint(currency_pair, exchange_rate)\r# 输出结果\rEURUSD 1.1152\rGBPUSD 1.2454\rAUDUSD 0.6161 break 语句可以跳出循环：\nfor i in range(15):\rif i == 2:\rbreak\relse:\rprint(i)\r# 输出结果\r0\r1 可以使用 continue 语句跳过本轮循环的剩余部分。即程序会使用下一个元素进入下一轮迭代：\nfor i in range(4):\rif i == 2:\rcontinue\relse:\rprint(i)\r# 输出结果\r0\r1\r3 使用 while 循环，循环会在条件不满足时停止：\nn = 0\rwhile n \u0026lt;= 2:\rprint(n)\rn += 1\r# 输出结果\r0\r1\r2 增强赋值：上一个例子中使用了增强赋值（augmented assignment）的写法：n += 1。这和 n = n + 1 是一样的。前面介绍过的其他算术运算符也可以采用同样的写法，比如，可以写成 n -= 1。\n3.4.4 列表、字典和集合推导式 # 假设有如下的货币名称对，你想把美元在后面的元素挑出来。你可能会写下面这样一个 for 循环：\ncurrency_pairs = [\u0026#34;USDJPY\u0026#34;, \u0026#34;USDGBP\u0026#34;, \u0026#34;USDCHF\u0026#34;,\r\u0026#34;USDCAD\u0026#34;, \u0026#34;AUDUSD\u0026#34;, \u0026#34;NZDUSD\u0026#34;]\rusd_quote = []\rfor pair in currency_pairs:\rif pair[3:] == \u0026#34;USD\u0026#34;:\rusd_quote.append(pair[:3])\rusd_quote、\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 这种情况用列表推导式（list comprehension）会更简单。列表推导式是一种更简洁的列表创建方法。\n[pair[:3] for pair in currency_pairs if pair[3:] == \u0026#34;USD\u0026#34;]\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 字典也有字典推导式：\nIn [105]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\r{k: v * 100 for (k, v) in exchange_rates.items()}\rOut[105]: {\u0026#39;EURUSD\u0026#39;: 111.52, \u0026#39;GBPUSD\u0026#39;: 124.54, \u0026#39;AUDUSD\u0026#39;: 61.61} 集合也有集合推导式：\nIn [106]: {s + \u0026#34;USD\u0026#34; for s in [\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;NZD\u0026#34;, \u0026#34;NZD\u0026#34;]}\rOut[106]: {\u0026#39;EURUSD\u0026#39;, \u0026#39;GBPUSD\u0026#39;, \u0026#39;NZDUSD\u0026#39;} 3.5 组织代码 # 如何让代码形成可维护的结构：首先会介绍函数的核心知识，然后如何将代码分成不同的 Python 模块。\n3.5.1 函数 # 即使只是用 Python 来写一些简单的脚本，你仍然会经常编写函数。函数是所有编程语言中最重要的构造，它们可以让你在程序的任何地方重用同样的代码。\n1. 定义函数 # 在 Python 中，需要使用 def 关键字来自定义函数，def 代表函数定义。函数定义的第一行以冒号结束，函数的主体需要缩进。\ndef function_name(required_argument, optional_argument=default_value, ...):\rreturn value1, value2, ... 必需参数：必需参数（required argument）没有默认值。参数之间用逗号隔开。\n可选参数：为参数提供默认值之后，它就成了可选参数（optional argument）。如果没有有意义的默认值，则通常用 None 作为可选参数的默认值。\n返回值：return 语句定义了函数的返回值。如果省略了返回值，那么函数就会自动返回 None。Python 允许你返回以逗号隔开的多个返回值，这很方便。\n来定义一个函数练习一下，这个函数可以将华氏度或者开氏度转换为摄氏度：\nIn [107]: def convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;):\rif source.lower() == \u0026#34;fahrenheit\u0026#34;:\rreturn (degrees-32) * (5/9)\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34; 字符串的 lower 方法可以将给定字符串转换为小写，这样就可以在保持比较字符串的代码照常工作的前提下，接受任何大小写形式的 source 字符串了。完成 convert_to_celsius 的定义后，来看看如何调用它。\n2. 调用函数 # 调用一个函数，可以在函数名后加上一对圆括号，并在其中给出参数。\nvalue1, value2, ... = function_name(positional_arg, arg_name=value, ...) 位置参数：如果将一个值作为位置参数（positional argument，即上面的 positional_arg）传递，那么这个值会被传递给对应位置上的参数。\n关键字参数：以 arg_name=value 这种形式传递的参数，就是关键字参数（keyword argument）。关键字参数的好处是可以以任意顺序传递参数，并且对于读者来说更加直观易懂。如果函数被定义成 f(a, b)，则可以像这样调用：f(b=1, a=2)。\n下面来尝试一下 convert_to_celsius 函数，看看它是如何工作的：\nIn [108]: convert_to_celsius(100, \u0026#34;fahrenheit\u0026#34;) # 位置参数\rOut[108]: 37.77777777777778\rIn [109]: convert_to_celsius(50) # 使用默认值（fahrenheit）\rOut[109]: 10.0\rIn [110]: convert_to_celsius(source=\u0026#34;kelvin\u0026#34;, degrees=0) # 关键字参数\rOut[110]: -273.15 3.5.2 模块和 import 语句 # 为大型项目编写代码时，在一定的时候会需要将代码分成不同的文件，从而保持一种可维护的结构。\nPython 文件的扩展名为 .py，通常我们会把主要的文件称作脚本（script）。如果你想让你的主脚本获得来自其他文件的概念，则需要先导入（import）那个功能。在这种情况下，Python 源文件被称为模块（module）。\n模块只会被导入一次：如果再一次运行 import temperature 单元格，你会注意到 print 函数不会输出任何内容。这是因为 Python 模块在每个会话中只会被导入一次。如果你要导入的模块发生了更改，则需要重启 Python 解释器才能让更改体现出来。在 Jupyter 笔记本中，需要点击“内核 \u0026gt; 重启”。\n在使用 import x from y 这样的语法时，你只导入了指定的对象。这些对象被直接导入主脚本的命名空间（namespace）中，也就是说，如果不看这些 import 语句，你就说不清被导入的对象是在你的 Python 脚本（或者 Jupyter 笔记本）中还是在另一个模块中定义的。\n不要让你的脚本和既存的包重名：一个常见的错误根源是给你的 Python 文件取一个和既存的包同样的名字。如果你要创建一个测试 pandas 功能的文件，那么不要将其命名为 pandas.py，因为这会造成冲突。\n3.5.3 datetime 类 # 要在 Python 中处理日期和时间，可以导入标准库中的 datetime 模块。这个模块包含了一个也叫 datetime 的类，可用于创建 datetime 对象。由于这个类和它所在的模块同名，可能会造成混淆，因此在本书中我会遵循这样的导入规则：import datetime as dt。这样可以更容易区分模块（dt）和类（datetime）。\n到目前为止，我们大部分时候是用字面量（literal）来创建列表和字典之类的对象。字面量指的是一种会被 Python 识别为特定类型对象的语法。对于列表来说就是像 [1, 2, 3] 这种写法。然而，大部分的对象需要调用对应的类来创建——这个过程被称为实例化（instantiation），因此对象也被称作类实例（class instance）。和调用函数一样，调用类也需要在类名后跟上一对圆括号，并在圆括号中提供参数。要实例化 datetime 对象，需要像下面这样调用对应的类：\nimport datetime as dt\rdt.datetime(year, month, day, hour, minute, second, microsecond, timezone) In [118]: # 将datetime模块导入为dt\rimport datetime as dt\rIn [119]: # 调用timestamp以创建datetime对象\rtimestamp = dt.datetime(2020, 1, 31, 14, 30)\rtimestamp\rOut[119]: datetime.datetime(2020, 1, 31, 14, 30)\rIn [120]: # datetime对象提供了多种属性，比如，想要知道它是几号\rtimestamp.day\rOut[120]: 31\rIn [121]: # 两个datetime对象求差会返回一个timedelta对象\rtimestamp - dt.datetime(2020, 1, 14, 12, 0)\rOut[121]: datetime.timedelta(days=17, seconds=9000)\rIn [122]: # 也可以对timedelta进行同样的操作\rtimestamp + dt.timedelta(days=1, hours=4, minutes=11)\rOut[122]: datetime.datetime(2020, 2, 1, 18, 41) 要将 datetime 对象格式化（format）成字符串，可以使用 strftime 方法；要解析（parse）字符串并将其转换为 datetime 对象，可以使用 strptime 函数：\nIn [123]: # 以特定方式格式化datetime对象\r# 也可以使用f字符串: f\u0026#34;{timestamp:%d/%m/%Y %H:%M}\u0026#34;\rtimestamp.strftime(\u0026#34;%d/%m/%Y %H:%M\u0026#34;)\rOut[123]: \u0026#39;31/01/2020 14:30\u0026#39;\rIn [124]: # 将字符串解析为datetime对象\rdt.datetime.strptime(\u0026#34;12.1.2020\u0026#34;, \u0026#34;%d.%m.%Y\u0026#34;)\rOut[124]: datetime.datetime(2020, 1, 12, 0, 0) 3.6 PEP 8：Python 风格指南 # Python 使用所谓的 Python 改进提案（Python Enhancement Proposals，PEP）来讨论新语言特性的引入。Python 代码的风格指南就是其中之一。这些提案一般用数字来表示，代码风格指南就被称作 PEP 8。PEP 8 是一系列提供给 Python 社区的风格建议。如果使用相同代码的所有人都遵循相同的代码风格，那么写出的代码可读性就会更高。在开源的世界中，会有很多互不相识的程序员开发同一个项目，此时遵循相同的代码风格会显得尤为重要。\n\u0026#34;\u0026#34;\u0026#34;这个脚本展示了一些PEP 8的规则 ➊\r\u0026#34;\u0026#34;\u0026#34;\rimport datetime as dt ➋\rTEMPERATURE_SCALES = (\u0026#34;fahrenheit\u0026#34;, \u0026#34;kelvin\u0026#34;,\r\u0026#34;celsius\u0026#34;) ➌\r➍\rclass TemperatureConverter: ➎\rpass # 暂时不做任何事 ➏\rdef convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;): ➐\r\u0026#34;\u0026#34;\u0026#34;这个函数将华氏度或开氏度转化为摄氏度 ➑\r\u0026#34;\u0026#34;\u0026#34;\rif source.lower() == \u0026#34;fahrenheit\u0026#34;: ➒\rreturn (degrees-32) * (5/9) ➓\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34;\rcelsius = convert_to_celsius(44, source=\u0026#34;fahrenheit\u0026#34;)\t11\rnon_celsius_scales = TEMPERATURE_SCALES[:-1]\t12\rprint(\u0026#34;Current time: \u0026#34; + dt.datetime.now().isoformat())\rprint(f\u0026#34;The temperature in Celsius is: {celsius}\u0026#34;) ➊ 在文件顶部用文档字符串（docstring）解释这个脚本或者模块做了些什么。文档字符串是一种特殊的字符串，它用 3 个引号引用。除了作为代码的文档，它还可以用来编写跨越多行的字符串。如果你的字符串中有很多双引号或单引号，那么也可以用文档字符串来避免转义。\n➋ 所有的导入语句都应该放在文件顶部，一行一个导入。从标准库导入的内容放在前面，然后是第三方包，最后是自己编写的模块。\n➌ 用大写字母和下划线表示常量。每行的长度不超过 79 个字符。尽可能地利用圆括号、方括号或花括号隐式跨行。\n➍ 类、函数和其他代码之间用两个空行隔开。\n➎ 尽管很多类像 datetime 一样使用小写字母命名，但是你自己编写的类也应该使用首字母大写的名称（CapitalizedWords）。有关类的更多内容请参见附录 C。\n➏ 行内注释应该和代码间隔至少两个空格。代码块应该用 4 个空格缩进。\n➐ 在能够提高可读性的情况下，函数和参数应该使用小写字母和下划线命名。不要在参数名和默认值之间使用空格。\n➑ 函数的文档字符串应当列出函数参数并解释其意义。\n➒ 冒号前后不要使用空格。\n➓ 可以在算术运算符前后使用空格。如果同时使用了优先级不同的运算符，则应当考虑在优先级最低的运算符前后添加空格。在本例中，由于乘号的优先级最低，因此它的前后被添加了空格。\n11：变量名称使用小写字母。在可以提升可读性的前提下使用下划线。为变量赋值时，在等号前后添加空格。不过在调用函数时，不要在关键字参数前后使用空格。\n12：在进行索引和切片时，不要在方括号前后使用空格。\n3.6.1 PEP 8 和 VS Code # 在使用 VS Code 时，确保代码严格遵循 PEP 8 的最简单方法是使用代码检查器（linter）。代码检查器会检查源代码中的语法和风格错误。vscode 怎么检查代码 • Worktile 社区\n3.6.2 类型提示 # Python 3.5 引入了一个叫作类型提示（type hint）的特性。类型提示也被称为类型标注（type annotation），它允许你声明变量的数据类型。类型提示并不是强制性的，它也不会影响 Python 解释器执行代码。其主要目的是让 VS Code 之类的文本编辑器可以在代码执行前捕获更多错误，不过它也可以增强编辑器的自动补全功能。\nmypy 是用于有类型标注的 Python 代码的最受欢迎的类型检查器，是 VS Code 提供的一种代码检查器。要理解类型标注如何工作，先来看下面这段没有类型提示的代码：\nx = 1\rdef hello(name):\rreturn f\u0026#34;Hello {name}!\u0026#34; 现在加上类型提示：\nx: int = 1\rdef hello(name: str) -\u0026gt; str:\rreturn f\u0026#34;Hello {name}!\u0026#34; 一般来说，类型提示在较大的项目中才会更有用。\n附录 A Conda 环境 # A.1 创建新的 Conda 环境 # 在 Anaconda Prompt 中执行下列命令以创建一个名为 xl38 的新环境，该环境使用了 Python 3.8：\n(base)\u0026gt; conda create --name xl38 python=3.8 安装完成之后，像下面这样激活新的环境：\n(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; 环境名称已从 base 变更为 xl38。现在你可以使用 Conda 或者 pip 在新环境中安装各种包，且不会影响任何其他的环境。（提醒一句：只有在 Conda 中找不到想要的包时才使用 pip。）\n首先，再次确认你处于 xl38 环境中，即 Anaconda Prompt 显示的是 (xl38)，然后像下面这样安装 Conda 包（注意，这里需要更换为国内镜像源更快）：\n(xl38)\u0026gt; conda install lxml=4.6.1 matplotlib=3.3.2 notebook=6.1.4 openpyxl=3.0.5 pandas=1.1.3 pillow=8.0.1 plotly=4.14.1 flake8=3.8.4 python-dateutil=2.8.1 requests=2.24.0 sqlalchemy=1.3.20 xlrd=1.2.0 xlsxwriter=1.3.7 xlutils=2.0.0 xlwings=0.20.8 xlwt=1.3.0 确认安装计划之后，最后再来使用 pip 安装剩下的两个包。\n(xl38)\u0026gt; pip install pyxlsb==1.0.7 pytrends==4.7.3 这里安装时出现问题，更换镜像源不行的话，需要关闭梯子的系统代理，参考如下：\npip 安装 Python 包时的 SSL 错误\n如果不想使用 base 环境而想使用 xl38 环境来运行本书中的所有示例代码，那么每次启动 Anaconda Prompt 时一定要执行如下命令来激活 xl38 环境：\n(base)\u0026gt; conda activate xl38 也就是说，每当本书代码中的 Anaconda Prompt 显示为 (base)\u0026gt; 时，你看到的应该是 (xl38)\u0026gt;。\n要停用环境并回到 base 环境，可以输入如下命令：\n(xl38)\u0026gt; conda deactivate 想彻底删除环境，可以运行以下命令：\n(base)\u0026gt; conda env remove --name xl38 除了按照上面的步骤手动创建 xl38 环境，也可以利用本书配套代码库的 conda 文件夹中的\nxl38.yml 环境文件。执行下面的命令就可以完成所有工作：\n(base)\u0026gt; cd C:\\Users\\username\\python-for-excel\\conda\r(base)\u0026gt; conda env create -f xl38.yml\r(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; A.2 禁用自动激活 # 如果不希望在每次启动 Anaconda Prompt 时自动激活 base 环境，你可以禁用它：这样你就需要在命令提示符（Windows 系统）或终端（macOS 系统）中手动输入 conda activate base 才能使用 Python。\n在 Windows 中，你需要使用一般的命令提示符而不是 Anaconda Prompt。下面的步骤可以在普通的命令提示符中启用 conda 命令。一定要将第一行中的路径替换成你的计算机上的 Anaconda 安装目录：\n\u0026gt; cd C:\\Users\\username\\Anaconda3\\condabin\r\u0026gt; conda init cmd.exe 现在你的普通命令提示符已经配置好 Conda，接下来就可以像下面这样激活 base 环境了。\n\u0026gt; conda activate base\r(base)\u0026gt; 附录 B 高级 VS Code 功能 # B.1 调试器 # 首先在 VS Code 中打开配套代码库的 debugging.py 文件。然后点击第 4 行左边的空白处，你会看到一个红点，这就是断点，代码会在此处暂停执行。接下来按下 F5 键开始调试：命令面板会显示调试配置选项。选择“Python 文件”以调试活动文件，代码会执行到断点处停止。此时这一行代码会高亮显示，代码的执行过程也会暂停。在调试时，状态栏会变成橙色。\n如果变量部分没有自动显示在左边，那么一定要点击运行菜单来查看变量的值。另外，也可以将鼠标指针悬停在源代码中的变量上，你会在提示信息中看到它的值。在顶部，你会看到调试工具栏，上面从左到右有这样几个按钮：继续、单步跳过、单步调试、单步跳出、重启和停止。把鼠标指针悬停在这些按钮上时，你还会看到对应的键盘快捷键。\n按钮的功能：\n1、继续：继续按钮可以让程序继续运行，直到碰到下一个断点或者程序的终点。如果碰到了程序的终点，则调试过程也会停止。\n2、单步跳过：调试器会前进一行。单步跳过意味着调试器在视觉上不会进入不属于当前作用域的那部分代码。例如，它不会进入你在各行中调用的函数，但是这些函数还是会被调用。\n3、单步调试：如果你调用了函数、类，或其他结构，那么单步调试会使调试器进入这个函数或类。如果这个函数或类在不同的文件中，则调试器会为你打开这个文件。\n4、单步跳出：如果你使用单步调试进入了一个函数，则单步跳出会使调试器返回上一层代码，最终你会回到一开始调用单步调试的那一层代码。\n5、重启：停止当前的调试进程并重新启动一个新的调试进程。\n6、停止：停止当前的调试进程。\nB.2 VS Code 中的 Jupyter 笔记本 # 除了在 Web 浏览器中运行 Jupyter 笔记本，也可以直接在 VS Code 中运行 Jupyter 笔记本。除了笔记本的基本功能之外，VS Code 还提供了一个便利的变量浏览器，以及在不丢失单元格功能的前提下将笔记本转换为标准 Python 文件的选项。这样一来调试器的使用就可以更加方便，在不同笔记本之间复制粘贴单元格也会更加便捷。\nB.2.1 运行 Jupyter 笔记本 # 点击活动栏中的资源管理器图标，打开配套代码库中的 ch05.ipynb。接下来，需要在弹出窗口中点击信任以使我们的笔记本成为受信任的笔记本。为了让笔记本的布局和 VS Code 的其他部分更协调，VS Code 中的笔记本看起来和浏览器中的布局会有点儿不一样。不过使用体验依然是一样的，连同快捷键也是如此。我们首先按下快捷键 Shift+Enter 来运行前 3 个单元格。如果 Jupyter 笔记本服务器没有启动，那么此时服务器会随之启动（你会在笔记本的右上方看到服务器的状态）。然后，点击笔记本顶部菜单中的计算器按钮：如图 B-2 所示，此时变量浏览器会显示出来，你可以在其中看到现有的所有变量的值。也就是说，你只会在这里看到来自已运行的单元格的变量。\nVS Code 中保存 Jupyter 笔记本：要在 VS Code 中保存笔记本，需要使用笔记本顶部的保存按钮，或是在 Windows 中按下快捷键 Ctrl+S。\n如果使用了像嵌套列表、NumPy 数组、DataFrame 一类的数据结构，那么可以双击变量来打开数据查看器，你会看到熟悉的表格式视图。下图展示了双击变量 df 后显示的数据查看器。\nB.2.2 带有代码单元格的 Python 脚本 # 为了在标准 Python 文件中使用 Jupyter 笔记本单元格，VS Code 使用了一种特殊的组件来表示单元格：# %%。要转换现有的 Jupyter 笔记本，可以打开该笔记本并点击笔记本顶部的 export 按钮。这样就可以在命令面板中选择“Python 文件”。不过，我们不会转换现有的文件，而是会新建一个叫作 cell.py 的文件，其中有如下内容：\n# %%\r3 + 4\r# %% [markdown]\r# # 这是标题\r#\r# 一些markdown内容 Markdown 单元格需要以 # %% [markdown] 开头，整个单元格必须被标记为注释。如果你想将这样的文件作为笔记本运行，那么可以将鼠标指针悬停在第一个单元格上，点击显示的“运行本单元格及下方单元格”链接。Python 交互式窗口会在右侧打开，如图所示。\n要将文件导出为 ipynb 格式，需要点击 Python 交互式窗口顶部的 save 图标。Python 交互式窗口还在底部提供了一个单元格，你可以在这里交互地执行代码。和 Jupyter 笔记本不同，使用常规的 Python 文件可以利用 VS Code 调试器，并使版本控制更加方便，因为输出单元格会被忽略（在版本发生变化时，输出单元格总是会产生大量烦人的信息）。\n","date":"2024-06-18","externalUrl":null,"permalink":"/posts/excel-python%E9%A3%9E%E9%80%9F%E6%90%9E%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%84%E7%90%86%E4%B9%8B-python-%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/","section":"Posts","summary":"","title":"Excel Python:飞速搞定数据分析与处理之 Python 入门笔记","type":"posts"},{"content":"\r第一部分 Python 入门 # 前言：本系列文章为作者个人学习 Python 数据处理的学习笔记，其中对于书上的一些案例进行了本地实现，以及在实现过程中对出现的一些问题进行了解决和知识拓展，希望可以为阅读笔记的朋友们提供一些帮助。\n第一章 为什么要用 Python 为 Excel 编程 # 1.1 Excel 作为一门编程语言 # 1.1.2 编程最佳实践 # 最重要的编程最佳实践，涉及关注点分离、DRY 原则、测试和版本控制。\n1. 关注点分离 # 编程最重要的设计原则之一就是关注点分离（separation of concerns），有时候也称作模块化（modularity）。一系列相关的功能应当被视作程序中一个独立的部分来处 理，从而可以在不影响应用程序其他部分的情况下，轻松地替换这一部分.\n一个应用程序通常被分为如下 3 层:\n• 表示层（presentation layer）：这一层是你可以看到并与之交互的部分，也就是所谓的用户界面。\n• 业务层（business layer）：这一层负责特定应用程序的逻辑。\n• 数据层（data layer）：这一层负责访问数据。\n2. DRY 原则 # 意思是“不要自我重复”（don’t repeat yourself），没有重复的代码意味着代码行数更少，错误也更少，代码自然也就更容易维护。\n3. 测试 # 专业软件开发人员测试代码，会写单元测试（unit test）。 这是一种可以测试程序各个组件的机制。单元测试会确保程序中的每一个函数都正常工作。大部分编程语言会提供一种自动执行单元测试的方法。执行自动测试可以使代码库的可靠性大幅提升，并且在一定程度上，测试会确保在编辑代码时不会破坏当前正常工作的代码。\n通常程序员会对单元测试进行配置，每当代码被提交到版本控制系统的时候，它就会自动运行。\n4. 版本控制 # 专业程序员会使用版本控制（version control）系统，或者称为源代码控制（source control）系统。版本控制系统（version control system，VCS）会不断跟踪源代码的更改，让你能够看到是谁进行了更改，更改了什么，什么时候更改的，为什么更改， 并且在任何时候都能还原到过去的版本。当今最受欢迎的版本控制系统是 Git。\n通常专业程序员都会结合像GitHub、GitLab、Bitbucket 和 Azure DevOps 这样的 Web 平台来使用 Git，这些平台可以让你提出所谓的拉取请求 （pull request）和合并请求（merge request）。这些操作可以让开发者正式地请求负责人将他 们的更改合并到主数据库中。一次拉取请求会提供如下信息：\n• 更改的作者； • 更改发生的时间； • 在提交信息（commit message）中描述的更改目的； • 在 diff 视图（其中新代码以绿色高亮显示，删掉的代码以红色高亮显示）中展示的更改细节。\n1.1.3 现代 Excel # 1. Power Query 和 Power Pivot # Power Query 可以连接各种数据源，包括 Excel 工作簿、CSV 文件、SQL 数据库，等等。核心功能是处理一张工作表装不下的数据集。在加载数据之后，你还可以通过额外的操作来清理、操作数据，使之成为 Excel 可用的形式。\nPower Pivot 和 Power Query 联系密切，利用 Power Query 获取和清理数据之后，就该 Power Pivot 上场了。Power Pivot 以一种引人入胜的方式直接在 Excel 中分析和呈现数据。可以把它视作一种传统意义上的数据透视表。和 Power Query 一样， 它也可以处理大型数据集。Power Pivot 可以用关系和层次来定义形式上的数据模型， 并且可以通过 DAX 公式语言添加计算列。\n2. Power BI # Power BI 是在 2015 年发布的一个独立应用程序。Power BI 通过在交互式仪表板中可视化巨大的数据集使其更容易理解。Power BI 的商业版可以让你在线和他人合作，并共享仪表板。Power BI 自 2018 年起就支持 Python 脚本了。\n1.2 用在 Excel 上的 Python # Excel 的主要功能是存储数据、分析数据和可视化数据。而 Python 在科学计算方面也极其\n强大，天生就适合搭配 Excel 工作。\n1.2.1 可读性和可维护性 # 良好的可读性使得发现错误和维护代码更加容易，Python 会强制将视觉缩进和代码逻辑对齐，从而避免可读性问题。当你在 if 语句或 for 循环中使用代码块时，Python 依靠缩进来定义代码块。\n使用缩进定义代码块的原因在于，编程时大部分时间是花费在维护代码而不是现写新的代码上。可读性好的代码可以帮助新进程序员回顾过去、了解现状。\n1.2.2 标准库和包管理器 # Python 通过标准库提供了丰富的内置工具。Python 社群喜欢称之为“自带电池”。尽管 Python 标准库涵盖了大量的功能，但还是有一些功能难以编写，又或是使用标准库来实现效率很低。这个时候就该 PyPI 上场了。PyPI 代表 Python Package Index（Python 包目录），它是任何人（包括你！）都可以上传开源 Python 包的巨大仓库，利用这些包可以扩展 Python 的功能。\n如果想更方便地从互联网上获取数据，可以安装 Requests 包来获取一系列强大又好用的命令。要安装一个包，需要在命令提示符或者终端中使用 Python 的包管理器，即 pip。pip 是 pip installs packages 的递归缩写。\n为什么包管理器如此重要。一个主要原因是，任何优质的包可能不仅依赖于 Python 标准库，还会依赖于 PyPI 上的其他开源包。而这些依赖项又可能会依赖其他的包，层层递进。pip 会递归地检查一个包的依赖项和子依赖项，并逐一下载安装。你还可以使用 pip 轻松地更新包，以保持各个依赖项都是最新版本。pip 让你能够坚守 DRY 原则，因为不用重新发明轮子或者复制粘贴 PyPI 上已有的包。有了 pip 和 PyPI，你就有了一套统一的机制来分发和安装依赖项——这正是 Excel 的插件所欠缺的。\n1.2.3 科学计算 # 诸如 NumPy、SciPy 和 pandas 之类的科学计算库提供了一种简洁的方式来表达数学问题。\n1.2.5 跨平台兼容性 # 即便在一台运行着 Windows 或者 macOS 的本地计算机上开发，在某个时候你也可能会想让代码在一台服务器或者云端上运行。服务器会通过其运算能力，让代码按计划执行，并使应用程序可以从任何地方访问。\n第二章 开发环境 # 先安装好 Anaconda Python 发行版。除了安装 Python，Anaconda 还会安装 Anaconda Prompt 和 Jupyter 笔记本。它们是贯穿本书的两种关键工具。Anaconda Prompt 是一种特殊的命令提示符（用 Windows 的话来说）或者终端（用 macOS 的话来说），我们可以通过它来运行 Python 脚本和一些本书中会用到的命令行工具。Jupyter 笔记本让我们可以交互地处理数据、代码和图表，可以说它是 Excel 工作簿的强力竞争者。在体验了 Jupyter 笔记本之后，我们会安装一个强大的文本编辑器——Visual Studio Code（VS Code）。VS Code 内置了集成终端，用它来编写、执行和调试 Python 代码非常方便。\n2.1 Anaconda Python 发行版 # 2.1.2 Anaconda Prompt # Anaconda Prompt 实际上就是 Windows 中的一个命令提示符或者 macOS 中的终端，只不过它配置好了 Python 解释器和第三方包。Anaconda Prompt 是执行 Python 代码的最基本的工具，本书会大量使用它来执行 Python 脚本和各种包提供的命令行工具。\n在 Windows 中，输入 dir 并按回车键。命令提示符会打印出当前所在目录的内容。\n输入 cd Down 并按 tab 键。cd 代表切换目录。如果位于 home 文件夹中，那么 Anaconda Prompt 极有可能会将刚才输入的内容自动补全为 cd Downloads。\n注意，如果路径以你当前所在目录中的文件夹名或文件名开始，那么你用的就是相对路径，比如 cd Downloads。如果想离开当前目录，可以输入绝对路径，比如在 Windows 中输入 cd C:\\Users。\n切换至父目录（上一级目录），需要输入 cd .. 然后按回车键（确保在 cd 和两点之间有一个空格）。将这个命令和目录名相结合，如果你想先返回上一级目录，然后进入 Desktop，可以输入 cd ..\\Desktop。\n2.1.3 Python REPL：交互式 Python 会话 # 交互式 Python 会话也被称为 REPL，意思是读取 – 求值 – 输出循环（read-eval-print loop），Python 会读取你的输入，对其求值，然后立即输出结果并等待下一次输入。\n要退出 Python 会话，需要输入 quit() 并按回车键。也可以在 Windows 中按下快捷键\nCtrl+Z，然后按回车键。\n2.1.4 包管理器：Conda 和 pip # Python 的包管理器 pip，它负责下载、安装、更新和卸载 Python 包及其依赖项和子依赖项。虽然 Anaconda 也可以配合 pip 工作，但是它还有一个名为 Conda 的内置包管理器。Conda 的一大优势是不仅可以安装 Python 包，还可以安装多种版本的 Python 解释器。一言以蔽之：软件包可以为 Python 添加标准库中所没有的功能。\n在使用 Anaconda 的情况下，应该尽可能地用 Conda 安装各种软件包。而 pip 只是用来安装那些在 Conda 中找不到的软件包。不然的话 Conda 可能会覆盖你用 pip 安装的包。\n表 2-2 列出了最常用的命令。这些命令必须在 Anaconda Prompt 中输入，可以让你安装、更新和卸载第三方包。\n查看安装的 Anaconda 发行版中已经安装了哪些包，可以输入以下代码：\n(base)\u0026gt; conda list 安装 Plotly 和 xlutils，这两个包都可以在 Conda 中找到：\n(base)\u0026gt; conda install plotly xlutils 执行这条命令之后，Conda 会向你表明它要干些什么，你需要输入 y 并按回车键表示确认。\n通过 pip 来安装 pyxlsb 和 pytrends，这两个包 Conda 中没有：\n(base)\u0026gt; pip install pyxlsb pytrends 和 Conda 不一样，pip 在你按回车键之后会立即开始安装而不需要确认。\n2.1.5 Conda 环境 # Anaconda Prompt 每行开头的 (base) 到底是什么。它是当前激活的 Conda 环境的名称。Conda 环境是一个被隔离的“Python 世界”，有着特定版本的 Python 和一系列安装好的包。为什么非要这么做呢？当你同时开发多个项目的时候，各个项目会有不同的需求：一个项目可能需要 Python 3.8 和 pandas 0.25.0，而另一个项目可能需要 Python 3.9 和 pandas 1.0.0。由于为 pandas 0.25.0 编写的代码往往需要进行修改才能用到 pandas 1.0.0 上，因此不能只更新 Python 和 pandas 而保持代码原封不动。为每个项目都配置一个 Conda 环境可以保证它们使用正确的依赖项运行。Conda 环境虽然是 Anaconda 发行版的专有概念，但虚拟环境是所有 Python 发行版的通用概念。相比之下 Conda 环境更加强大，因为它不仅可以管理多个版本的软件包，还可以轻松管理不同版本的 Python 解释器。\n创建新项目时，为每个项目使用单独的 Conda 环境或者虚拟环境是很好的实践方式，这可以让你规避不同项目之间的依赖冲突。\n详情可见附录 A\n2.2 Jupyter 笔记本 # 在数据科学领域，人们热衷于使用 Jupyter 笔记本来运行代码。它把格式规整的可执行 Python 代码、图片和图表融合到一个交互式笔记本中，并且这个笔记本是运行在浏览器中的。Jupyter 笔记本对初学者很友好，在教学、原型开发、研究等领域极为受欢迎，极大地方便了可重现的研究。\nJupyter 笔记本可以快速准备、分析和可视化数据，这和工作簿的用例几乎相同。它已然成了 Excel 的竞争者。但和 Excel 不同，Jupyter 笔记本是用 Python 代码来完成这些工作的，而不是用鼠标在 Excel 中点来点去。Jupyter 笔记本的另一个优势是，它不会把数据和业务逻辑混在一起。Jupyter 笔记本会负责代码和图表，使用来自外部 CSV 文件或者数据库中的数据。Jupyter 笔记本在本地和远程服务器上都可以运行，一般来说，服务器要比本地机器性能更强，它可以在无人值守的情况下运行代码。\n2.2.1 运行 Jupyter 笔记本 # 在 Anaconda Prompt 中，切换至配套代码库所在目录，这里使用创建的虚拟环境 xl38，然后启动 Jupyter 笔记本服务器：\n(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; cd ..\r(xl38)\u0026gt; F:\r(xl38)\u0026gt; cd F:\\Python\\python-for-excel-1st-edition\r(xl38)\u0026gt; jupyter notebook 打开的 Jupyter 仪表板会显示执行命令时所在目录中的文件。在 Jupyter 仪表板的右上方，点击新建，在下拉列表中选择 xl38，这里需要激活连接新建的虚拟环境 xl38（具体可见文档：Python 开发环境安装流程.md 中的 Jupyter 代码编辑器的虚拟环境连接 Jupyter），过程如下：\n(xl38) C:\\Users\\SHY\u0026gt;pip install ipykernel -i https://pypi.tuna.tsinghua.edu.cn/simple\r(xl38) C:\\Users\\SHY\u0026gt;python -m ipykernel install --user --name=xl38 浏览器会为你的第一个空白笔记本打开新的标签页：\n点击 Jupyter logo 旁边的 Untitled，为工作簿取一个更有意义的名字，比如 first_notebook。\n2.2.2 笔记本单元格 # 输入 3 + 4，然后点击上面菜单栏中的运行按钮，或者用更方便的快捷键：Shift+ 回车。单元格中的代码将会执行，并把结果输出到单元格下方，然后跳到下一个单元格。由于目前我们只有一个单元格，因此笔记本会在下面插入一个空白单元格。现在再仔细看一下，当单元格正在计算时，会显示 In [*]；在计算完成时，星号就变成了数字，也就是 In [1]。在这个单元格下方你会看到对应的输出单元格，而且和输入单元格有相同的编号：Out [1]。每当你运行一个单元格，编号就会加 1，这个编号可以帮助你识别单元格执行的顺序。\n**注意：**如果单元格的最后一行返回了一个值，那么它会自动输出到 Jupyter 笔记本的 Out [ ] 单元格中。然而，如果你使用的是 print 函数或者发生了异常，则相应的输出会直接显示在 In 单元格下方而没有 Out [ ] 标签。\n单元格有不同的类型，我们需要关注以下两种。\n1、代码：默认类型。需要执行 Python 代码时就会用到它。\n2、Markdown：Markdown 是一种格式化语法，它使用标准的文本字符来格式化文本。可以用它在笔记本中添加格式规整的解释和说明。\n要把单元格的类型切换为 Markdown，先选中单元格，然后在单元格模式下拉菜单中选 Markdown，\n在将一个空单元格切换为 Markdown 单元格后，输入下列文本，这是对 Markdown 语法规则的介绍\n# 这是一级标题\r## 这是二级标题\r你可以让你的文本变成*斜体*、**粗体**或`等宽字体`\r* 这是项目符号\r* 又一个项目符号 按下快捷键 Shift+ 回车之后，这段文本会被渲染成格式规整的 HTML。Markdown 单元格还可以添加图片、视频或公式。\n2.2.3 编辑模式与命令模式 # 当和 Jupyter 笔记本中的单元格互动时，你要么处于编辑模式（editing mode），要么处于命令模式（command mode）。\n编辑模式：点击一个单元格以启动编辑模式。被选中的单元格边缘会变成绿色，单元格中的光标也会开始闪烁。除了点击单元格，还可以在选中单元格时按回车键。\n命令模式：要切换至命令模式，需要按下 Esc 键。被选中的单元格边缘会变成蓝色且不会出现光标。\n2.2.4 执行顺序很重要 # 假设你的笔记本中有下面这样几个单元格，从上往下执行：\nIn [2]: a = 1\rIn [3]: a\rOut[3]: 1\rIn [4]: a = 2 单元格 Out[3] 会按照预期输出 1。然而，如果你回去再一次执行 In[3]，就会得到下面的结果：\nIn [2]: a = 1\rIn [5]: a\rOut[5]: 2\rIn [4]: a = 2 2.2.5 关闭 Jupyter 笔记本 # 每个笔记本都在一个独立的 Jupyter 内核中运行。内核是运行单元格中 Python 代码的“引擎”。每个内核都会消耗操作系统提供的 CPU 和 RAM 资源。在关闭笔记本时，还需要关闭它的内核，以便内核所占用的资源可以被其他任务重用——从而防止系统变慢。\n最简单的方法是选择菜单中的“文件 \u0026gt; 关闭”。如果只是关闭了浏览器标签页，那么内核并不会自动关闭。另外，在 Jupyter 仪表板中，也可以从运行标签页中关闭正在运行的笔记本。\n要关闭整个 Jupyter 服务器，可以点击 Jupyter 仪表板右上方的退出按钮（logout）。如果已经关闭了浏览器，可以在运行笔记本服务器的 Anaconda Prompt 中按两次快捷键 Ctrl+C，或者连同 Anaconda Prompt 一起关闭。\n2.3 VS Code # 安装并配置 VS Code，它是微软开发的一个免费且开源的文本编辑器。\nJupyter 笔记本虽然对于研究、教学和实验这类互动型的工作流程来说很好用，但是如果想编写针对生产环境的 Python 脚本（这类脚本用不到笔记本的可视化功能），Jupyter 笔记本并非理想之选。对于一些涉及大量文件和多位开发者的复杂项目，Jupyter 笔记本也不是那么好用。\n理论上来讲，可以使用任何文本编辑器（哪怕是记事本也行），但实际上你需要的是一个可以“理解”Python 的编辑器。这样的编辑器至少应该有如下特性。\n1、语法高亮：编辑器会为具有不同语义（函数、字符串、数字，等等）的单词赋予不同的颜色，从而使得代码更容易阅读和理解。\n2、自动补全：自动补全（autocomplete），或者用微软的话来讲叫智能感知（intelliSense），可以为文本组件提供建议，以便你少打字、少打错字。\nVS Code 自 2015 年发布以来就深受开发者喜爱，其融合了纯文本编辑器和全功能 IDE：VS Code 是一个迷你 IDE，囊括了编程所需要的所有工具。除此之外，它还具有如下特性。\n1、跨平台：VS Code 可以在 Windows、macOS 和 Linux 中运行，也有像 GitHub Codespaces 这样的云托管版本。\n2、集成工具：VS Code 内置调试器，支持 Git 版本控制，还有可以用作 Anaconda Prompt 的集成终端。\n3、扩展：包括 Python 支持在内的其他所有功能，都可以以扩展的形式一键安装。\n4、轻量：根据操作系统的不同，VS Code 的安装包仅有 50MB~100MB 大小。\nVS Code 和 Visual Studio\n不要把 VS Code 和名为 Visual Studio 的 IDE 搞混了！虽然也可以用 Visual Studio 来进行 Python 开 发 [Visual Studio 有 PTVS（Python Tools for Visual Studio，适用于 Visual Studio 的 Python 工具）]，但是需要安装很多东西。传统上 Visual Studio 是用来做 .NET 语言（如 C#）开发的。\n2.3.1 安装和配置 # 下载官网：Visual Studio Code - Code Editing. Redefined\n安装的时候注意安装位置，避免安装到 C 盘。VS Code 确实是一个开箱即用的优秀文本编辑器，但是要让它完美配合 Python，还需要进行一些配置。点击活动栏上的扩展图标，然后搜索 Python。安装作者显示为微软（Microsoft）的官方 Python 插件。待其安装完成之后，可以点击需要重新加载按钮来完成安装。或者也可以完全重启 VS Code。\n命令面板：按下 F1 键或者快捷键：Ctrl+Shift+P（Windows 系统）或者 Command-Shift-P（macOS 系统），可以打开命令面板。如果对某些东西拿不准，你首先就应该想到命令面板。VS Code 所有功能的快捷入口都在其中。\nWindows 中，打开命令面板，输入 default profile。选择“终端：选择默认配置文件”这一项，然后按回车键。在下拉菜单中，选择命令提示符并按回车键确认。我们需要这样设置，以便 VS Code 正常激活 Conda 环境。\n2.3.2 执行 Python 脚本 # 虽然可以从 Windows 的开始菜单或者 macOS 的启动台打开 VS Code，但是直接从 Anaconda Prompt 中打开会更快——可以直接用 code 命令启动 VS Code。接下来，打开一个新的 Anaconda Prompt，通过 cd 命令将目录切换到你希望进行操作的地方，然后让 VS Code 打开当前目录（用点表示）：\n(base) C:\\Users\\SHY\u0026gt;conda activate xl38\r(xl38) C:\\Users\\SHY\u0026gt;cd ..\r(xl38) C:\\Users\u0026gt;cd ..\r(xl38) C:\\\u0026gt;D:\r(xl38) D:\\\u0026gt;cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38) D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\u0026gt; 以这种方式启动 VS Code 可以让活动栏中的资源浏览器自动显示启动目录中的内容。\n把鼠标悬停在活动栏的资源管理器中的文件上时，会看到新建文件按钮。点击新建文件，取名为 hello_world.py，然后按回车键。当文件在编辑器中打开之后，输入下面这行代码：\nprint(\u0026#34;hello world!\u0026#34;) 状态栏中，应该可以看到 Python 的版本，比如“Python 3.8.5 64-bit (conda)”。如果点一下，命令面板会显示让你选择一个不同的 Python 解释器（如果你有好几个的话），也包括不同的 Conda 环境。\n在执行脚本之前，一定要先保存。在 Windows 中可以按快捷键 Ctrl+S 进行保存。\n在 VS Code 中，可以通过 Anaconda Prompt 运行，也可以直接点运行按钮。当你要执行一个服务器上的脚本时，可能更多地还是从 Anaconda Prompt 中执行，所以有必要知道具体如何操作。\nAnaconda Prompt：打开 Anaconda Prompt，将 cd 放入脚本所在的文件夹中，按如下方式运行脚本：\n(xl38)\u0026gt; cd cd D:\\DevTools\\Jupyter\\python-for-excel-1st-edition\r(xl38)\u0026gt; python hello_world.py\rhello world! 注意，如果你当前不在 Python 文件所在的目录，则需要使用完整路径。\n1、VS Code 中的 Anaconda Prompt：\n不必为了使用 Anaconda Prompt 而从 VS Code 中切换出去。在 VS Code 中可以直接通过快捷键 Ctrl+` 或者“查看 \u0026gt; 终端”菜单项显示集成终端。由于集成终端会在项目所在文件夹中打开，因此也不需要切换目录\n2、VS Code 中的运行按钮\n在 VS Code 中，有一种无须使用 Anaconda Prompt 也能运行代码的简单方法。在编辑 Python 文件时，你会在右上方看到一个播放图标，这就是运行文件按钮。点击这个按钮会自动在底部打开终端并运行代码。\n3、在 VS Code 中打开文件\n当你在资源管理器（位于活动栏）中单击一个文件时，VS Code 会有一些令人意外的默认行为。单击文件后，文件会以预览模式打开，意思就是说如果没有对这个文件进行更改，那么你下一次单击打开的文件会替换掉这个文件的标签页。如果想关掉单击操作的这种行为（变成单击选定文件，双击打开），可以在“首选项 \u0026gt; 设置”中（或者用快捷键，在 Windows 中是 Ctrl+,，在 macOS 中是 Command-,）将“工作台 \u0026gt;‘List: Open Mode’”设置为“doubleClick”。\n拓展：\n第三章 Python 入门 # 本章首先会介绍 Python 的基本数据类型，比如整型和字符串。然后会介绍 Python 的核心概念——索引和切片，使你可以访问一个序列的指定元素。接下来会讲到列表和字典等数据结构，它们可以保存多个对象。之后会介绍 Python 中的控制流：if 语句、for 循环和 while 循环。紧接着是函数和模块的相关知识，它们可以用来组织和架构你的代码。最后会展示应该如何正确格式化 Python 代码。\n3.1 数据类型 # 最常用的数据类型有整型、浮点型、布尔值和字符串。要理解什么是数据类型，需要先解释一下什么是对象。\n3.1.1 对象 # 在 Python 中，一切皆对象（object）。数字、字符串、函数，以及我们会在本章中见到的其他所有东西，它们都是对象。通过提供一系列变量和函数，对象可以让复杂的东西简单化。先来看看变量和函数。\n1、变量：\n在 Python 中，变量（variable）是通过等号给对象赋予的一个名字。 Python 中，可以通过给变量赋值一个新的对象来改变变量的类型。这种行为被称作动态类型：\nIn [2]: a = 3\rprint(a)\ra = \u0026#34;three\u0026#34;\rprint(a)\r3\rthree Python 是区分大小写的，因此 a 和 A 是不同的变量。变量名必须遵守下列规则：\n• 必须以字母或下划线开头；\n• 只能由字母、数字和下划线组成。\n2、函数\n要调用一个函数，需要在函数名后跟上一对圆括号，并在圆括号中提供参数，和数学记法几乎一模一样：\nfunction_name(argument1, argument2, ...) 3、属性和方法\n谈到对象时，变量被称作属性（attribute）1 ，函数被称作方法（method）。你可以通过属性来访问对象的数据，而方法可以用来执行某种操作。你可以通过点号来访问属性和方法，比如 myobject.attribute 和 myobject.method()。\n如果你在写一个赛车游戏，那么很可能需要表示车的对象。car 对象应该有一个 speed 属性，这样你就可以通过 car.speed 来获取车辆的当前速度。或许还可以通过调用加速方法 car.acc.accelerate(10) 来让车辆加速，即让车速增加到每小时 10 英里。\n对象的类型及其行为是由类（class）定义的，因此在前面的例子中，你可能需要编写一个 Car 类。从 Car 类构造 car 对象的过程叫作实例化（instantiation）。要实例化一个对象，需要像调用函数那样去调用类：car = Car()。\n3.1.2 数值类型 # int 和 float 分别表示整数（integer）和浮点数（floating-point number）。通过内置的 type 函数可以获得指定对象的类型：\nIn [3]: type(4)\rOut[3]: int\rIn [4]: type(4.4)\rOut[4]: float 强制让一个数字成为 float 类型而不是 int 类型，可以在后面加一个小数点，或者使用 float 构造器：\nIn [5]: type(4.)\rOut[5]: float\rIn [6]: float(4)\rOut[6]: 4.0 对于整型也是一样的，int 构造器可以将一个 float 值转换为 int。如果小数部分不为零，那么转换时会直接舍去。\nIn [7]: int(4.9)\rOut[7]: 4 Excel 单元格永远保存的是浮点数：从 Excel 单元格读取数字的时候，可能需要先把 float 转换为 int，然后才能把它传给一个需要整型参数的函数。原因是即使 Excel 显示的是整数，但在背后它总是以浮点数形式存储。\n3.1.3 布尔值 # Python 中，布尔类型只有 True 和 False 两种取值，Python 中的布尔运算符 and、or 和 not 全是小写形式。每个 Python 对象都可以被视作 True 或 False。大部分的对象会被视作 True，但 None、False、0 或空数据类型 [ 比如空字符串（下一节中会讲到字符串）] 会被视作 False。\nNone 是一个内置的常量，按照官方文档的说法，它代表“没有值”（the absence of a value）。如果一个函数没有显式地返回值，那么它实际上返回的就是 None。None 可以用来表示 Excel 中的空单元格。\n3.1.4 字符串 # Python 中的字符串既可以用双引号（\u0026quot;）来表示，也可以用单引号（\u0026rsquo;）来表示。唯一的要求是字符串的首尾必须是同一种引号。可以用 + 来拼接字符串，或者用 * 来重复字符串的内容。如果发现字符串的内容还是需要转义，可以用反斜杠来转义字符：\nIn [31]: print(\u0026#34;Don\u0026#39;t wait! \u0026#34; + \u0026#39;Learn how to \u0026#34;speak\u0026#34; Python.\u0026#39;)\rDon\u0026#39;t wait! Learn how to \u0026#34;speak\u0026#34; Python.\rIn [32]: print(\u0026#34;It\u0026#39;s easy to \\\u0026#34;escape\\\u0026#34; characters with a leading \\\\.\u0026#34;)\rIt\u0026#39;s easy to \u0026#34;escape\u0026#34; characters with a leading \\. 当字符串中包含变量的值时，通常可以使用 f 字符串（f-string，格式化字符串字面量，formatted string literal 的缩写）来处理。\nIn [33]: # 注意Python如何在一行中为多个变量赋予多个值\rfirst_adjective, second_adjective = \u0026#34;free\u0026#34;, \u0026#34;open source\u0026#34;\rf\u0026#34;Python is {first_adjective} and {second_adjective}.\u0026#34;\rOut[33]: \u0026#39;Python is free and open source.\u0026#39; 转换大小写：\nIn [34]: \u0026#34;PYTHON\u0026#34;.lower()\rOut[34]: \u0026#39;python\u0026#39;\rIn [35]: \u0026#34;python\u0026#34;.upper()\rOut[35]: \u0026#39;PYTHON\u0026#39; 获取帮助：在 Jupyter 笔记本中，敲入对象后面的点之后按 Tab 键，比如 \u0026ldquo;python\u0026rdquo;.。画面上会出现一个下拉菜单，其中包含了这个对象提供的所有属性和方法。如果你的光标停在一个方法上，比如停在 \u0026ldquo;python\u0026rdquo;.upper() 的括号中，按下快捷键 Shift+Tab 就可以获得这个函数的描述信息。VS Code 会以提示的形式自动显示这些信息。如果你在 Anaconda Prompt 中运行 Python REPL，使用 dir(\u0026ldquo;python\u0026rdquo;) 可以获得可用的属性，而使用 help(\u0026ldquo;python\u0026rdquo;,upper) 可以打印 upper 方法的描述信息。除此之外，也应该经常看一下 Python 的在线文档。如果你在找 pandas 之类的第三方包的文档，可以在 PyPI（Python 包索引）中搜索对应的包，在这里可以找到这些包的主页和文档的链接。\n3.2 索引和切片 # 索引和切片让你可以访问一个序列的指定元素。\n3.2.1 索引 # Python 的索引从 0 开始，意思就是说序列的第一个元素通过 0 来引用。负索引从 -1 开始，你可以用负索引从序列末端引用元素。\n索引的语法如下：\nsequence[index] 访问字符串的指定元素：\nIn [36]: language = \u0026#34;PYTHON\u0026#34;\rIn [37]: language[0]\rOut[37]: \u0026#39;P\u0026#39;\rIn [38]: language[1]\rOut[38]: \u0026#39;Y\u0026#39;\rIn [39]: language[-1]\rOut[39]: \u0026#39;N\u0026#39;\rIn [40]: language[-2]\rOut[40]: \u0026#39;O\u0026#39; 3.2.2 切片 # 如果你想从一个序列中获取一个以上的元素，就要用到切片（slicing）语法：\nsequence[start:stop:step] Python 使用的是左闭右开区间，意思是切片区间包含 start，但不包含 stop。如果省略了 start 或者 stop，则切片会分别包含从头开始或者从末尾开始的所有元素。step 决定了切片的方向和步长。如果令步长为 2，那么切片就会从左到右每两个元素取一个值；如果令步长为 -3，则切片会从右到左每 3 个元素取一个值。默认步长为 1:\nIn [41]: language[:3] # 同language[0:3]\rOut[41]: \u0026#39;PYT\u0026#39;\rIn [42]: language[1:3]\rOut[42]: \u0026#39;YT\u0026#39;\rIn [43]: language[-3:] # 同language[-3:6]\rOut[43]: \u0026#39;HON\u0026#39;\rIn [44]: language[-3:-1]\rOut[44]: \u0026#39;HO\u0026#39;\rIn [45]: language[::2] # 每两个元素取一个\rOut[45]: \u0026#39;PTO\u0026#39;\rIn [46]: language[-1:-4:-1] # 负步长从右到左\rOut[46]: \u0026#39;NOH\u0026#39; Python 也可以将多次索引和切片操作串联起来。如果你想获得最后 3 个字符中的第二个，可以像下面这样做：\nIn [47]: language[-3:][1]\rOut[47]: \u0026#39;O\u0026#39; 上述代码和 language[-2] 是等价的，连续索引并不会简单到哪儿去。但是在索引和切片列表的时候，连续索引会显得更有条理一些。\n3.3 数据结构 # Python 提供了强大的数据结构以便于处理对象集合。本节会介绍列表、字典、元组和集合。虽然每种数据结构有各自的特点，但它们有一个共同特点，即都能存储多个对象。\n3.3.1 列表 # 列表（list）可以存储不同数据类型的多个对象。用途广泛，可以随时使用。创建列表的语法如下：\n[element1, element2, ...] 实例，下面是两个列表，一个保存了一些 Excel 文件的名称，另一个保存了几个数字：\nIn [48]: file_names = [\u0026#34;one.xlsx\u0026#34;, \u0026#34;two.xlsx\u0026#34;, \u0026#34;three.xlsx\u0026#34;]\rnumbers = [1, 2, 3] 和字符串一样，列表也可以用加号进行拼接。下面的代码还体现了列表的一个特性，那就是它可以保存不同类型的对象：\nIn [49]: file_names + numbers\rOut[49]: [\u0026#39;one.xlsx\u0026#39;, \u0026#39;two.xlsx\u0026#39;, \u0026#39;three.xlsx\u0026#39;, 1, 2, 3] 列表也是对象，也可以包含其他列表作为元素。我称之为嵌套列表（nested list）：\nIn [50]: nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 把这种嵌套列表写成多行，你就会发现列表可以很好地表示矩阵和工作表单元格。注意，这些方括号会隐式地让代码跨行（参见“跨行”）。通过索引和切片，你可以获得想要的任何元素。\nIn [51]: cells = [[1, 2, 3],\r[4, 5, 6],\r[7, 8, 9]]\rIn [52]: cells[1] # 第二行\rOut[52]: [4, 5, 6]\rIn [53]: cells[1][1:] # 第二行的第二列和第三列\rOut[53]: [5, 6] 更改列表中的元素：\nIn [56]: users = [\u0026#34;Linda\u0026#34;, \u0026#34;Brian\u0026#34;]\rIn [57]: users.append(\u0026#34;Jennifer\u0026#34;) # 最常用的操作是向列表末尾追加元素\rusers\rOut[57]: [\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;]\rIn [58]: users.insert(0, \u0026#34;Kim\u0026#34;) # 在索引0处插入\u0026#34;Kim\u0026#34;\rusers\rOut[58]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;, \u0026#39;Jennifer\u0026#39;] 要删除一个元素，可以使用 pop 或者 del。pop 是一个方法，而 del 是一种 Python 语句：\nIn [59]: users.pop() # 在默认情况下，移除并返回最后一个元素\rOut[59]: \u0026#39;Jennifer\u0026#39;\rIn [60]: users\rOut[60]: [\u0026#39;Kim\u0026#39;, \u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [61]: del users[0] # del会移除指定索引处的元素 可以对列表进行以下操作：\nIn [62]: len(users) # 长度\rOut[62]: 2\rIn [63]: \u0026#34;Linda\u0026#34; in users # 检查users是否包含\u0026#34;Linda\u0026#34;\rOut[63]: True\rIn [64]: print(sorted(users)) # 返回新的排好序的列表\rprint(users) # 原列表保持不变\r[\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;]\r[\u0026#39;Linda\u0026#39;, \u0026#39;Brian\u0026#39;]\rIn [65]: users.sort() # 对原列表进行排序\rusers\rOut[65]: [\u0026#39;Brian\u0026#39;, \u0026#39;Linda\u0026#39;] 也可以把 len 和 in 用在字符串上：\nIn [66]: len(\u0026#34;Python\u0026#34;)\rOut[66]: 6\rIn [67]: \u0026#34;free\u0026#34; in \u0026#34;Python is free and open source.\u0026#34;\rOut[67]: True 要访问列表中的元素，可以通过元素的**位置（索引）**来引用一个元素——但并非任何时候都能知道元素的位置。\n3.3.2 字典 # 字典（dictionary）是键到值的映射。你会经常遇到键 – 值对。创建字典最简单的方法如下：\n{key1: value1, key2: value2, ...} 和索引一样，键也被放在方括号中。下面的代码中，一对货币（键）映射到了汇率（值）：\nIn [68]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rIn [69]: exchange_rates[\u0026#34;EURUSD\u0026#34;] # 访问EURUSD的汇率\rOut[69]: 1.1152 下面的代码展示了如何修改既存的值以及添加新的键 – 值对：\nIn [70]: exchange_rates[\u0026#34;EURUSD\u0026#34;] = 1.2 # 修改已经存在的值\rexchange_rates\rOut[70]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161}\rIn [71]: exchange_rates[\u0026#34;CADUSD\u0026#34;] = 0.714 # 添加新的键–值对\rexchange_rates\rOut[71]: {\u0026#39;EURUSD\u0026#39;: 1.2, \u0026#39;GBPUSD\u0026#39;: 1.2454, \u0026#39;AUDUSD\u0026#39;: 0.6161, \u0026#39;CADUSD\u0026#39;: 0.714} 合并两个或多个字典的最简单的办法是将字典解包（unpack）后再合并到一个新的字典中。在字典前加上两个星号就可以进行解包。如果第二个字典包含第一个字典中的键，那么第一个字典中对应的值会被覆盖。\nIn [72]: {**exchange_rates, **{\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222}}\rOut[72]: {\u0026#39;EURUSD\u0026#39;: 1.2,\r\u0026#39;GBPUSD\u0026#39;: 1.2222,\r\u0026#39;AUDUSD\u0026#39;: 0.6161,\r\u0026#39;CADUSD\u0026#39;: 0.714,\r\u0026#39;SGDUSD\u0026#39;: 0.7004} Python 3.9 引入了管道符号 作为专门的字典合并运算符。上面的表达式可以简化成如下代码：\nexchange_rates | {\u0026#34;SGDUSD\u0026#34;: 0.7004, \u0026#34;GBPUSD\u0026#34;: 1.2222} get 方法可以在键不存在时返回一个默认值：\nIn [75]: # currencies[100]会引发异常\r# 除了100，还可以尝试任何不存在的键\rcurrencies.get(100, \u0026#34;N/A\u0026#34;)\rOut[75]: \u0026#39;N/A\u0026#39; 3.3.3 元组 # 元组（tuple）和列表类似，只不过它们是不可变的（immutable）：一旦被创建，它们的元素就无法被修改。虽然很多时候元组和列表可以互换使用，但对于那些在整个程序中都不会发生改变的集合来说，元组是不二之选。元组是通过多个被逗号分隔的值创建的：\nmytuple = element1, element2, ... 使用圆括号通常更易于阅读：\nIn [76]: currencies = (\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;) 可以使用访问数组的方法来访问元组，只是不能修改元组的元素。拼接元组会在“暗地里”创建一个新的元组，然后再把新元组绑定到你的变量上：\nIn [77]: currencies[0] # 访问第一个元素\rOut[77]: \u0026#39;EUR\u0026#39;\rIn [78]: # 拼接元组会返回一个新元组\rcurrencies + (\u0026#34;SGD\u0026#34;,)\rOut[78]: (\u0026#39;EUR\u0026#39;, \u0026#39;GBP\u0026#39;, \u0026#39;AUD\u0026#39;, \u0026#39;SGD\u0026#39;) 附录 C 中会解释可变对象和不可变对象之间的区别。\n3.3.4 集合 # 集合（set）是一种没有重复元素的集合（collection）。你自然可以把集合用于集合论的运算中，但在实践中它们经常被用于列表去重或者元组去重。使用花括号创建集合：\n{element1, element2, ...} 要对列表或者元组进行去重，可以像下面这样使用 set 构造器：\nIn [79]: set([\u0026#34;USD\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;])\rOut[79]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;} 还可以进行像交集和并集之类的集合论运算：\nIn [80]: portfolio1 = {\u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CHF\u0026#34;}\rportfolio2 = {\u0026#34;EUR\u0026#34;, \u0026#34;SGD\u0026#34;, \u0026#34;CAD\u0026#34;}\rIn [81]: # 同 portfolio2.union(portfolio1)\rportfolio1.union(portfolio2)\rOut[81]: {\u0026#39;CAD\u0026#39;, \u0026#39;CHF\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;, \u0026#39;USD\u0026#39;}\rIn [82]: # 同 portfolio2.intersection(portfolio1)\rportfolio1.intersection(portfolio2)\rOut[82]: {\u0026#39;EUR\u0026#39;, \u0026#39;SGD\u0026#39;} 回顾一下刚刚认识的 4 种数据结构，使用前面用过的字面量（literal）记法。另外，列出它们的构造器。和字面量一样，构造器可以创建对应的数据结构，并且通常用于数据结构之间的相互转换。例如，要把元组转换为列表，可以执行以下操作：\nIn [83]: currencies = \u0026#34;USD\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;CHF\u0026#34;\rcurrencies\rOut[83]: (\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;)\rIn [84]: list(currencies)\rOut[84]: [\u0026#39;USD\u0026#39;, \u0026#39;EUR\u0026#39;, \u0026#39;CHF\u0026#39;] 3.4 控制流 # 介绍 if 语句、for 循环和 while 循环。if 只会在满足特定条件时执行特定的代码，for 循环和 while 循环会反复执行代码块中的代码。\n3.4.1 代码块和 pass 语句 # 代码块（code block）界定了一段源代码，这段代码会用于一些特定的目的。在 Python 中，代码块通过缩进来体现，而不像包括 VBA 在内的大部分编程语言那样——使用花括号。这就是所谓的有特殊含义的空白（significant white space）。Python 社区坚持使用 4 个空格作为缩进，不过你通常只需要敲一次 Tab 键就行了。Jupyter 笔记本和 VS Code 都会自动将 Tab 键转换为 4 个空格。代码块的前一行总是会以冒号结尾。一旦某一行没有被缩进，代码块就自然结束了。\n3.4.2 if 语句和条件表达式 # 在 Python 中，if 语句本身不需要任何的圆括号。要检查一个值是否为 True，并不需要显式地写这样一个表达式。\n条件表达式（conditional expression）或者三元运算符（ternary operator）可以以一种更紧凑的形式编写 if/else 语句：\nIn [88]: is_important = False\rprint(\u0026#34;important\u0026#34;) if is_important else print(\u0026#34;not important\u0026#34;)\rnot important 3.4.3 for 循环和 while 循环 # for 循环会对一个序列 [ 比如列表、元组、字符串（记住，字符串就是字符的序列）] 进行迭代。\nIn [89]: currencies = [\u0026#34;USD\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;AUD\u0026#34;]\rfor currency in currencies:\rprint(currency)\rUSD\rGBP\rAUD 在 Python 中，如果你在 for 循环中需要一个计数器变量，那么可以用内置的 range 函数和enumerate 函数。先来看看 range，它会提供一连串的数字。你可以只提供一个 stop 参数，也可以同时提供 start 参数和 stop 参数，还可以提供一个可选的 step 参数。和切片类似，range 产生的区间包含 start，但不包含 stop，step 决定了步长，默认为 1：\nrange(stop)\rrange(start, stop, step) range 会延迟求值，意思就是说只要你不明确要求求值，它就不会产生指定的序列：\nIn [90]: range(5)\rOut[90]: range(0, 5) 将 range 转换为列表可以解决这个问题：\nIn [91]: list(range(5)) # stop参数\rOut[91]: [0, 1, 2, 3, 4]\rIn [92]: list(range(2, 5, 2)) # start、stop和step 3个参数\rOut[92]: [2, 4] 不过大部分时候没必要把 range 包装成一个列表：\nfor i in range(3):\rprint(i)\r# 输出结果\r0\r1\r2 如果在迭代序列时需要一个计数器变量，那么可以使用 enumerate。它会返回一系列 (index, element) 元组。 在默认情况下，索引从 0 开始，每次循环加 1。在循环中可以这样使用 enumerate：\nfor i, currency in enumerate(currencies):\rprint(i, currency)\r# 输出结果\r0 USD\r1 GBP\r2 AUD 在元组和集合中进行循环与在列表中类似。在字典中进行循环时，Python 会按照键进行循环：\nexchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\rfor currency_pair in exchange_rates:\rprint(currency_pair)\r# 输出结果\rEURUSD\rGBPUSD\rAUDUSD items 方法可以以元组的形式同时获得键和对应的值：\nfor currency_pair, exchange_rate in exchange_rates.items():\rprint(currency_pair, exchange_rate)\r# 输出结果\rEURUSD 1.1152\rGBPUSD 1.2454\rAUDUSD 0.6161 break 语句可以跳出循环：\nfor i in range(15):\rif i == 2:\rbreak\relse:\rprint(i)\r# 输出结果\r0\r1 可以使用 continue 语句跳过本轮循环的剩余部分。即程序会使用下一个元素进入下一轮迭代：\nfor i in range(4):\rif i == 2:\rcontinue\relse:\rprint(i)\r# 输出结果\r0\r1\r3 使用 while 循环，循环会在条件不满足时停止：\nn = 0\rwhile n \u0026lt;= 2:\rprint(n)\rn += 1\r# 输出结果\r0\r1\r2 增强赋值：上一个例子中使用了增强赋值（augmented assignment）的写法：n += 1。这和 n = n + 1 是一样的。前面介绍过的其他算术运算符也可以采用同样的写法，比如，可以写成 n -= 1。\n3.4.4 列表、字典和集合推导式 # 假设有如下的货币名称对，你想把美元在后面的元素挑出来。你可能会写下面这样一个 for 循环：\ncurrency_pairs = [\u0026#34;USDJPY\u0026#34;, \u0026#34;USDGBP\u0026#34;, \u0026#34;USDCHF\u0026#34;,\r\u0026#34;USDCAD\u0026#34;, \u0026#34;AUDUSD\u0026#34;, \u0026#34;NZDUSD\u0026#34;]\rusd_quote = []\rfor pair in currency_pairs:\rif pair[3:] == \u0026#34;USD\u0026#34;:\rusd_quote.append(pair[:3])\rusd_quote、\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 这种情况用列表推导式（list comprehension）会更简单。列表推导式是一种更简洁的列表创建方法。\n[pair[:3] for pair in currency_pairs if pair[3:] == \u0026#34;USD\u0026#34;]\r# 输出结果\r[\u0026#39;AUD\u0026#39;, \u0026#39;NZD\u0026#39;] 字典也有字典推导式：\nIn [105]: exchange_rates = {\u0026#34;EURUSD\u0026#34;: 1.1152,\r\u0026#34;GBPUSD\u0026#34;: 1.2454,\r\u0026#34;AUDUSD\u0026#34;: 0.6161}\r{k: v * 100 for (k, v) in exchange_rates.items()}\rOut[105]: {\u0026#39;EURUSD\u0026#39;: 111.52, \u0026#39;GBPUSD\u0026#39;: 124.54, \u0026#39;AUDUSD\u0026#39;: 61.61} 集合也有集合推导式：\nIn [106]: {s + \u0026#34;USD\u0026#34; for s in [\u0026#34;EUR\u0026#34;, \u0026#34;GBP\u0026#34;, \u0026#34;EUR\u0026#34;, \u0026#34;NZD\u0026#34;, \u0026#34;NZD\u0026#34;]}\rOut[106]: {\u0026#39;EURUSD\u0026#39;, \u0026#39;GBPUSD\u0026#39;, \u0026#39;NZDUSD\u0026#39;} 3.5 组织代码 # 如何让代码形成可维护的结构：首先会介绍函数的核心知识，然后如何将代码分成不同的 Python 模块。\n3.5.1 函数 # 即使只是用 Python 来写一些简单的脚本，你仍然会经常编写函数。函数是所有编程语言中最重要的构造，它们可以让你在程序的任何地方重用同样的代码。\n1. 定义函数 # 在 Python 中，需要使用 def 关键字来自定义函数，def 代表函数定义。函数定义的第一行以冒号结束，函数的主体需要缩进。\ndef function_name(required_argument, optional_argument=default_value, ...):\rreturn value1, value2, ... 必需参数：必需参数（required argument）没有默认值。参数之间用逗号隔开。\n可选参数：为参数提供默认值之后，它就成了可选参数（optional argument）。如果没有有意义的默认值，则通常用 None 作为可选参数的默认值。\n返回值：return 语句定义了函数的返回值。如果省略了返回值，那么函数就会自动返回 None。Python 允许你返回以逗号隔开的多个返回值，这很方便。\n来定义一个函数练习一下，这个函数可以将华氏度或者开氏度转换为摄氏度：\nIn [107]: def convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;):\rif source.lower() == \u0026#34;fahrenheit\u0026#34;:\rreturn (degrees-32) * (5/9)\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34; 字符串的 lower 方法可以将给定字符串转换为小写，这样就可以在保持比较字符串的代码照常工作的前提下，接受任何大小写形式的 source 字符串了。完成 convert_to_celsius 的定义后，来看看如何调用它。\n2. 调用函数 # 调用一个函数，可以在函数名后加上一对圆括号，并在其中给出参数。\nvalue1, value2, ... = function_name(positional_arg, arg_name=value, ...) 位置参数：如果将一个值作为位置参数（positional argument，即上面的 positional_arg）传递，那么这个值会被传递给对应位置上的参数。\n关键字参数：以 arg_name=value 这种形式传递的参数，就是关键字参数（keyword argument）。关键字参数的好处是可以以任意顺序传递参数，并且对于读者来说更加直观易懂。如果函数被定义成 f(a, b)，则可以像这样调用：f(b=1, a=2)。\n下面来尝试一下 convert_to_celsius 函数，看看它是如何工作的：\nIn [108]: convert_to_celsius(100, \u0026#34;fahrenheit\u0026#34;) # 位置参数\rOut[108]: 37.77777777777778\rIn [109]: convert_to_celsius(50) # 使用默认值（fahrenheit）\rOut[109]: 10.0\rIn [110]: convert_to_celsius(source=\u0026#34;kelvin\u0026#34;, degrees=0) # 关键字参数\rOut[110]: -273.15 3.5.2 模块和 import 语句 # 为大型项目编写代码时，在一定的时候会需要将代码分成不同的文件，从而保持一种可维护的结构。\nPython 文件的扩展名为 .py，通常我们会把主要的文件称作脚本（script）。如果你想让你的主脚本获得来自其他文件的概念，则需要先导入（import）那个功能。在这种情况下，Python 源文件被称为模块（module）。\n模块只会被导入一次：如果再一次运行 import temperature 单元格，你会注意到 print 函数不会输出任何内容。这是因为 Python 模块在每个会话中只会被导入一次。如果你要导入的模块发生了更改，则需要重启 Python 解释器才能让更改体现出来。在 Jupyter 笔记本中，需要点击“内核 \u0026gt; 重启”。\n在使用 import x from y 这样的语法时，你只导入了指定的对象。这些对象被直接导入主脚本的命名空间（namespace）中，也就是说，如果不看这些 import 语句，你就说不清被导入的对象是在你的 Python 脚本（或者 Jupyter 笔记本）中还是在另一个模块中定义的。\n不要让你的脚本和既存的包重名：一个常见的错误根源是给你的 Python 文件取一个和既存的包同样的名字。如果你要创建一个测试 pandas 功能的文件，那么不要将其命名为 pandas.py，因为这会造成冲突。\n3.5.3 datetime 类 # 要在 Python 中处理日期和时间，可以导入标准库中的 datetime 模块。这个模块包含了一个也叫 datetime 的类，可用于创建 datetime 对象。由于这个类和它所在的模块同名，可能会造成混淆，因此在本书中我会遵循这样的导入规则：import datetime as dt。这样可以更容易区分模块（dt）和类（datetime）。\n到目前为止，我们大部分时候是用字面量（literal）来创建列表和字典之类的对象。字面量指的是一种会被 Python 识别为特定类型对象的语法。对于列表来说就是像 [1, 2, 3] 这种写法。然而，大部分的对象需要调用对应的类来创建——这个过程被称为实例化（instantiation），因此对象也被称作类实例（class instance）。和调用函数一样，调用类也需要在类名后跟上一对圆括号，并在圆括号中提供参数。要实例化 datetime 对象，需要像下面这样调用对应的类：\nimport datetime as dt\rdt.datetime(year, month, day, hour, minute, second, microsecond, timezone) In [118]: # 将datetime模块导入为dt\rimport datetime as dt\rIn [119]: # 调用timestamp以创建datetime对象\rtimestamp = dt.datetime(2020, 1, 31, 14, 30)\rtimestamp\rOut[119]: datetime.datetime(2020, 1, 31, 14, 30)\rIn [120]: # datetime对象提供了多种属性，比如，想要知道它是几号\rtimestamp.day\rOut[120]: 31\rIn [121]: # 两个datetime对象求差会返回一个timedelta对象\rtimestamp - dt.datetime(2020, 1, 14, 12, 0)\rOut[121]: datetime.timedelta(days=17, seconds=9000)\rIn [122]: # 也可以对timedelta进行同样的操作\rtimestamp + dt.timedelta(days=1, hours=4, minutes=11)\rOut[122]: datetime.datetime(2020, 2, 1, 18, 41) 要将 datetime 对象格式化（format）成字符串，可以使用 strftime 方法；要解析（parse）字符串并将其转换为 datetime 对象，可以使用 strptime 函数：\nIn [123]: # 以特定方式格式化datetime对象\r# 也可以使用f字符串: f\u0026#34;{timestamp:%d/%m/%Y %H:%M}\u0026#34;\rtimestamp.strftime(\u0026#34;%d/%m/%Y %H:%M\u0026#34;)\rOut[123]: \u0026#39;31/01/2020 14:30\u0026#39;\rIn [124]: # 将字符串解析为datetime对象\rdt.datetime.strptime(\u0026#34;12.1.2020\u0026#34;, \u0026#34;%d.%m.%Y\u0026#34;)\rOut[124]: datetime.datetime(2020, 1, 12, 0, 0) 3.6 PEP 8：Python 风格指南 # Python 使用所谓的 Python 改进提案（Python Enhancement Proposals，PEP）来讨论新语言特性的引入。Python 代码的风格指南就是其中之一。这些提案一般用数字来表示，代码风格指南就被称作 PEP 8。PEP 8 是一系列提供给 Python 社区的风格建议。如果使用相同代码的所有人都遵循相同的代码风格，那么写出的代码可读性就会更高。在开源的世界中，会有很多互不相识的程序员开发同一个项目，此时遵循相同的代码风格会显得尤为重要。\n\u0026#34;\u0026#34;\u0026#34;这个脚本展示了一些PEP 8的规则 ➊\r\u0026#34;\u0026#34;\u0026#34;\rimport datetime as dt ➋\rTEMPERATURE_SCALES = (\u0026#34;fahrenheit\u0026#34;, \u0026#34;kelvin\u0026#34;,\r\u0026#34;celsius\u0026#34;) ➌\r➍\rclass TemperatureConverter: ➎\rpass # 暂时不做任何事 ➏\rdef convert_to_celsius(degrees, source=\u0026#34;fahrenheit\u0026#34;): ➐\r\u0026#34;\u0026#34;\u0026#34;这个函数将华氏度或开氏度转化为摄氏度 ➑\r\u0026#34;\u0026#34;\u0026#34;\rif source.lower() == \u0026#34;fahrenheit\u0026#34;: ➒\rreturn (degrees-32) * (5/9) ➓\relif source.lower() == \u0026#34;kelvin\u0026#34;:\rreturn degrees - 273.15\relse:\rreturn f\u0026#34;Don\u0026#39;t know how to convert from {source}\u0026#34;\rcelsius = convert_to_celsius(44, source=\u0026#34;fahrenheit\u0026#34;)\t11\rnon_celsius_scales = TEMPERATURE_SCALES[:-1]\t12\rprint(\u0026#34;Current time: \u0026#34; + dt.datetime.now().isoformat())\rprint(f\u0026#34;The temperature in Celsius is: {celsius}\u0026#34;) ➊ 在文件顶部用文档字符串（docstring）解释这个脚本或者模块做了些什么。文档字符串是一种特殊的字符串，它用 3 个引号引用。除了作为代码的文档，它还可以用来编写跨越多行的字符串。如果你的字符串中有很多双引号或单引号，那么也可以用文档字符串来避免转义。\n➋ 所有的导入语句都应该放在文件顶部，一行一个导入。从标准库导入的内容放在前面，然后是第三方包，最后是自己编写的模块。\n➌ 用大写字母和下划线表示常量。每行的长度不超过 79 个字符。尽可能地利用圆括号、方括号或花括号隐式跨行。\n➍ 类、函数和其他代码之间用两个空行隔开。\n➎ 尽管很多类像 datetime 一样使用小写字母命名，但是你自己编写的类也应该使用首字母大写的名称（CapitalizedWords）。有关类的更多内容请参见附录 C。\n➏ 行内注释应该和代码间隔至少两个空格。代码块应该用 4 个空格缩进。\n➐ 在能够提高可读性的情况下，函数和参数应该使用小写字母和下划线命名。不要在参数名和默认值之间使用空格。\n➑ 函数的文档字符串应当列出函数参数并解释其意义。\n➒ 冒号前后不要使用空格。\n➓ 可以在算术运算符前后使用空格。如果同时使用了优先级不同的运算符，则应当考虑在优先级最低的运算符前后添加空格。在本例中，由于乘号的优先级最低，因此它的前后被添加了空格。\n11：变量名称使用小写字母。在可以提升可读性的前提下使用下划线。为变量赋值时，在等号前后添加空格。不过在调用函数时，不要在关键字参数前后使用空格。\n12：在进行索引和切片时，不要在方括号前后使用空格。\n3.6.1 PEP 8 和 VS Code # 在使用 VS Code 时，确保代码严格遵循 PEP 8 的最简单方法是使用代码检查器（linter）。代码检查器会检查源代码中的语法和风格错误。vscode 怎么检查代码 • Worktile 社区\n3.6.2 类型提示 # Python 3.5 引入了一个叫作类型提示（type hint）的特性。类型提示也被称为类型标注（type annotation），它允许你声明变量的数据类型。类型提示并不是强制性的，它也不会影响 Python 解释器执行代码。其主要目的是让 VS Code 之类的文本编辑器可以在代码执行前捕获更多错误，不过它也可以增强编辑器的自动补全功能。\nmypy 是用于有类型标注的 Python 代码的最受欢迎的类型检查器，是 VS Code 提供的一种代码检查器。要理解类型标注如何工作，先来看下面这段没有类型提示的代码：\nx = 1\rdef hello(name):\rreturn f\u0026#34;Hello {name}!\u0026#34; 现在加上类型提示：\nx: int = 1\rdef hello(name: str) -\u0026gt; str:\rreturn f\u0026#34;Hello {name}!\u0026#34; 一般来说，类型提示在较大的项目中才会更有用。\n附录 A Conda 环境 # A.1 创建新的 Conda 环境 # 在 Anaconda Prompt 中执行下列命令以创建一个名为 xl38 的新环境，该环境使用了 Python 3.8：\n(base)\u0026gt; conda create --name xl38 python=3.8 安装完成之后，像下面这样激活新的环境：\n(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; 环境名称已从 base 变更为 xl38。现在你可以使用 Conda 或者 pip 在新环境中安装各种包，且不会影响任何其他的环境。（提醒一句：只有在 Conda 中找不到想要的包时才使用 pip。）\n首先，再次确认你处于 xl38 环境中，即 Anaconda Prompt 显示的是 (xl38)，然后像下面这样安装 Conda 包（注意，这里需要更换为国内镜像源更快）：\n(xl38)\u0026gt; conda install lxml=4.6.1 matplotlib=3.3.2 notebook=6.1.4 openpyxl=3.0.5 pandas=1.1.3 pillow=8.0.1 plotly=4.14.1 flake8=3.8.4 python-dateutil=2.8.1 requests=2.24.0 sqlalchemy=1.3.20 xlrd=1.2.0 xlsxwriter=1.3.7 xlutils=2.0.0 xlwings=0.20.8 xlwt=1.3.0 确认安装计划之后，最后再来使用 pip 安装剩下的两个包。\n(xl38)\u0026gt; pip install pyxlsb==1.0.7 pytrends==4.7.3 这里安装时出现问题，更换镜像源不行的话，需要关闭梯子的系统代理，参考如下：\npip 安装 Python 包时的 SSL 错误\n如果不想使用 base 环境而想使用 xl38 环境来运行本书中的所有示例代码，那么每次启动 Anaconda Prompt 时一定要执行如下命令来激活 xl38 环境：\n(base)\u0026gt; conda activate xl38 也就是说，每当本书代码中的 Anaconda Prompt 显示为 (base)\u0026gt; 时，你看到的应该是 (xl38)\u0026gt;。\n要停用环境并回到 base 环境，可以输入如下命令：\n(xl38)\u0026gt; conda deactivate 想彻底删除环境，可以运行以下命令：\n(base)\u0026gt; conda env remove --name xl38 除了按照上面的步骤手动创建 xl38 环境，也可以利用本书配套代码库的 conda 文件夹中的\nxl38.yml 环境文件。执行下面的命令就可以完成所有工作：\n(base)\u0026gt; cd C:\\Users\\username\\python-for-excel\\conda\r(base)\u0026gt; conda env create -f xl38.yml\r(base)\u0026gt; conda activate xl38\r(xl38)\u0026gt; A.2 禁用自动激活 # 如果不希望在每次启动 Anaconda Prompt 时自动激活 base 环境，你可以禁用它：这样你就需要在命令提示符（Windows 系统）或终端（macOS 系统）中手动输入 conda activate base 才能使用 Python。\n在 Windows 中，你需要使用一般的命令提示符而不是 Anaconda Prompt。下面的步骤可以在普通的命令提示符中启用 conda 命令。一定要将第一行中的路径替换成你的计算机上的 Anaconda 安装目录：\n\u0026gt; cd C:\\Users\\username\\Anaconda3\\condabin\r\u0026gt; conda init cmd.exe 现在你的普通命令提示符已经配置好 Conda，接下来就可以像下面这样激活 base 环境了。\n\u0026gt; conda activate base\r(base)\u0026gt; 附录 B 高级 VS Code 功能 # B.1 调试器 # 首先在 VS Code 中打开配套代码库的 debugging.py 文件。然后点击第 4 行左边的空白处，你会看到一个红点，这就是断点，代码会在此处暂停执行。接下来按下 F5 键开始调试：命令面板会显示调试配置选项。选择“Python 文件”以调试活动文件，代码会执行到断点处停止。此时这一行代码会高亮显示，代码的执行过程也会暂停。在调试时，状态栏会变成橙色。\n如果变量部分没有自动显示在左边，那么一定要点击运行菜单来查看变量的值。另外，也可以将鼠标指针悬停在源代码中的变量上，你会在提示信息中看到它的值。在顶部，你会看到调试工具栏，上面从左到右有这样几个按钮：继续、单步跳过、单步调试、单步跳出、重启和停止。把鼠标指针悬停在这些按钮上时，你还会看到对应的键盘快捷键。\n按钮的功能：\n1、继续：继续按钮可以让程序继续运行，直到碰到下一个断点或者程序的终点。如果碰到了程序的终点，则调试过程也会停止。\n2、单步跳过：调试器会前进一行。单步跳过意味着调试器在视觉上不会进入不属于当前作用域的那部分代码。例如，它不会进入你在各行中调用的函数，但是这些函数还是会被调用。\n3、单步调试：如果你调用了函数、类，或其他结构，那么单步调试会使调试器进入这个函数或类。如果这个函数或类在不同的文件中，则调试器会为你打开这个文件。\n4、单步跳出：如果你使用单步调试进入了一个函数，则单步跳出会使调试器返回上一层代码，最终你会回到一开始调用单步调试的那一层代码。\n5、重启：停止当前的调试进程并重新启动一个新的调试进程。\n6、停止：停止当前的调试进程。\nB.2 VS Code 中的 Jupyter 笔记本 # 除了在 Web 浏览器中运行 Jupyter 笔记本，也可以直接在 VS Code 中运行 Jupyter 笔记本。除了笔记本的基本功能之外，VS Code 还提供了一个便利的变量浏览器，以及在不丢失单元格功能的前提下将笔记本转换为标准 Python 文件的选项。这样一来调试器的使用就可以更加方便，在不同笔记本之间复制粘贴单元格也会更加便捷。\nB.2.1 运行 Jupyter 笔记本 # 点击活动栏中的资源管理器图标，打开配套代码库中的 ch05.ipynb。接下来，需要在弹出窗口中点击信任以使我们的笔记本成为受信任的笔记本。为了让笔记本的布局和 VS Code 的其他部分更协调，VS Code 中的笔记本看起来和浏览器中的布局会有点儿不一样。不过使用体验依然是一样的，连同快捷键也是如此。我们首先按下快捷键 Shift+Enter 来运行前 3 个单元格。如果 Jupyter 笔记本服务器没有启动，那么此时服务器会随之启动（你会在笔记本的右上方看到服务器的状态）。然后，点击笔记本顶部菜单中的计算器按钮：如图 B-2 所示，此时变量浏览器会显示出来，你可以在其中看到现有的所有变量的值。也就是说，你只会在这里看到来自已运行的单元格的变量。\nVS Code 中保存 Jupyter 笔记本：要在 VS Code 中保存笔记本，需要使用笔记本顶部的保存按钮，或是在 Windows 中按下快捷键 Ctrl+S。\n如果使用了像嵌套列表、NumPy 数组、DataFrame 一类的数据结构，那么可以双击变量来打开数据查看器，你会看到熟悉的表格式视图。下图展示了双击变量 df 后显示的数据查看器。\nB.2.2 带有代码单元格的 Python 脚本 # 为了在标准 Python 文件中使用 Jupyter 笔记本单元格，VS Code 使用了一种特殊的组件来表示单元格：# %%。要转换现有的 Jupyter 笔记本，可以打开该笔记本并点击笔记本顶部的 export 按钮。这样就可以在命令面板中选择“Python 文件”。不过，我们不会转换现有的文件，而是会新建一个叫作 cell.py 的文件，其中有如下内容：\n# %%\r3 + 4\r# %% [markdown]\r# # 这是标题\r#\r# 一些markdown内容 Markdown 单元格需要以 # %% [markdown] 开头，整个单元格必须被标记为注释。如果你想将这样的文件作为笔记本运行，那么可以将鼠标指针悬停在第一个单元格上，点击显示的“运行本单元格及下方单元格”链接。Python 交互式窗口会在右侧打开，如图所示。\n要将文件导出为 ipynb 格式，需要点击 Python 交互式窗口顶部的 save 图标。Python 交互式窗口还在底部提供了一个单元格，你可以在这里交互地执行代码。和 Jupyter 笔记本不同，使用常规的 Python 文件可以利用 VS Code 调试器，并使版本控制更加方便，因为输出单元格会被忽略（在版本发生变化时，输出单元格总是会产生大量烦人的信息）。\n","date":"2024-06-18","externalUrl":null,"permalink":"/studynotes/excel-python%E9%A3%9E%E9%80%9F%E6%90%9E%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90%E4%B8%8E%E5%A4%84%E7%90%86%E4%B9%8B-python-%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/","section":"我的学习笔记","summary":"","title":"Excel Python:飞速搞定数据分析与处理之 Python 入门笔记","type":"studynotes"},{"content":" Cloud_Shy 分享热爱 \u0026#x1f60d; 本节包含一些学习笔记，主要用于记录博主本人的学习过程以及促进和广大网友们的交流学习。您还可以参考标签页面的内容。\n","date":"2024-06-18","externalUrl":null,"permalink":"/studynotes/","section":"我的学习笔记","summary":"","title":"我的学习笔记","type":"studynotes"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"在你的文章中添加不同作者的简单示例。\n","externalUrl":null,"permalink":"/authors/","section":"作者介绍","summary":"","title":"作者介绍","type":"authors"}]