<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>夜羽的小作坊</title><description>技术学习与分享</description><link>https://momoyeyu.github.io/</link><language>zh_CN</language><item><title>CMake 入门</title><link>https://momoyeyu.github.io/posts/cmake-introduction/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/cmake-introduction/</guid><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CMake Introduction 的目标不是覆盖 CMake 的全部功能，而是解释一个 C++ 初学者最先需要理解的几件事：CMake 是什么、&lt;code&gt;CMakeLists.txt&lt;/code&gt; 写什么、如何配置和构建项目，以及为什么现代 C++ 项目普遍围绕 target 来组织。&lt;/p&gt;
&lt;p&gt;很多 C++ 初学者第一次看到 &lt;code&gt;CMakeLists.txt&lt;/code&gt; 时，会误以为 CMake 是另一种编译器，或者是 Makefile 的替代语法。更准确地说，CMake 是一个构建系统生成器。&lt;/p&gt;
&lt;p&gt;你写的是项目描述：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;项目叫什么&lt;/li&gt;
&lt;li&gt;用什么语言&lt;/li&gt;
&lt;li&gt;使用哪个 C++ 标准&lt;/li&gt;
&lt;li&gt;哪些源码要编译成可执行程序&lt;/li&gt;
&lt;li&gt;哪些库需要被链接&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CMake 再根据这些描述生成真正的构建文件，比如 Ninja 文件、Makefile 或 Xcode 工程。&lt;/p&gt;
&lt;h2&gt;从手动编译开始&lt;/h2&gt;
&lt;p&gt;假设我们只有一个 C++ 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// main.cpp
#include &amp;lt;iostream&amp;gt;

int main() {
    std::cout &amp;lt;&amp;lt; &quot;Hello, CMake!&quot; &amp;lt;&amp;lt; std::endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不用 CMake 时，可以直接调用编译器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clang++ -std=c++23 -Wall -Wextra -o hello main.cpp
./hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这对单文件程序很直接。但当源码文件变多、要区分 Debug 和 Release、要链接第三方库、要给 IDE 提供项目信息时，手写命令会很快变得难维护。&lt;/p&gt;
&lt;p&gt;CMake 解决的正是这个问题：把构建规则写进项目里。&lt;/p&gt;
&lt;h2&gt;最小 CMake 项目&lt;/h2&gt;
&lt;p&gt;一个最小项目可以长这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello-cmake/
├── CMakeLists.txt
└── main.cpp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

int main() {
    std::cout &amp;lt;&amp;lt; &quot;Hello, CMake!&quot; &amp;lt;&amp;lt; std::endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CMakeLists.txt&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.20)
project(hello_cmake CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(hello main.cpp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是一个完整的 CMake 项目。&lt;/p&gt;
&lt;h2&gt;逐行解释 CMakeLists.txt&lt;/h2&gt;
&lt;p&gt;第一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.20)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;声明项目需要的最低 CMake 版本。这样可以避免旧版本 CMake 不认识某些语法。&lt;/p&gt;
&lt;p&gt;第二行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;project(hello_cmake CXX)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定义项目名，并声明这个项目使用 C++。&lt;code&gt;CXX&lt;/code&gt; 是 CMake 里表示 C++ 语言的名字。&lt;/p&gt;
&lt;p&gt;接下来两行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要求使用 C++23，并且这个要求是必须满足的。如果编译器不支持 C++23，CMake 会在配置阶段报错。&lt;/p&gt;
&lt;p&gt;最后一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_executable(hello main.cpp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定义一个可执行程序。这里的 &lt;code&gt;hello&lt;/code&gt; 是 target 名字，也是最终生成的可执行文件名；&lt;code&gt;main.cpp&lt;/code&gt; 是它的源码文件。&lt;/p&gt;
&lt;p&gt;现代 CMake 的核心概念就是 target。可执行程序是 target，库也是 target。后续的头文件路径、编译选项、链接关系，通常都应该围绕 target 来写。&lt;/p&gt;
&lt;h2&gt;配置、构建、运行&lt;/h2&gt;
&lt;p&gt;进入项目目录后，先配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake -S . -B build -G Ninja
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake --build build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./build/hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是最常见的 CMake 使用流程。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;-S&lt;/code&gt; 和 &lt;code&gt;-B&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;这条命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake -S . -B build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以读成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-S .&lt;/code&gt;：源码目录是当前目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-B build&lt;/code&gt;：构建目录是 &lt;code&gt;build&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;推荐把源码目录和构建目录分开，这叫 out-of-source build。这样源码目录不会混进大量中间文件。想重新来过时，删除 &lt;code&gt;build&lt;/code&gt; 目录即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rm -rf build
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;-G Ninja&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;-G&lt;/code&gt; 用来指定 CMake 的 generator：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake -S . -B build -G Ninja
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;generator 决定 CMake 要生成哪种底层构建系统。&lt;/p&gt;
&lt;p&gt;常见选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ninja&lt;/code&gt;：速度快，适合日常开发&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Unix Makefiles&lt;/code&gt;：生成 Makefile&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Xcode&lt;/code&gt;：生成 Xcode 工程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果不指定 &lt;code&gt;-G&lt;/code&gt;，CMake 会使用当前环境的默认 generator。&lt;/p&gt;
&lt;h2&gt;CMake 和 Makefile 的关系&lt;/h2&gt;
&lt;p&gt;CMake 可以生成 Makefile，但 CMake 本身不是 Makefile。&lt;/p&gt;
&lt;p&gt;手写 Makefile 时，你是在直接告诉 &lt;code&gt;make&lt;/code&gt; 每一步怎么编译：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CXX = clang++
CXXFLAGS = -std=c++23 -Wall -Wextra
TARGET = hello
SRC = main.cpp

$(TARGET): $(SRC)
	$(CXX) $(CXXFLAGS) -o $@ $^

clean:
	rm -f $(TARGET)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而使用 CMake 时，你是在描述项目结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_executable(hello main.cpp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后由 CMake 生成 Makefile、Ninja 文件或 IDE 工程。&lt;/p&gt;
&lt;p&gt;所以，小 demo 可以手写 Makefile；稍微正式一点的 C++ 项目，更常见的选择是 CMake。&lt;/p&gt;
&lt;h2&gt;Debug 和 Release&lt;/h2&gt;
&lt;p&gt;CMake 可以指定构建类型。&lt;/p&gt;
&lt;p&gt;Debug 构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake -S . -B build-debug -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build-debug
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Release 构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake -S . -B build-release -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build-release
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见构建类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Debug&lt;/code&gt;：带调试信息，适合开发和调试&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Release&lt;/code&gt;：开启优化，适合发布或性能测试&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RelWithDebInfo&lt;/code&gt;：开启优化，同时保留调试信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;多个源码文件&lt;/h2&gt;
&lt;p&gt;当项目从一个文件变成多个文件时，可以继续把源码添加到同一个 target：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello-cmake/
├── CMakeLists.txt
├── greeting.cpp
├── greeting.h
└── main.cpp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;greeting.h&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#pragma once

#include &amp;lt;string&amp;gt;

std::string make_greeting(const std::string&amp;amp; name);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;greeting.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;greeting.h&quot;

std::string make_greeting(const std::string&amp;amp; name) {
    return &quot;Hello, &quot; + name + &quot;!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

#include &quot;greeting.h&quot;

int main() {
    std::cout &amp;lt;&amp;lt; make_greeting(&quot;CMake&quot;) &amp;lt;&amp;lt; std::endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CMakeLists.txt&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.20)
project(hello_cmake CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(hello
  main.cpp
  greeting.cpp
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里没有把头文件写进 &lt;code&gt;add_executable&lt;/code&gt;，因为真正需要编译的是 &lt;code&gt;.cpp&lt;/code&gt; 文件。头文件会通过 &lt;code&gt;#include&lt;/code&gt; 被编译器读取。&lt;/p&gt;
&lt;h2&gt;拆成库&lt;/h2&gt;
&lt;p&gt;项目继续变大时，通常会把一部分代码拆成库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hello-cmake/
├── CMakeLists.txt
├── include/
│   └── greeting/
│       └── greeting.h
└── src/
    ├── greeting.cpp
    └── main.cpp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;include/greeting/greeting.h&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#pragma once

#include &amp;lt;string&amp;gt;

std::string make_greeting(const std::string&amp;amp; name);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/greeting.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;greeting/greeting.h&quot;

std::string make_greeting(const std::string&amp;amp; name) {
    return &quot;Hello, &quot; + name + &quot;!&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/main.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

#include &quot;greeting/greeting.h&quot;

int main() {
    std::cout &amp;lt;&amp;lt; make_greeting(&quot;CMake&quot;) &amp;lt;&amp;lt; std::endl;
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;CMakeLists.txt&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.20)
project(hello_cmake CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(greeting src/greeting.cpp)
target_include_directories(greeting PUBLIC include)

add_executable(hello src/main.cpp)
target_link_libraries(hello PRIVATE greeting)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里出现了三个重要命令。&lt;/p&gt;
&lt;p&gt;创建库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_library(greeting src/greeting.cpp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;声明库的公开头文件目录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;target_include_directories(greeting PUBLIC include)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;让可执行程序链接这个库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;target_link_libraries(hello PRIVATE greeting)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;PUBLIC&lt;/code&gt; 表示 &lt;code&gt;greeting&lt;/code&gt; 自己需要这个 include 目录，链接 &lt;code&gt;greeting&lt;/code&gt; 的 target 也需要这个 include 目录。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PRIVATE&lt;/code&gt; 表示 &lt;code&gt;hello&lt;/code&gt; 只是自己链接 &lt;code&gt;greeting&lt;/code&gt;，这个关系不需要再向外传播。&lt;/p&gt;
&lt;h2&gt;记住这条主线&lt;/h2&gt;
&lt;p&gt;入门阶段不需要记太多 CMake 命令。先记住这条主线：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;add_executable(...)
add_library(...)
target_include_directories(...)
target_link_libraries(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先定义 target&lt;/li&gt;
&lt;li&gt;再给 target 配头文件目录&lt;/li&gt;
&lt;li&gt;再描述 target 之间的链接关系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样写出来的 CMake 项目更容易扩展，也更接近真实 C++ 项目的组织方式。&lt;/p&gt;
</content:encoded></item><item><title>Python for Machine Learning</title><link>https://momoyeyu.github.io/posts/tutorial-of-python-for-learning-ml-and-dl/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/tutorial-of-python-for-learning-ml-and-dl/</guid><pubDate>Mon, 03 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Python for Machine Learning&lt;/h1&gt;
&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;我当时在做一个和机器学习（Machine Learning，ML）、深度学习（Deep Learning，DL）、Cybersecurity 有关的项目，但自己对 Python 工程经验、ML 和 DL 都不够熟悉，直接看课程和书会比较吃力。因此这篇文章整理的是一份快速补齐 Python 基础的路线，目标不是把 Python 学到很深，而是尽快能读懂 ML/DL/强化学习（Reinforcement Learning，RL）相关代码，并能开始做实验。&lt;/p&gt;
&lt;p&gt;如果后续要系统做 ML 或 DL，Python 基础越扎实越好；但入门阶段不必追求一次性学完所有语法。先掌握最常用的语言结构、数据处理、文件读写、包管理和调试方法，就足够支撑后续继续学习。&lt;/p&gt;
&lt;h2&gt;1. 基础语法&lt;/h2&gt;
&lt;p&gt;需要先熟悉变量、数据类型、条件分支、循环、函数和类。写代码时尽量保持命名清晰、结构简单，后续读 ML 代码会轻松很多。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Variables and basic data types
name = &quot;John&quot;
age = 25
is_student = True
height = 1.75

# Control flow statements - if-else
if age &amp;gt;= 18:
    print(&quot;You are an adult.&quot;)
else:
    print(&quot;You are a minor.&quot;)

# Loops - for loop
for i in range(1, 6):
    print(i)

# Functions
def greet(name):
    print(&quot;Hello, &quot; + name + &quot;!&quot;)

greet(&quot;Alice&quot;)

# Classes and objects
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(&quot;My name is&quot;, self.name, &quot;and I am&quot;, self.age, &quot;years old.&quot;)

person1 = Person(&quot;Alice&quot;, 25)
person1.introduce()

person2 = Person(&quot;Bob&quot;, 30)
person2.introduce()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里最容易困惑的是 &lt;code&gt;__init__&lt;/code&gt; 和 &lt;code&gt;self&lt;/code&gt;。&lt;code&gt;__init__&lt;/code&gt; 是类的构造方法，创建对象时会自动调用；&lt;code&gt;self&lt;/code&gt; 表示当前对象本身，用来访问对象自己的属性和方法。比如 &lt;code&gt;self.name = name&lt;/code&gt; 就是把传入的 &lt;code&gt;name&lt;/code&gt; 保存到这个对象上。&lt;/p&gt;
&lt;h2&gt;2. 数据结构&lt;/h2&gt;
&lt;p&gt;Python 内置的 &lt;code&gt;list&lt;/code&gt;、&lt;code&gt;tuple&lt;/code&gt;、&lt;code&gt;dict&lt;/code&gt; 和 &lt;code&gt;set&lt;/code&gt; 非常常用。ML 代码里经常需要组织样本、标签、配置和中间结果，所以至少要掌握索引、切片、遍历、增删改查这些操作。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Lists
fruits = [&apos;apple&apos;, &apos;banana&apos;, &apos;orange&apos;]
print(fruits)

print(fruits[0])
print(fruits[-1])

fruits[1] = &apos;grape&apos;
fruits.append(&apos;mango&apos;)
removed_fruit = fruits.pop(1)
print(removed_fruit)
print(fruits)

# Tuples
person = (&apos;John&apos;, 25, &apos;USA&apos;)
name, age, country = person
print(name, age, country)

# Dictionaries
student = {&apos;name&apos;: &apos;Alice&apos;, &apos;age&apos;: 20, &apos;major&apos;: &apos;Computer Science&apos;}
print(student[&apos;name&apos;])
print(student.get(&apos;age&apos;))

student[&apos;age&apos;] = 21
student[&apos;university&apos;] = &apos;ABC University&apos;
removed_major = student.pop(&apos;major&apos;)
print(removed_major)
print(student)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dict&lt;/code&gt; 在实验代码里尤其常见，常被用来保存超参数、指标、配置项和数据字段。相比用多个列表硬凑，字典能直接表达“键 -&amp;gt; 值”的映射关系。&lt;/p&gt;
&lt;h2&gt;3. 常用库和模块&lt;/h2&gt;
&lt;p&gt;进入 ML 前，至少要知道怎么导入库，以及几个基础库各自做什么。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import math
import random

print(math.sqrt(25))
print(math.pi)
print(random.randint(1, 10))
print(random.choice([&apos;apple&apos;, &apos;banana&apos;, &apos;orange&apos;]))

from datetime import date
from random import shuffle

today = date.today()
print(today)

my_list = [1, 2, 3, 4, 5]
shuffle(my_list)
print(my_list)

import numpy as np
import pandas as pd

array = np.array([1, 2, 3, 4, 5])
print(array)

data_frame = pd.DataFrame({&apos;Name&apos;: [&apos;Alice&apos;, &apos;Bob&apos;, &apos;Charlie&apos;], &apos;Age&apos;: [25, 30, 35]})
print(data_frame)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常用库可以先按用途记：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NumPy&lt;/code&gt;：数值计算和数组操作，是很多科学计算库的基础。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Pandas&lt;/code&gt;：表格数据处理，常用于读 CSV、清洗数据、做统计分析。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Matplotlib&lt;/code&gt;：画图和可视化，适合看数据分布和模型结果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scikit-learn&lt;/code&gt;：传统 ML 常用库，包含分类、回归、聚类、降维、评估等工具。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TensorFlow&lt;/code&gt; / &lt;code&gt;PyTorch&lt;/code&gt;：DL 框架，用来搭建和训练神经网络。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个很简化的 scikit-learn 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# Load the dataset
data = pd.read_csv(&apos;data.csv&apos;)

# Split the dataset into features and labels
X = data.drop(&apos;label&apos;, axis=1)
y = data[&apos;label&apos;]

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Train a logistic regression model
model = LogisticRegression()
model.fit(X_train, y_train)

# Evaluate the model
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(&apos;Accuracy:&apos;, accuracy)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 文件读写&lt;/h2&gt;
&lt;p&gt;做 ML 时经常要读数据集、保存处理结果、写日志或者保存配置。最基本的是理解 &lt;code&gt;with open(...)&lt;/code&gt; 的写法，它能保证文件用完后正确关闭。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def write_to_file(filename, content):
    with open(filename, &apos;w&apos;) as file:
        file.write(content)


def read_from_file(filename):
    with open(filename, &apos;r&apos;) as file:
        return file.read()


filename = &quot;example.txt&quot;
content_to_write = &quot;Hello, World!&quot;

write_to_file(filename, content_to_write)
content_read = read_from_file(filename)
print(content_read)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不想覆盖已有文件，可以先检查文件是否存在：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os


def write_to_file(filename, content):
    if os.path.isfile(filename):
        print(f&quot;File &apos;{filename}&apos; already exists.&quot;)
    else:
        with open(filename, &apos;w&apos;) as file:
            file.write(content)
        print(f&quot;Content &apos;{content}&apos; written to &apos;{filename}&apos;.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更完整一点的版本可以加异常处理和追加写入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def write_to_file(filename, content):
    try:
        with open(filename, &apos;w&apos;) as file:
            file.write(content)
        print(f&quot;Content written to &apos;{filename}&apos; successfully.&quot;)
    except IOError as e:
        print(f&quot;Error writing to &apos;{filename}&apos;: {e}&quot;)


def read_from_file(filename):
    try:
        with open(filename, &apos;r&apos;) as file:
            return file.read()
    except FileNotFoundError:
        print(f&quot;File &apos;{filename}&apos; not found.&quot;)
    except IOError as e:
        print(f&quot;Error reading from &apos;{filename}&apos;: {e}&quot;)


def append_to_file(filename, content):
    try:
        with open(filename, &apos;a&apos;) as file:
            file.write(content)
        print(f&quot;Content appended to &apos;{filename}&apos; successfully.&quot;)
    except IOError as e:
        print(f&quot;Error appending to &apos;{filename}&apos;: {e}&quot;)


filename = &quot;example.txt&quot;
write_to_file(filename, &quot;Hello, World!&quot;)
append_to_file(filename, &quot;\nAppending some more content!&quot;)
print(read_from_file(filename))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. ML/DL 相关函数和库&lt;/h2&gt;
&lt;p&gt;不需要一开始就掌握所有框架，但要知道基本分工。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NumPy&lt;/code&gt;：负责矩阵、向量、随机数、线性代数等基础数值计算。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Pandas&lt;/code&gt;：负责结构化数据的读取、筛选、合并、清洗和统计。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scikit-learn&lt;/code&gt;：适合传统 ML，比如线性回归、逻辑回归、SVM、随机森林、KMeans 等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TensorFlow&lt;/code&gt;：Google 推出的 DL 框架，配合 Keras 可以快速搭模型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PyTorch&lt;/code&gt;：动态图机制更直观，科研和原型验证里非常常见。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Matplotlib&lt;/code&gt;：画 loss 曲线、散点图、直方图、预测结果等。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

# Generate sample data
X = np.random.rand(100, 1)
y = 2 * X + np.random.randn(100, 1)

# Create a Pandas DataFrame
df = pd.DataFrame({&apos;X&apos;: X.flatten(), &apos;y&apos;: y.flatten()})

# Fit a linear regression model
model = LinearRegression()
model.fit(X, y)

# Predict the output
X_new = np.array([[0.2], [0.4], [0.6]])
y_pred = model.predict(X_new)

# Plot the data and regression line
plt.scatter(X, y, color=&apos;blue&apos;, label=&apos;Data&apos;)
plt.plot(X_new, y_pred, color=&apos;red&apos;, linewidth=2, label=&apos;Regression Line&apos;)
plt.xlabel(&apos;X&apos;)
plt.ylabel(&apos;y&apos;)
plt.legend()
plt.show()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码包含了一个典型的最小流程：生成数据、组织数据、训练模型、预测、可视化。后续复杂模型基本也是在这个流程上扩展。&lt;/p&gt;
&lt;h2&gt;6. 异常处理和调试&lt;/h2&gt;
&lt;p&gt;写 ML 代码时，错误不一定来自算法，也可能来自数据维度、文件路径、包版本、数据类型。先掌握基础调试方法很重要。&lt;/p&gt;
&lt;p&gt;常见错误大致可以分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;语法错误：代码本身不符合 Python 语法。&lt;/li&gt;
&lt;li&gt;运行时错误：比如文件不存在、数组越界、类型不匹配。&lt;/li&gt;
&lt;li&gt;逻辑错误：代码能跑，但结果不对，这类最难查。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;异常处理的基本写法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;try:
    # Code that might raise an exception
    result = 10 / 0
except ZeroDivisionError:
    print(&quot;Cannot divide by zero&quot;)
except Exception as e:
    print(&quot;Unexpected error:&quot;, e)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也可以用 &lt;code&gt;logging&lt;/code&gt; 代替大量 &lt;code&gt;print&lt;/code&gt;，尤其是训练过程比较长的时候：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import logging

logging.basicConfig(level=logging.DEBUG)

logging.debug(&apos;This is a debug message&apos;)
logging.info(&apos;This is an info message&apos;)
logging.warning(&apos;This is a warning message&apos;)
logging.error(&apos;This is an error message&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;调试时建议先读报错信息和 stack trace，定位出错行；如果问题不明显，就逐步缩小代码范围，检查关键变量的 shape、dtype 和取值。&lt;/p&gt;
&lt;h2&gt;7. 包管理&lt;/h2&gt;
&lt;p&gt;ML/DL 项目依赖通常比较多，环境管理不清楚很容易出现“在我机器上能跑”的问题。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pip&lt;/code&gt;：Python 默认包管理器，例如 &lt;code&gt;pip install numpy&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;venv&lt;/code&gt;：Python 内置虚拟环境工具，可以为每个项目创建独立环境。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;conda&lt;/code&gt;：常用于数据科学项目，适合管理 Python 版本、CUDA 相关依赖和科学计算库。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;requirements.txt&lt;/code&gt;：记录项目依赖，常用 &lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt; 生成，用 &lt;code&gt;pip install -r requirements.txt&lt;/code&gt; 安装。&lt;/li&gt;
&lt;li&gt;版本约束：例如 &lt;code&gt;numpy==1.26.4&lt;/code&gt; 表示固定版本，&lt;code&gt;torch&amp;gt;=2.0.0&lt;/code&gt; 表示最低版本。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一个简单流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -m venv .venv
source .venv/bin/activate
pip install numpy pandas scikit-learn matplotlib
pip freeze &amp;gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后续如果换机器或给别人复现，可以直接：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;小结&lt;/h2&gt;
&lt;p&gt;这篇文章的重点是：为了学习 ML/DL，不需要先把 Python 所有细节都学完，但要先掌握能支撑实验代码的核心能力，包括基础语法、常见数据结构、常用库、文件读写、异常处理、调试和包管理。&lt;/p&gt;
&lt;p&gt;接下来比较适合的路线是：先用 &lt;code&gt;NumPy&lt;/code&gt; 和 &lt;code&gt;Pandas&lt;/code&gt; 做数据处理，再用 &lt;code&gt;scikit-learn&lt;/code&gt; 跑几个传统 ML 模型，最后进入 &lt;code&gt;PyTorch&lt;/code&gt; 或 &lt;code&gt;TensorFlow&lt;/code&gt;。边学边写小实验，比单纯看教程有效很多。&lt;/p&gt;
</content:encoded></item><item><title>C++ Vector 详解</title><link>https://momoyeyu.github.io/posts/vector/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/vector/</guid><pubDate>Wed, 26 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Vector&lt;/h1&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;vector 是 C++ 标准库中的动态数组容器，功能类似其他语言的 ArrayList。它支持运行时动态扩容，并可随时查询当前元素数量。&lt;/p&gt;
&lt;h2&gt;基本用法&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;vector&amp;gt;

struct Vertex
{
    float x, y, z;

    Vertex(float x, float y, float z)
        : x(x), y(y), z(z)
    {}
};

// 重载 &amp;lt;&amp;lt; 运算符，支持直接输出 Vertex
std::ostream&amp;amp; operator&amp;lt;&amp;lt;(std::ostream&amp;amp; stream, const Vertex vertex)
{
    stream &amp;lt;&amp;lt; &quot;(&quot; &amp;lt;&amp;lt; vertex.x &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; vertex.y &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; vertex.z &amp;lt;&amp;lt; &quot;)&quot;;
    return stream;
}

int main()
{
    std::vector&amp;lt;Vertex&amp;gt; vertices;

    vertices.push_back({ 1, 2, 3 });
    vertices.push_back({ 4, 5, 6 });

    // 下标遍历
    for (int i = 0; i &amp;lt; vertices.size(); i++)
        std::cout &amp;lt;&amp;lt; vertices[i] &amp;lt;&amp;lt; std::endl;

    vertices.erase(vertices.begin() + 1); // 删除索引 1 处的元素

    // 范围 for 遍历，使用引用避免拷贝
    for (Vertex&amp;amp; v : vertices)
        std::cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; std::endl;

    std::cin.get();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;几个关键点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用前需要 &lt;code&gt;#include&amp;lt;vector&amp;gt;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;push_back()&lt;/code&gt; 在末尾追加元素；&lt;code&gt;erase()&lt;/code&gt; 配合 &lt;code&gt;begin()&lt;/code&gt; 加偏移量删除指定位置元素。&lt;/li&gt;
&lt;li&gt;与 Java 不同，C++ vector 的元素类型可以是基本类型（如 &lt;code&gt;int&lt;/code&gt;），不必是对象。&lt;/li&gt;
&lt;li&gt;范围 for 循环中用引用（&lt;code&gt;&amp;amp;&lt;/code&gt;）接收元素，避免不必要的拷贝。&lt;/li&gt;
&lt;li&gt;重载 &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; 运算符可自定义类型的输出格式。&lt;/li&gt;
&lt;li&gt;初始化列表（initializer list）在构造函数中直接初始化成员，效率高于赋值。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;性能优化&lt;/h2&gt;
&lt;p&gt;上面的示例展示了基本用法，但存在不必要的拷贝开销。下面针对拷贝问题进行优化。&lt;/p&gt;
&lt;h3&gt;减少拷贝&lt;/h3&gt;
&lt;p&gt;首先要明确拷贝发生在哪里。给 &lt;code&gt;Vertex&lt;/code&gt; 添加拷贝构造函数并打印日志，可以直观看到拷贝次数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;vector&amp;gt;

struct Vertex
{
    float x, y, z;

    Vertex(float x, float y, float z)
        : x(x), y(y), z(z)
    {}

    Vertex(const Vertex&amp;amp; vertex)
        : x(vertex.x), y(vertex.y), z(vertex.z)
    {
        std::cout &amp;lt;&amp;lt; &quot;Copied!&quot; &amp;lt;&amp;lt; std::endl; // 每次拷贝时打印
    }
};

int main()
{
    std::vector&amp;lt;Vertex&amp;gt; vertices;
    vertices.push_back(Vertex(1, 2, 3));
    vertices.push_back(Vertex(4, 5, 6));
    vertices.push_back(Vertex(4, 5, 6));

    std::cin.get();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行上面的代码，控制台会打印 6 次 &quot;Copied!&quot;。&lt;/p&gt;
&lt;h4&gt;避免扩容引发的拷贝&lt;/h4&gt;
&lt;p&gt;vector 容量不足时会重新分配内存，将已有数据全部拷贝到新位置后再释放旧内存。每次 &lt;code&gt;push_back()&lt;/code&gt; 触发扩容，就会产生额外拷贝。&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;reserve()&lt;/code&gt; 预先声明所需容量，可以避免扩容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;std::vector&amp;lt;Vertex&amp;gt; vertices;

vertices.reserve(3); // 预分配 3 个元素的空间，避免扩容

vertices.push_back(Vertex(1, 2, 3));
vertices.push_back(Vertex(4, 5, 6));
vertices.push_back(Vertex(4, 5, 6));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加上 &lt;code&gt;reserve(3)&lt;/code&gt; 后，控制台只打印 3 次 &quot;Copied!&quot;。&lt;/p&gt;
&lt;h4&gt;避免构造时的额外拷贝&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;push_back(Vertex(1, 2, 3))&lt;/code&gt; 先在当前作用域构造一个临时对象，再将其拷贝进 vector。使用 &lt;code&gt;emplace_back()&lt;/code&gt; 可以将参数直接传给 vector 内部的构造函数，省去这次拷贝：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vertices.emplace_back(1, 2, 3);
vertices.emplace_back(4, 5, 6);
vertices.emplace_back(4, 5, 6);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时使用 &lt;code&gt;reserve()&lt;/code&gt; 和 &lt;code&gt;emplace_back()&lt;/code&gt;，再次运行代码，控制台不会打印任何 &quot;Copied!&quot;。&lt;/p&gt;
</content:encoded></item><item><title>智能指针</title><link>https://momoyeyu.github.io/posts/smart-pointer/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/smart-pointer/</guid><pubDate>Fri, 21 Apr 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;智能指针&lt;/h1&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;智能指针可以自动管理内存，避免因忘记调用 &lt;code&gt;delete&lt;/code&gt; 而造成的内存泄漏。&lt;/p&gt;
&lt;h2&gt;前置代码&lt;/h2&gt;
&lt;p&gt;本文示例基于以下头文件和 &lt;code&gt;Entity&lt;/code&gt; 类：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include&amp;lt;string&amp;gt;
#include&amp;lt;memory&amp;gt; // 引入智能指针

class Entity
{
public:
    Entity()
    {
        std::cout &amp;lt;&amp;lt; &quot;Created Entity!&quot; &amp;lt;&amp;lt; std::endl;
    }

    ~Entity()
    {
        std::cout &amp;lt;&amp;lt; &quot;Destroyed Entity!&quot; &amp;lt;&amp;lt; std::endl;
    }

    void Print() {}
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;unique_ptr&lt;/h2&gt;
&lt;p&gt;下面是 &lt;code&gt;unique_ptr&lt;/code&gt; 的基本用法，花括号用于显式标记作用域：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;... // 省略前面的代码
int main()
{
    {// 显式作用域开始
        
        std::unique_ptr&amp;lt;Entity&amp;gt; entity = std::make_unique&amp;lt;Entity&amp;gt;();

        entity-&amp;gt;Print();
    }// entity 在此离开作用域，自动释放内存

    //main 结束
    std::cin.get();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;unique_ptr&lt;/code&gt; &lt;strong&gt;不能被拷贝&lt;/strong&gt;，这也是其名称的含义。以下用法是非法的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Example
{
    ...//omit
};
...//omit
    std::unique_ptr&amp;lt;Example&amp;gt; uniq_ptr = std::make_unique&amp;lt;Example&amp;gt;();
    void* ptr
    ptr = uniq_ptr // 非法，unique_ptr 不可拷贝
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;尝试拷贝时编译器会报错。如需转移所有权，可使用移动语义（&lt;code&gt;std::move&lt;/code&gt;）。&lt;/p&gt;
&lt;h2&gt;shared_ptr&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;shared_ptr&lt;/code&gt; 通过&lt;strong&gt;引用计数&lt;/strong&gt;实现共享所有权：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每当一个新的 &lt;code&gt;shared_ptr&lt;/code&gt; 共享同一对象，引用计数加一；&lt;/li&gt;
&lt;li&gt;每当一个 &lt;code&gt;shared_ptr&lt;/code&gt; 销毁，引用计数减一；&lt;/li&gt;
&lt;li&gt;引用计数归零时，内存才会被释放。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;int main()
{
    std::shared_ptr&amp;lt;Entity&amp;gt; entity;
    // entity 已声明，但尚未初始化
    {
        std::shared_ptr&amp;lt;Entity&amp;gt; shared_entity = std::make_shared&amp;lt;Entity&amp;gt;();

        entity = shared_entity; // entity 开始共同持有该对象

        entity-&amp;gt;Print();
    }
    // shared_entity 在此离开作用域，但内存尚未释放，entity 仍持有
    // because ptr &quot;entity&quot; hold it&apos;s memory
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;weak_ptr&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;weak_ptr&lt;/code&gt; 可以看作一种特殊的 &lt;code&gt;shared_ptr&lt;/code&gt;——它可以引用一个 &lt;code&gt;shared_ptr&lt;/code&gt; 管理的对象，但&lt;strong&gt;不影响引用计数&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int main()
{
    std::weak_ptr&amp;lt;Entity&amp;gt; entity;
    // entity 已声明，但尚未初始化
    {
        std::shared_ptr&amp;lt;Entity&amp;gt; shared_entity = std::make_shared&amp;lt;Entity&amp;gt;();

        entity = shared_entity;

        shared_entity-&amp;gt;Print();
    }
    // shared_entity 离开作用域，引用计数归零，内存释放
    // 可通过 weak_ptr 检查其指向的内存是否已被释放
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当所有关联的 &lt;code&gt;shared_ptr&lt;/code&gt; 都销毁后，&lt;code&gt;weak_ptr&lt;/code&gt; 不再持有内存，但可以用 &lt;code&gt;expired()&lt;/code&gt; 或 &lt;code&gt;lock()&lt;/code&gt; 检查对象是否仍然存在。&lt;code&gt;weak_ptr&lt;/code&gt; 的典型用途是&lt;strong&gt;打破循环引用&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;C++ 中的智能指针用于自动管理内存的分配与释放，防止内存泄漏和悬空指针。三种常用类型均以模板实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;unique_ptr&lt;/code&gt;：独占所有权，不可拷贝，只能移动。适合&lt;strong&gt;单一指针管理一个对象&lt;/strong&gt;的场景，离开作用域时自动销毁对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;shared_ptr&lt;/code&gt;：共享所有权，多个指针可指向同一对象，通过&lt;strong&gt;引用计数&lt;/strong&gt;追踪引用数量，计数归零时自动销毁对象。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;weak_ptr&lt;/code&gt;：配合 &lt;code&gt;shared_ptr&lt;/code&gt; 使用，提供非拥有性引用，&lt;strong&gt;不影响引用计数&lt;/strong&gt;，常用于打破循环引用，并可检查对象是否已被销毁。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Python-字典</title><link>https://momoyeyu.github.io/posts/python-%E5%AD%97%E5%85%B8/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/python-%E5%AD%97%E5%85%B8/</guid><pubDate>Sun, 22 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;字典&lt;/h1&gt;
&lt;p&gt;字典是Python中唯一实现&lt;code&gt;映射关系&lt;/code&gt;的内置类型&lt;/p&gt;
&lt;h2&gt;1. 解决单表代换密码问题&lt;/h2&gt;
&lt;h3&gt;1.1 模拟字典方法&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;以下不是真正的字典，但可以实现类似的功能&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;通过两个列表对照实现&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;c_table = [&quot;cipher1&quot;, &quot;cipher2&quot;...] # 密文表
d_table = [&quot;plain1&quot;, &quot;plain2&quot;...] # 明文表
cipher = input(&quot;input your cipher&quot;) # 输入密文
split_cipher = cipher.split(&quot; &quot;) # 密文拆分
result = [d_table[c_table.index(each)] for each in split_cipher] # 通过查找密文下标找到对应下标明文来解密
print(result) # 打印结果
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;通过一个列表实现&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;table = [&quot;cipher1&quot;, &quot;plain1&quot;, &quot;cipher2&quot;, &quot;plain2&quot; ...]
cipher = input(...) # 输入密文
split_cipher = cipher.split(&quot; &quot;) # 密文拆分
result = [table[table.index(each) + 1] for each in split_cipher] # 通过查找密文下标，得到其下一位，即对应的明文
print(result) # 打印结果
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这两种方法在处理小量数据的时候和字典效率相差不大，但由于其数据结构本身不是映射关系，实际在处理大量数据时效率远不及字典&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.2 字典方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;table = {&quot;cipher1&quot;:&quot;plain1&quot;, &quot;cipher2&quot;:&quot;plain2&quot;, &quot;cipher3&quot;:&quot;plain3&quot;...}
cipher = input(&quot;input your cipher&quot;)
split_cipher = cipher.split(&quot; &quot;)
result = [table[each] for each in split_cipher]
print(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 字典基础用法&lt;/h2&gt;
&lt;p&gt;Python中，字典内一对数据叫做一个&lt;code&gt;键值对&lt;/code&gt;：dic = {&quot;键&quot;:&quot;值&quot;}，一个键对应一个值&lt;/p&gt;
&lt;h3&gt;2.1 字典的6种一般声明方法&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;a = {&quot;alpha&quot;:&quot;a&quot;, &quot;bravo&quot;:&quot;b&quot;...}
b = dict(alpha=&quot;a&quot;, bravo=&quot;b&quot;...)
c = dict([(&quot;alpha&quot;, &quot;a&quot;), (&quot;bravo&quot;, &quot;b&quot;)...])
d = dict({&quot;alpha&quot;:&quot;a&quot;, &quot;bravo&quot;:&quot;b&quot;...})
e = dict({&quot;alpha&quot;:&quot;a&quot;, &quot;bravo&quot;:&quot;b&quot;...}, charlie=&quot;c&quot;...)
f = dict(zip([&quot;alpha&quot;, &quot;bravo&quot;, &quot;charlie&quot;...], [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;...]))
a == b == c == d == e == f # True # &amp;lt;class &apos;dict&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 fromkeys声明&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;fromkeys(iterable, value) 其中value是可选参数，默认为None&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;dic = dict.fromkeys(&quot;Momoyeyu&quot;, 0) # 键被看作集合，重复的o和y只会存一个
print(dic)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Output
{&apos;M&apos;: 0, &apos;o&apos;: 0, &apos;m&apos;: 0, &apos;y&apos;: 0, &apos;e&apos;: 0, &apos;u&apos;: 0}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.3 修改字典&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;dic = dict.fromkeys(&quot;Momoyeyu&quot;, 0)
print(dic)
dic[&quot;M&quot;] = 1 # 改
dic[&quot;New&quot;] = 2 # 增
dic.pop(&quot;o&quot;) # 删 （pop的返回值是删除的值）
print(dic)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Output:&lt;br /&gt;
{&apos;M&apos;: 0, &apos;o&apos;: 0, &apos;m&apos;: 0, &apos;y&apos;: 0, &apos;e&apos;: 0, &apos;u&apos;: 0}&lt;br /&gt;
{&apos;M&apos;: 1, &apos;m&apos;: 0, &apos;y&apos;: 0, &apos;e&apos;: 0, &apos;u&apos;: 0, &apos;New&apos;: 2}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;键被当作下标使用，这也解释了为什么键要被视为集合储存：&lt;code&gt;具有无序性和唯一性&lt;/code&gt;&lt;br /&gt;
一个字典中没有两个相等的键，但不同的键可以关联同一个值，&lt;code&gt;键重复了就用新的值覆盖旧的值&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;2.3.1 关于删除&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;dic.pop(key, default)&lt;br /&gt;
若pop的键key不存在dic中，pop会报错，但也可以通过可选参数default来设置报错内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dic.popitem()&lt;br /&gt;
在 Python 3.7 以后的版本，字典的键值对才有储存顺序，popitem 会弹出最后一个加入字典 dic 的键值对&lt;br /&gt;
但在 Python 3.7 以前的版本，popitem 会随机弹出一个键值对&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;del关键词&lt;br /&gt;
通过 del dic[&apos;键&apos;] 也可以删除一个键值对，也可以 del dic 直接删除字典，注意和 dic.clear() 区分&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;clear()&lt;br /&gt;
通过 dic.clear() 可以得到空字典，注意和 del dic 区分&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2&gt;3. 其他字典函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;dic.get(key, default=None)&lt;/td&gt;
&lt;td&gt;查找key对应的value，不存在则返回None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dic.setdefault(key, value)&lt;/td&gt;
&lt;td&gt;查找key的值，若key存在，返回key原本的value；若key不存在，则把键值对key:value添加到dic中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dic.keys()&lt;/td&gt;
&lt;td&gt;返回dic的&lt;code&gt;键的视图对象&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dic.values()&lt;/td&gt;
&lt;td&gt;返回dic的&lt;code&gt;值的视图对象&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dic.items()&lt;/td&gt;
&lt;td&gt;返回dic的&lt;code&gt;字典视图对象&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3.1 关于视图对象&lt;/h3&gt;
&lt;p&gt;视图对象是字典的&lt;code&gt;动态&lt;/code&gt;视图，字典改变的时候，其视图对象会随之改变&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dic = dict.fromkeys(&quot;Momoyeyu&quot;, 0)
keys = dic.keys()
values = dic.values()
items = dic.items()
print(keys)
print(values)
print(items)
dic.pop(&apos;M&apos;)
print(items)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Output:&lt;br /&gt;
dict_keys([&apos;M&apos;, &apos;o&apos;, &apos;m&apos;, &apos;y&apos;, &apos;e&apos;, &apos;u&apos;])&lt;br /&gt;
dict_values([0, 0, 0, 0, 0, 0])&lt;br /&gt;
dict_items([(&apos;M&apos;, 0), (&apos;o&apos;, 0), (&apos;m&apos;, 0), (&apos;y&apos;, 0), (&apos;e&apos;, 0), (&apos;u&apos;, 0)])&lt;br /&gt;
dict_items([(&apos;o&apos;, 0), (&apos;m&apos;, 0), (&apos;y&apos;, 0), (&apos;e&apos;, 0), (&apos;u&apos;, 0)])&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;4. 嵌套字典&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;a = {&quot;Momoyeyu&quot;:{&quot;Chinese&quot;:60, &quot;Math&quot;:50, &quot;English&quot;:40}}
b = {&quot;Momoyeyu&quot;:[60, 50, 40]}
print(a[&quot;Momoyeyu&quot;][&quot;Math&quot;], end=&quot; &quot;)
print(b[&quot;Momoyeyu&quot;][1])
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Output:&lt;br /&gt;
50 50&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Python-分支和循环</title><link>https://momoyeyu.github.io/posts/python-%E5%88%86%E6%94%AF%E5%92%8C%E5%BE%AA%E7%8E%AF/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/python-%E5%88%86%E6%94%AF%E5%92%8C%E5%BE%AA%E7%8E%AF/</guid><pubDate>Fri, 20 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;参考资料：
&lt;a href=&quot;https://www.bilibili.com/video/BV1c4411e77t&quot;&gt;【Python教程】《零基础入门学习Python》最新版（2022年12月26日更新）&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;分支结构&lt;/h1&gt;
&lt;h2&gt;1. if结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;if condition:
    statement_1(s1)
statement_2(s2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. if-else结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;if condition:
    statement_1(s1)
else:
    statement_2(s2)
statement_3(s3)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. if-elif-elif...(-else)结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;if condition_1:
    statement_1(s1)
elif condition_2:
    statement_2(s2)
...
# else:
#     statement_n(sn)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. oneline结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;true_statement if condition else false_statement
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;循环结构&lt;/h1&gt;
&lt;h2&gt;1. while循环&lt;/h2&gt;
&lt;h3&gt;1.1 基本结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;while condition:
    statement_1(s1)
statement_2(s2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.2 while-break结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;while condition_1:
    statement_1(s1)
    if condition_2:
        break
    statement_2(s2)
statement_3(s3)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1.3 while-else结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;while condition_1:
    statement_1(s1)
    if condition_2:
        break
    statement_2(s2)
else:
    statement_3(s3)
statement_4(s4)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;仅在循环由condition_1退出时才执行else，由break终止则不执行else&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.4 嵌套结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;i = 1
while i &amp;lt;= 9:
    j = 1
    while j &amp;lt;= i:
        print(j, &quot;*&quot;, i, &quot;=&quot;, j*i, end=&quot; &quot;)
        j += 1
    print()
    i += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;1 * 1 = 1 
1 * 2 = 2 2 * 2 = 4 
1 * 3 = 3 2 * 3 = 6 3 * 3 = 9 
1 * 4 = 4 2 * 4 = 8 3 * 4 = 12 4 * 4 = 16 
1 * 5 = 5 2 * 5 = 10 3 * 5 = 15 4 * 5 = 20 5 * 5 = 25 
1 * 6 = 6 2 * 6 = 12 3 * 6 = 18 4 * 6 = 24 5 * 6 = 30 6 * 6 = 36 
1 * 7 = 7 2 * 7 = 14 3 * 7 = 21 4 * 7 = 28 5 * 7 = 35 6 * 7 = 42 7 * 7 = 49 
1 * 8 = 8 2 * 8 = 16 3 * 8 = 24 4 * 8 = 32 5 * 8 = 40 6 * 8 = 48 7 * 8 = 56 8 * 8 = 64 
1 * 9 = 9 2 * 9 = 18 3 * 9 = 27 4 * 9 = 36 5 * 9 = 45 6 * 9 = 54 7 * 9 = 63 8 * 9 = 72 9 * 9 = 81 
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. for循环&lt;/h2&gt;
&lt;h3&gt;2.1 基本结构&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;for identifier in iterable:
    statement_1(s1)
statement_2(s2)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sum = 0
for i in range(10):
    sum += i
print(sum)
# 45
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2.2 range()函数&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;range(stop)&lt;br /&gt;
range(start, stop)&lt;br /&gt;
range(start, stop, step)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;for n in range(2, 10):
    for m in range(2, n):
            if n % m == 0:
                print(n, &quot;=&quot;, m, &quot;*&quot;, n // m)
                break
    else:
        print(n, &quot;is a prime number&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;2 is a prime number
3 is a prime number
4 = 2 * 2
5 is a prime number
6 = 2 * 3
7 is a prime number
8 = 2 * 4
9 = 3 * 3
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Python-序列</title><link>https://momoyeyu.github.io/posts/python-%E5%BA%8F%E5%88%97/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/python-%E5%BA%8F%E5%88%97/</guid><pubDate>Fri, 20 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;参考资料：
&lt;a href=&quot;https://www.bilibili.com/video/BV1c4411e77t&quot;&gt;【Python教程】《零基础入门学习Python》最新版（2022年12月26日更新）&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;序列&lt;/h1&gt;
&lt;p&gt;Python中，列表、元组和字符串都属于序列&lt;/p&gt;
&lt;h2&gt;1. 序列的基本运算&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;加法 +&lt;br /&gt;
乘法 *&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
d = a * 2
print(c)
print(d)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[1, 2, 3, 4, 5, 6]
[1, 2, 3, 1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 序列的判定函数&lt;/h2&gt;
&lt;h3&gt;2.1 关键词&apos;is&apos; &amp;amp; &apos;is not&apos;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;a = [1, 2, 3]
b = [1, 2, 3]
print(&quot;a == b?&quot;)
print(&quot;True&quot;) if a == b else print(&quot;False&quot;)
print(&quot;a is b?&quot;)
print(&quot;True&quot;) if a is b else print(&quot;False&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;a == b?
True
a is b?
False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一次判定的是&apos;a&apos;与&apos;b&apos;的元素值是否相等，而第二次判定的是&apos;a&apos;与&apos;b&apos;是否与同一组数据挂钩&lt;br /&gt;
放在C语言中，就好比&apos;==&apos;判断变量储存的数值是否相等，而&apos;is&apos;判断他们是否指向同一个内存地址&lt;br /&gt;
但是在Python中，我们一般认为变量名并不是储存了数据，而是与数据挂钩，同时一般Python也不常用指针的概念&lt;br /&gt;
这是因为Python对指针做了良好封装，一切都是“对象”，一切对象都有一个“变量”指向它。这个“变量”就是“指针”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;而&apos;is&apos;和&apos;is not&apos;就是用来判断&apos;a&apos;和&apos;b&apos;是否指向了同一个&lt;code&gt;对象&lt;/code&gt;，其本质和比较指针是一样的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.2 id()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Return the identity of an object.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;a = (1, 2, 3)
b = 1, 2, 3
print(&quot;True&quot;) if id(a) == id(b) else print(&quot;False&quot;)
c = [1, 2, 3]
d = [1, 2, 3]
print(&quot;True&quot;) if id(c) == id(d) else print(&quot;False&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;True
False
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;id()相当于C语言中取地址符，它得到的相当于与变量名挂钩的数据的&quot;身份证&quot;，只要数据存在于内存中，这个值就唯一&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.3 关键词&apos;in&apos; &amp;amp; &apos;not in&apos;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;a = (1, 2, 3)
b = 1, 2, 3
print(&quot;1 in a?&quot;)
print(&quot;True&quot;) if 1 in a else print(&quot;False&quot;)
print(&quot;a not in b?&quot;)
print(&quot;True&quot;) if a not in b else print(&quot;False&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;1 in a?
True
a not in b?
True
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 关键词&apos;del&apos;&lt;/h2&gt;
&lt;p&gt;作用：删除&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = [1, 2, 3, 4, 5]
print(x)
del x[0]
print(x)
del x[:2]
print(x)
del x[:]
print(x)
del x
print(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[1, 2, 3, 4, 5]
[2, 3, 4, 5]
[4, 5]
[]
Traceback (most recent call last):
  File &quot;D:\PycharmProjects\test\main.py&quot;, line 10, in &amp;lt;module&amp;gt;
    print(x)
NameError: name &apos;x&apos; is not defined
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 序列基本函数&lt;/h2&gt;
&lt;h3&gt;4.1 list() &amp;amp; tuple() &amp;amp; str()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;list(iterable)&lt;br /&gt;
tuple(iterable)&lt;br /&gt;
str(object) # str(object=&apos;&apos;) -&amp;gt; str&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(list(&quot;Momoyeyu&quot;))
print(tuple(&quot;Momoyeyu&quot;))
print(str(&quot;Momoyeyu&quot;))
print(str(list(&quot;Momoyeyu&quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[&apos;M&apos;, &apos;o&apos;, &apos;m&apos;, &apos;o&apos;, &apos;y&apos;, &apos;e&apos;, &apos;y&apos;, &apos;u&apos;]
(&apos;M&apos;, &apos;o&apos;, &apos;m&apos;, &apos;o&apos;, &apos;y&apos;, &apos;e&apos;, &apos;y&apos;, &apos;u&apos;)
Momoyeyu
[&apos;M&apos;, &apos;o&apos;, &apos;m&apos;, &apos;o&apos;, &apos;y&apos;, &apos;e&apos;, &apos;y&apos;, &apos;u&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 max() &amp;amp; min()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;max(iterable, *[, default=obj, key=func])
min(iterable, *[, default=obj, key=func])
注：可选参数default默认是报错，可以设置内容&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(max([1, 2, 3, 4, 5]))
print(min(&quot;Momoyeyu&quot;))
print(min([], default = &quot;Empty!&quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;5
M
Empty!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.3 len() &amp;amp; sum()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;len(obj)
sum(iterable, /, start=0)
注：可选参数start默认是0，可以设置起始值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(len(range(2 ** 10)))
print(sum([1, 2, 3, 4, 5], start=10))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;1024
25
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.4 sorted() &amp;amp; reversed()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;sorted(iterable, /, *, key=None, reverse=False)&lt;br /&gt;
reversed(sequence) # Return a reverse iterator over the values of the given sequence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(sorted([3, 1, 4, 2]))
print(sorted([&quot;Momoyeyu&quot;, &quot;Gger&quot;, &quot;Guitar&quot;], key=len, reverse=True))
print(reversed([1, 0, 0, 8, 6]))
print(list(reversed([1, 0, 0, 8, 6])))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[1, 2, 3, 4]
[&apos;Momoyeyu&apos;, &apos;Guitar&apos;, &apos;Gger&apos;]
&amp;lt;list_reverseiterator object at 0x000002891CDAFE20&amp;gt;
[6, 8, 0, 0, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由输出第3行我们注意到，reversed()返回的不是一个列表，根据Python官方文档说明，reversed()返回的是一个&lt;code&gt;迭代器&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;4.5 all() &amp;amp; any()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;all(iterable)
any(iterable)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(all([1, 1, 0]))
print(any([0, 0, 1]))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;False
True
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 关于迭代器-iterator&lt;/h2&gt;
&lt;h3&gt;5.1 enumerate()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;enumerate(iterable, start=0) # 返回一个枚举对象&lt;br /&gt;
注：可选参数start可以设置起始序号&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Kisetsu = [&quot;Haru&quot;, &quot;Natsu&quot;, &quot;Aki&quot;, &quot;Huyu&quot;]
print(enumerate(Kisetsu))
print(list(enumerate(Kisetsu)))
print(list(enumerate(Kisetsu, 10)))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;enumerate object at 0x0000014117E308C0&amp;gt;
[(0, &apos;Haru&apos;), (1, &apos;Natsu&apos;), (2, &apos;Aki&apos;), (3, &apos;Huyu&apos;)]
[(10, &apos;Haru&apos;), (11, &apos;Natsu&apos;), (12, &apos;Aki&apos;), (13, &apos;Huyu&apos;)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.2 zip()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;zip(*iterables, strict=False) # Return an iterator&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;x, y = [1, 2, 3], [4, 5, 6]
z = zip(x, y)
print(z)
print(list(z))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;zip object at 0x0000022F43B43040&amp;gt;
[(1, 4), (2, 5), (3, 6)]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.3 itertools.zip_longest()&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;print(list(zip([1, 2, 3], &quot;Momoyeyu&quot;)))
import itertools
print(list(itertools.zip_longest([1, 2, 3], &quot;Momoyeyu&quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[(1, &apos;M&apos;), (2, &apos;o&apos;), (3, &apos;m&apos;)]
[(1, &apos;M&apos;), (2, &apos;o&apos;), (3, &apos;m&apos;), (None, &apos;o&apos;), (None, &apos;y&apos;), (None, &apos;e&apos;), (None, &apos;y&apos;), (None, &apos;u&apos;)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;zip()默认进行的是截短运算，但可以从itertools中引用itertools.zip_longest()来进行保长运算&lt;/p&gt;
&lt;h3&gt;5.4 map() &amp;amp; filter()&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;map(func, *iterables)&lt;br /&gt;
注：func指的是一套运算规则，map()会将*iterables中的对象都按照func进行计算然后返回其结果组成的iterator&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(list(map(ord, &quot;Momoyeyu&quot;)))
print(list(map(pow, [2, 2, 2], [8, 9, 10, 11])))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[77, 111, 109, 111, 121, 101, 121, 117]
[256, 512, 1024]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由输出第二行可以看出，对于数据长度不同时，map()与zip()相同，选择了截短运算&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;filter(function or None, iterable)
注：和map()类似，但只将结果为True的元素返回到iterator&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;print(list(filter(str.islower, &quot;G-ger&quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;[&apos;g&apos;, &apos;e&apos;, &apos;r&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 迭代器和可迭代对象-iterator &amp;amp; iterable&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;iterator是一次性的，而iterable可以重复使用&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;可参考&lt;a href=&quot;https://blog.csdn.net/pythonandaiot/article/details/122312616&quot;&gt;迭代器和可迭代对象&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;6.1 iterator&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;x = [1, 2, 3, 4, 5]
y = iter(x)
print(type(x))
print(type(y))
i = 0
while i &amp;lt; len(x):
    i+=1
    print(next(y, &quot;Empty&quot;), end=&quot; &quot;)
print(next(y, &quot;Empty&quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;class &apos;list&apos;&amp;gt;
&amp;lt;class &apos;list_iterator&apos;&amp;gt;
1 2 3 4 5 Empty
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;next()函数可以让iterator进行一次迭代，迭代到尽头之后就会报错，可以设置报错内容&lt;/p&gt;
&lt;h3&gt;6.2 iterable&lt;/h3&gt;
&lt;p&gt;可迭代对象可以理解为可以重复使用的迭代器&lt;br /&gt;
iterable可以进行迭代，迭代完成后，它又可以被引用，从头进行迭代，因为它的数据还被完整保留着&lt;br /&gt;
而iterator迭代完成之后，迭代器里的数据就被释放完了，不可再次使用&lt;/p&gt;
&lt;p&gt;一个迭代器&lt;code&gt;肯定&lt;/code&gt;是一个可迭代对象&lt;/p&gt;
&lt;h3&gt;6.3 iterator与iterable比较&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;根据应用场景不同，他们有各自的优劣：
iterator: 不会占用太多资源储存数据，他只会由现在的数据迭代计算下一个数据，但这个过程往往是不可逆的，迭代后上一个数据就抛弃了
iterable: 可以重复使用，迭代后之前的数据也得到保存，但比较占用资源&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Python-字符串</title><link>https://momoyeyu.github.io/posts/python-%E5%AD%97%E7%AC%A6%E4%B8%B2/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/python-%E5%AD%97%E7%AC%A6%E4%B8%B2/</guid><pubDate>Thu, 19 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;参考资料：
&lt;a href=&quot;https://www.bilibili.com/video/BV1c4411e77t&quot;&gt;【Python教程】《零基础入门学习Python》最新版（2022年12月26日更新）&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;字符串&lt;/h1&gt;
&lt;p&gt;关于字符串，主要分为两大块知识：一块是各种字符串相关函数，另一块是format字符串和f-string&lt;/p&gt;
&lt;h2&gt;1. 字母大小写转换&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.capitalize()&lt;/td&gt;
&lt;td&gt;首字母大写，其余小写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.casefold()&lt;/td&gt;
&lt;td&gt;字母全变为小写，可以支持多种语言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.title()&lt;/td&gt;
&lt;td&gt;每个单词首字母都大写，其余小写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.swapcase()&lt;/td&gt;
&lt;td&gt;字母大小写全部和原来相反&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.upper()&lt;/td&gt;
&lt;td&gt;字母全变为大写，英语之外可能不支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.lower()&lt;/td&gt;
&lt;td&gt;字母全变为小写&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：
这些函数都没有直接改变str指向的字符串，而是按规则生成了一个新的字符串，即str还是与原本的字符串挂钩
因此要改变str时：str = str.function()&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;2. 对齐函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.center(width, fillchar=&apos; &apos;)&lt;/td&gt;
&lt;td&gt;width设置总字符数，fillchar设置填充字符，使str&lt;code&gt;居中&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.ljust(width, fillchar=&apos; &apos;)&lt;/td&gt;
&lt;td&gt;width设置总字符数，fillchar设置填充字符，使str&lt;code&gt;左对齐&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rjust(width, fillchar=&apos; &apos;)&lt;/td&gt;
&lt;td&gt;width设置总字符数，fillchar设置填充字符，使str&lt;code&gt;右对齐&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.zfill(width)&lt;/td&gt;
&lt;td&gt;width设置总字符数，str左侧用0填充，若str是数字字符串，可以支持正负数&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;3. 查找函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.count(char, start, end)&lt;/td&gt;
&lt;td&gt;返回str在所选范围char的&lt;code&gt;个数&lt;/code&gt;，起止位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.find(char, start, end)&lt;/td&gt;
&lt;td&gt;返回str在所选范围&lt;code&gt;从左往右&lt;/code&gt;第一个为char的&lt;code&gt;下标&lt;/code&gt;，找不到则返回-1，起止位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rfind(char, start, end)&lt;/td&gt;
&lt;td&gt;返回str在所选范围&lt;code&gt;从右往左&lt;/code&gt;第一个为char的&lt;code&gt;下标&lt;/code&gt;，找不到则返回-1，起止位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.index()&lt;/td&gt;
&lt;td&gt;返回str在所选范围&lt;code&gt;从左往右&lt;/code&gt;第一个为char的&lt;code&gt;下标&lt;/code&gt;，找不到则报错，起止位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rindex()&lt;/td&gt;
&lt;td&gt;返回str在所选范围&lt;code&gt;从右往左&lt;/code&gt;第一个为char的&lt;code&gt;下标&lt;/code&gt;，找不到则报错，起止位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;4. 转换函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.expandtabs(num)&lt;/td&gt;
&lt;td&gt;将str中所有Tab转换为num个空格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.replace(old, new, count=-1)&lt;/td&gt;
&lt;td&gt;将str中old转换为new，可选参数count设置转换个数，默认-1表示全部转换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.translate(table)&lt;/td&gt;
&lt;td&gt;table表示一个转换规则，可由maketrans()生成，可以实现table中对应字符的转换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.maketrans(origin, trans, ignorestr)&lt;/td&gt;
&lt;td&gt;生成一个转换规则，表示将origin中的对象转换为trans中对应的对象，与ignorestr相同的字符串不会被转换&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;5. 判断函数&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这类函数会根据判断的结果返回bool类型数值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.startswith(prefix, start, end)&lt;/td&gt;
&lt;td&gt;判断是否以prefix开头，prefix可以为元组，元组中任意一个元素满足即可，起始位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.endswith(suffix, start, end)&lt;/td&gt;
&lt;td&gt;判断是否以suffix结尾，suffix可以为元组，元组中任意一个元素满足即可，起始位置为可选参数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isupper()&lt;/td&gt;
&lt;td&gt;判断是否全为大写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.islower()&lt;/td&gt;
&lt;td&gt;判断是否全为小写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.istitle()&lt;/td&gt;
&lt;td&gt;判断str是否为标题格式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isalpha()&lt;/td&gt;
&lt;td&gt;判断是否全为字母&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isascii()&lt;/td&gt;
&lt;td&gt;判断是否都为ascii&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isspace()&lt;/td&gt;
&lt;td&gt;判断是否都为空白字符(空格、Tab、换行符等)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isprintable()&lt;/td&gt;
&lt;td&gt;判断是否都可以打印&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isdecimal()&lt;/td&gt;
&lt;td&gt;判断是否数字的一个标准（范围最小）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isdigit()&lt;/td&gt;
&lt;td&gt;判断是否数字的一个标准（范围适中）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isnumeric()&lt;/td&gt;
&lt;td&gt;判断是否数字的一个标准（范围最大）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isalnum()&lt;/td&gt;
&lt;td&gt;判断是否全为字母或数字&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.isidentifier()&lt;/td&gt;
&lt;td&gt;判断str是否为Python的合法标识符&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;5.1 prefix/suffix为元组的例子&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if &quot;她爱Python&quot;.startswith((&quot;我&quot;, &quot;你&quot;, &quot;她&quot;)):
    print(&quot;总有人爱Python&quot;)
# &quot;总有人爱Python&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5.2 isdecimal() &amp;amp; isdigit() &amp;amp; isnumeric() 区别&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = &quot;123&quot;
# All: True
x = &quot;2²&quot;
# x.isdecimal(): False
# x.isdigit() &amp;amp; x.isnumeric(): True
x = &quot;一二三&quot;
# x.isdecimal() &amp;amp; x.isdigit(): False
# x.isnumeric(): True
x = &quot;我不是数字&quot;
# All: False
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 截取函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.strip(chars=None)&lt;/td&gt;
&lt;td&gt;从左右两侧删除选定字符，直到遇到第一个非选定字符时停止；默认None表示空白字符，chars是字符串，&lt;code&gt;会被视为集合&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.lstrip(chars=None)&lt;/td&gt;
&lt;td&gt;从左侧删除选定字符，直到遇到第一个非选定字符时停止；默认None表示空白字符，chars是字符串，&lt;code&gt;会被视为集合&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rstrip(chars=None)&lt;/td&gt;
&lt;td&gt;从右侧删除选定字符，直到遇到第一个非选定字符时停止；默认None表示空白字符，chars是字符串，&lt;code&gt;会被视为集合&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.removeprefix(prefix)&lt;/td&gt;
&lt;td&gt;去除前缀prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.removesuffix(suffix)&lt;/td&gt;
&lt;td&gt;去除后缀suffix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;7. 拆分与拼接&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;str.partition(char)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;从左往右&lt;/code&gt;找到第一个为char的字符，以此为结点拆分得到一个三元组&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rpartition(char)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;从右往左&lt;/code&gt;找到第一个为char的字符，以此为结点拆分得到一个三元组&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.split(sep=None, maxsplit=-1)&lt;/td&gt;
&lt;td&gt;将str拆分为多个字符串并返回其组成的列表；sep设置拆分字符，默认为空白字符；maxsplit设置最大分割数，默认-1表示全部拆分&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.rsplit(sep=None, maxsplit=-1)&lt;/td&gt;
&lt;td&gt;从右往左开始拆分，功能与split()相同&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.splitlines(save=False)&lt;/td&gt;
&lt;td&gt;以换行符为拆分字符将str拆分，可识别&lt;code&gt;不同系统的换行符&lt;/code&gt;；可选参数save控制是否保留换行符到其前面的子串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;str.join(iterable)&lt;/td&gt;
&lt;td&gt;以str为结点连接iterable中各个元素，str可为空字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;7.1 不同系统的换行符&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unix, Linux: \n
Max OS: \r
Windows: \r\n&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;7.2 join() 比 + 的优势在于 join() 的&lt;code&gt;处理效率&lt;/code&gt;远高于 +&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;8. format字符串&lt;/h2&gt;
&lt;h3&gt;8.1 基础用法&lt;/h3&gt;
&lt;p&gt;问题来源：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;year = 2023
month = 1
print(&quot;现在是 year 年 month 月&quot;)
# 现在是 year 年 month 月
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类似于 C/C++ 中的转义字符，Python 的字符串也需要类似转义字符的存在&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;year = 2023
print(&quot;现在是 {} 年 {} 月&quot;.format(year, month))
# 现在是 2023 年 1 月
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;{}中可以通过写&lt;code&gt;下标&lt;/code&gt;选择format()中的数据，且可以&lt;code&gt;重复使用&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;print(&quot;{}爱{}&quot;.format(&quot;我&quot;, &quot;你&quot;))
# 我爱你
print(&quot;{1}爱{0}&quot;.format(&quot;我&quot;, &quot;你&quot;))
# 你爱我
print(&quot;{0}{0}{1}{2}&quot;.format(&quot;mo&quot;, &quot;ye&quot;, &quot;yu&quot;))
# momoyeyu
print(&apos;{2},{1},{0}&apos;.format(*&apos;abc&apos;))
# c,b,a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以使用&lt;code&gt;关键字参数&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;print(&quot;我是{name}，我喜欢{fav}&quot;.format(name = &quot;墨末夜羽&quot;, fav = &quot;吉他&quot;))
# 我是墨末夜羽，我喜欢吉他
print(&quot;我是{fav}，我喜欢{name}&quot;.format(name = &quot;墨末夜羽&quot;, fav = &quot;吉他&quot;))
# 我是吉他，我喜欢墨末夜羽
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8.2 语法格式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;format_spec ::=  [[fill]align][sign][#][0][width][,][.precision][type]
fill        ::=  &amp;lt;any character&amp;gt; &lt;code&gt;# 填充字符&lt;/code&gt;
align       ::=  &quot;&amp;lt;&quot; | &quot;&amp;gt;&quot; | &quot;=&quot; | &quot;^&quot; &lt;code&gt;# 填充位置&lt;/code&gt;
sign        ::=  &quot;+&quot; | &quot;-&quot; | &quot; &quot; &lt;code&gt;# 显示符号&lt;/code&gt;
width       ::=  integer &lt;code&gt;# 打印宽度&lt;/code&gt;
precision   ::=  integer &lt;code&gt;# 浮点数精度&lt;/code&gt;
type        ::=  &quot;b&quot; | &quot;c&quot; | &quot;d&quot; | &quot;e&quot; | &quot;E&quot; | &quot;f&quot; | &quot;F&quot; | &quot;g&quot; | &quot;G&quot; | &quot;n&quot; | &quot;o&quot; | &quot;s&quot; | &quot;x&quot; | &quot;X&quot; | &quot;%&quot; &lt;code&gt;# 数据表达方式&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;8.2.1 示例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;{1:^10}{0:&amp;lt;10}&quot;.format(&quot;123&quot;, &quot;456&quot;)
# &apos;   456    123       &apos; # 居；左对齐
&quot;{:08}{:08}&quot;.format(1024,-1024)
# &apos;00001024-0001024&apos; # 填充0；0不影响符号
&quot;{a:*&amp;gt;10}|{b:*&amp;lt;10}&quot;.format(a=120,b=110)
# &apos;*******120|110*******&apos; # 选择*为填充字符
&quot;{:+,}||{:-_}&quot;.format(1234567,7654321)
# &apos;+1,234,567||7_654_321&apos; # 正数显示正号，每3位用（，）分开；负数显示负号（默认就显示），每3位用（_）分开
&quot;{:.2f}||{:.3g}&quot;.format(12.3456,12.345)
# &apos;12.35||12.3&apos; # 小数点后保留2位数；总共保留3位数
&quot;{:.4}&quot;.format(&quot;Momoyeyu&quot;)
# &quot;Momo&quot; # 保留前4个字符（对数字不可用）
&quot;{0:d}||{0:c}||{0:b}||{0:o}||{0:x}||{0:#b}||{0:#o}||{0:#x}||{0:e}&quot;.format(127)
# &apos;127||\x7f||1111111||177||7f||0b1111111||0o177||0x7f||1.270000e+02&apos; # 详情看下表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;8.2.2 关于type&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;值&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;b&lt;/td&gt;
&lt;td&gt;以二进制输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#b&lt;/td&gt;
&lt;td&gt;b的基础上，会在数前标0b，表示这是二进制数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;以Unicode输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d&lt;/td&gt;
&lt;td&gt;以十进制输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;o&lt;/td&gt;
&lt;td&gt;以八进制输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#o&lt;/td&gt;
&lt;td&gt;o的基础上，会在数前标0o，表示这是八进制数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;x&lt;/td&gt;
&lt;td&gt;以十六进制输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#x&lt;/td&gt;
&lt;td&gt;x的基础上，会在数前标0x，表示这是十六进制数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;以十六进制输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;#X&lt;/td&gt;
&lt;td&gt;X的基础上，后者会在数前标0X，表示这是十六进制数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n&lt;/td&gt;
&lt;td&gt;类似于&apos;d&apos;，但会根据语言环境的分隔符插入到恰当位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;什么都不填，则对整数默认是&apos;d&apos;，对小数默认精度与所给值一样&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;e&lt;/td&gt;
&lt;td&gt;以科学计数法输出，默认精度6位&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;以科学计数法输出，默认精度6位&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f&lt;/td&gt;
&lt;td&gt;以定点表示法输出，默认精度6位（非数用&apos;nan&apos;标示，无穷用&apos;inf&apos;标示）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;以定点表示法输出，默认精度6位（非数用&apos;NAN&apos;标示，无穷用&apos;INF&apos;标示）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;g&lt;/td&gt;
&lt;td&gt;通用格式，小数以&apos;f&apos;输出，大数以&apos;e&apos;输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;G&lt;/td&gt;
&lt;td&gt;通用格式，小数以&apos;F&apos;输出，大数以&apos;E&apos;输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%&lt;/td&gt;
&lt;td&gt;以百分比形式输出，默认精度同f，可通过&apos;.num%&apos;设置精度（num为一个数）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;8.2.3 format字符串综合运用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;{:{fill}{align}{width}.{prec}{typ}}&quot;.format(3.1415, fill=&apos;+&apos;, align=&apos;^&apos;, width=10, prec=3, typ=&apos;g&apos;)
# &apos;+++3.14+++&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. f-string&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;也叫f字符串，字符串前加&apos;f&apos;或&apos;F&apos;，其中{}内的变量名可以引用，算式可以计算，内容也可以格式化输出&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;9.1 示例&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;year = 2023
f&quot;现在是 {year} 年&quot;
# &apos;现在是 2023 年&apos;
F&quot;1+2={1+2}, 2²={2*2}&quot;
# &apos;1+2=3, 2²=4&apos;
f&quot;{-110:0=10}||{3.1415:.2f}&quot;
# &apos;-000000110||3.14&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;9.2 f-string综合运用&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fill, align, width, prec, typ = &apos;+&apos;, &apos;^&apos;, 10, 3, &apos;g&apos;
f&quot;{3.1415:{fill}{align}{width}.{prec}{typ}}&quot;
# &apos;+++3.14+++&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;f-string的效率比format字符串效率要高，但由于其是Python3.6才产生，考虑到兼容性，format字符串使用会更多&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Python-列表与元组</title><link>https://momoyeyu.github.io/posts/python-%E5%88%97%E8%A1%A8%E4%B8%8E%E5%85%83%E7%BB%84/</link><guid isPermaLink="true">https://momoyeyu.github.io/posts/python-%E5%88%97%E8%A1%A8%E4%B8%8E%E5%85%83%E7%BB%84/</guid><pubDate>Tue, 17 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;参考资料：
&lt;a href=&quot;https://www.bilibili.com/video/BV1c4411e77t&quot;&gt;【Python教程】《零基础入门学习Python》最新版（2022年12月26日更新）&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;列表&lt;/h1&gt;
&lt;h2&gt;1. 创建列表&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;mlist = [1, 2, 3, 4, 5, 6]
_ = []
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 访问列表&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;print(mlist[0], end=&quot; &quot;)
print(mlist[-1])
# 1 6
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;for each in mlist:
	print(each, end=&quot; &quot;)
# 1 2 3 4 5 6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 修改列表&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;3.1 通过下标索引修改&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mlist = [1, 1, 3, 4, 5]
mlist[1] = 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果：mlist = [1, 2, 3, 4, 5]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2 通过切片修改&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mlist[3:] = [2, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果：mlist = [1, 2, 3, 2, 1]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.3 通过运算符修改&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_1 = [1, 2]
_2 = [3, 4]
_ = _1 + _2
# _ = [1, 2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 切片&lt;/h2&gt;
&lt;h3&gt;4.1 切片访问列表&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;mlist = [1, 2, 3, 4, 5, 6]
mlist[2:4]
# [3, 4]
mlist[:3]
# [1, 2, 3]
mlist[2:]
# [3, 4, 5, 6]
mlist[:]
# [1, 2, 3, 4, 5, 6]
mlist[0:6:2]
# [1, 3, 5]
mlist[::-1]
# [6, 5, 4, 3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;切片访问语法：&lt;code&gt;列表名[起始下标:停止下标:检索跨度]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;注意：切片访问返回的是一个可迭代对象，所以切片可以实现浅拷贝&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mlist_copy = mlist[:]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 切片修改列表&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;mlist = [1, 2, 3, 4, 5, 6]
mlist[len(mlist):] = [7]
# mlist = [1, 2, 3, 4, 5, 6, 7]
mlist[len(mlist):] = [8, 9]
# mlist = [1, 2, 3, 4, 5, 6, 7, 8, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 函数&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;函数&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;mlist.append(an element)&lt;/td&gt;
&lt;td&gt;将&lt;code&gt;一个元素&lt;/code&gt;追加到列表mlist末尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.extend(iterable)&lt;/td&gt;
&lt;td&gt;将&lt;code&gt;迭代结果&lt;/code&gt;逐个追加到列表mlist末尾&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.insert(an index, an element)&lt;/td&gt;
&lt;td&gt;将该元素&lt;code&gt;插入&lt;/code&gt;到列表mlist的指定下标位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.remove(an element)&lt;/td&gt;
&lt;td&gt;将该元素从列表mlist中&lt;code&gt;删除&lt;/code&gt;，若元素不在列表内，则会报错&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.pop(an index)&lt;/td&gt;
&lt;td&gt;将该下标对应元素从列表中&lt;code&gt;弹出&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.clear()&lt;/td&gt;
&lt;td&gt;将列表mlist变为&lt;code&gt;空列表&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.sort(key=None, reverse=False)&lt;/td&gt;
&lt;td&gt;将列表mlist&lt;code&gt;排序&lt;/code&gt;，参数reverse控制是否&lt;code&gt;倒序&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.reverse()&lt;/td&gt;
&lt;td&gt;将列表&lt;code&gt;倒序&lt;/code&gt;排列&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.count(an element)&lt;/td&gt;
&lt;td&gt;返回这个元素在列表中的&lt;code&gt;个数&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.index(an element, start index, end index)&lt;/td&gt;
&lt;td&gt;返回这个元素的&lt;code&gt;下标&lt;/code&gt;，若有多个则返回第一个&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mlist.copy()&lt;/td&gt;
&lt;td&gt;返回原列表的&lt;code&gt;浅拷贝&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;len(mlist)&lt;/td&gt;
&lt;td&gt;返回值等于列表mlist的&lt;code&gt;长度&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;6. 嵌套列表&lt;/h2&gt;
&lt;p&gt;初始化&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
matrix = [[1, 2, 3], 
          [4, 5, 6],
          [7, 8, 9]]
A = [0] * 3
for i in range(3):
    A[i] = [0] * 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;注： 不要这样声明嵌套列表：&lt;/code&gt;B = [[0] * 3] * 3&lt;/p&gt;
&lt;p&gt;这样声明的列表其实是对同一个[0, 0, 0]引用三次&lt;/p&gt;
&lt;p&gt;即假设 B[0][0] = 1，则B = [[1, 0, 0], [1, 0, 0], [1, 0, 0]]&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B[0] is B[1]
# True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;matrix[0]
# [1， 2， 3]
matrix[0][0]
# 1
for i in matrix:
    for j in i:
        print(j, end=&quot; &quot;)# 空格结尾
    print() # 换行
# 1 2 3
# 4 5 6
# 7 8 9
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7. 列表名与列表&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;x = [1, 2, 3]
y = x
x is y
# True 说明x与y表示同一个列表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注：Python中，变量名并不是一个盒子，数据并非储存在变量中，而是变量名与数据挂钩，列表名能够引用其指向的数据&lt;/p&gt;
&lt;h2&gt;8. 列表拷贝&lt;/h2&gt;
&lt;p&gt;在Python中，拷贝可以分为浅拷贝和深拷贝&lt;/p&gt;
&lt;p&gt;在嵌套结构中，对其中所嵌套元素，浅拷贝仅拷贝其引用，而深拷贝会将嵌套元素也拷贝&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mlist = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
import copy # 深拷贝所在库
mlist_copy1 = mlist # 引用赋值（非拷贝，mlist_copy1 与 mlist 指向同一对象）
mlist_copy2 = copy.copy(mlist) # 浅拷贝
mlist_copy3 = copy.deepcopy(mlist) # 深拷贝
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. 列表推导式&lt;/h2&gt;
&lt;p&gt;语法：&lt;/p&gt;
&lt;p&gt;基本形式：_ = [expression for target in iterable]&lt;/p&gt;
&lt;p&gt;筛选形式：_ = [expression for target in iterable if condition]&lt;/p&gt;
&lt;p&gt;完整形式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = [expression for target1 in iterable1 if condition1  
                for target2 in iterable2 if condition2  
                                 ...  
                for target3 in iterable3 if condition3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = []
for target1 in iterable1:
    if condition1:
        for target2 in iterable2:
            if condition2:
                ...
                    _ = expression
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例&lt;/strong&gt;
1.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mlist = [1, 2, 3, 4, 5]
mlist = [i * 2 for i in mlist]
# mlist = [2, 4, 6, 8, 10]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;mlist = [char * 2 for char in &quot;Momoyeyu&quot;]
# mlist = [&apos;MM&apos;, &apos;oo&apos;, &apos;mm&apos;, &apos;oo&apos;, &apos;yy&apos;, &apos;ee&apos;, &apos;yy&apos;, &apos;uu&apos;]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;matrix = [[1, 2, 3], 
          [4, 5, 6],
          [7, 8, 9]]
diag = [matrix[i][i] for i in range(len(matrix))]
# diag = [1, 5, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;matrix = [[1, 2, 3], 
          [4, 5, 6],
          [7, 8, 9]]
flatten = [col for row in matrix for col in row]
# flatten = [1, 2, 3, 4, 5, 6, 7, 8, 9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;flatten = []
for row in matrix:
    for col in row:
        flatten.append(col)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;_ = [[x, y] for x in range(10) if x % 2 == 0 for y in range(10) if y % 3 == 0]
# _ = [[0, 0], [0, 3], [0, 6], [0, 9], [2, 0], [2, 3], [2, 6], [2, 9], [4, 0], [4, 3], [4, 6], [4, 9], [6, 0], [6, 3], [6, 6], [6, 9], [8, 0], [8, 3], [8, 6], [8, 9]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = []
for x in range(10):
    if x % 2 == 0:
        for y in range(10):
            if y % 3 == 0:
                _.append([x, y])
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;元组&lt;/h1&gt;
&lt;p&gt;许多部分与列表相似，因此不多赘述，没有提到的部分基本都可以参考列表进行操作&lt;/p&gt;
&lt;h2&gt;1. 创建与访问元组&lt;/h2&gt;
&lt;p&gt;创建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_1 = (1, 2, 3, 4, 5)
_2 = 1, 2, 3, 4, 5
_1 == _2 # True
_1 is _2 # False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注：建立元组可以省略小括号，但一定需要加逗号&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x = 1
type(x) # &amp;lt;class &apos;int&apos;&amp;gt;
y = 1,
type(y) # &amp;lt;class &apos;tuple&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问：与访问列表基本一致&lt;/p&gt;
&lt;h2&gt;2. 元组的修改&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;元组不可修改，指的是元组中每个元素的指向永远不变，但元素指向的数据可以发生改变&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = (1, 2, 3 , 4, 5)
_[0] = 0
# Traceback (most recent call last):
#   File &quot;&amp;lt;pyshell#9&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;
#     _[0] = 0
# TypeError: &apos;tuple&apos; object does not support item assignment
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;_ = (1, 2, 3, 4, [1, 2, 3])
_[4].append(4)
# _ = (1, 2, 3, 4, [1, 2, 3, 4])
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 解包操作&lt;/h2&gt;
&lt;p&gt;列表，元组，字符串都可以使用解包操作&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;t = (1, 2, 3)
x, y, z = t
# x = 1; y = 2; z = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;x, y, z = &quot;Momoyeyu&quot;
# Error 左侧变量名和右侧元素数量不等
x, y, *z = &quot;Momoyeyu&quot;
# x = M; y = o; z = &quot;moyeyu&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Python的&lt;code&gt;多重赋值&lt;/code&gt;本质就是先将值包装为元组，再解包与各个变量名挂钩&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x, y = 1, 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;等价于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;_ = (1, 2)
x, y = _
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item></channel></rss>