Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

MySQL——引擎比较说明


关于引擎

  • 查看各种引擎 show engines;
  • 查看当前默认引擎 show variables like '%storage_engine%';
  • 查看指定表的引擎 show create table tableName;
  • 修改指定表的引擎 alter table tableName engine = innodb;
  • 创建表时指定引擎 create table mytable (id int, titlechar(20)) engine = innodb
  • 修改默认存储引擎
    在mysql配置文件(linux下为/etc/my.cnf),在mysqld后面增加default-storage-engine=INNODB即可

不同引擎的事务支持说明

  • MySQL数据库有多种引擎,一般使用的是InnoDB(从MySQL5.5.5以后,InnoDB是默认引擎),InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比Myisam的存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引
  • 其他的引擎不支持事务等,但是存储空间占的比较小,而且操作比较快一些
  • MySQL有多种存储引擎,每种存储引擎有各自的优缺点,可以择优选择使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE
  • 虽然MySQL里的存储引擎不只是MyISAM与InnoDB这两个,但常用的就是两个
    • InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了
  • MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
  • InnoDB支持外键,MyISAM不支持
  • 从MySQL5.5.5以后,InnoDB是默认引擎
  • InnoDB不支持FULLTEXT类型的索引
  • InnoDB中不保存表的行数,如select count(*) from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时MyISAM也需要扫描整个表
  • 对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
  • 清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表
  • InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’

附录:事务的理解

  • 变量 @@autocommit

    1
    2
    select @@autocommit;
    set @@autocommit = 0;
  • @@autocommit 为0时表示不以显示事务开头的语句或者以事务开头(begin; 或者 start transaction;)都会被缓存起来并且在commit;提交前都可以用rollback;回滚

  • @@autocommit 为1时表示必须以事务开头的语句才会被缓存,否则一个sql语句将会被当做一个事务提交,将不能使用rollback;语句回滚

  • 说明:不是所有引擎都支持事务,常用的支持事务的引擎是InnoDB

Hexo——命令总结

Hexo命令归纳整理


init

hexo init [folder]

# 在cmd命令下,cd到你所需要建立博客的文件夹,执行此命令,其中folder为可选指令,若不写,则默认当前目录


hexo new

hexo new [layout] \<title\>

#layout为可选项,默认使用_config.yml中的default_layout。新建文章的指令


generate

hexo generate

# 生成静态文件,

# 可选参数:

-d ,–deploy 文件生成后立即部署网站

-w , –watch 件事文件变动


deploy

hexo deploy

# 发布到网站,这里就是发布到 _config.yml中deploy中设置的网址上。

# 参数

-g , –generate 部署前生成静态文件


npm install

每一个rn项目都有一个package.json文件,里面有很多组件信息,使用npm install将按照package.json安装所需要的组件放在生成的node_modules文件夹中,rn项目下的每一个文件中都可以通过import引入node_modules的组件来加以使用


hexo clean

hexo clean 清除缓存文件(db.json)和已生成的静态文件(public),通常更换主题后,无效时,可以运行此命令


hexo server

hexo server

# 启动server,就可以在本地预览效果。

#参数,默认网址http://localhost:4000/

-p , –port 重设端口

-s , –static 只是用静态文件

-l , –log 启动日志记录,使用覆盖记录格式

-i , –ip 重新制定服务器ip

Math——梯度和微分的理解

梯度方向是函数局部上升最快的方向


微分的定义与理解

  • 假设在任意方程中存在自变量 \(t\) 和因变量 \(x,y\),他们都是 \(t\) 的函数 \(x(t),y(t)\),则当所有因变量都对同一个自变量 \(t\) 计算变化量时,即可得到微分形式:
    $$
    \begin{align}
    d y &= y(t+\Delta) - y(t) \\
    d x &= x(t+\Delta) - x(t) \\
    d t &= (t+\Delta) - t = \Delta
    \end{align}
    $$
    • 其中 \(\Delta \rightarrow 0\)
  • 此时有:
    • 导数 \(\frac{dy}{dt}\) 表示因变量 \(y\) 关于 \(t\) 的变化率,是 \(t\) 的函数
    • 导数 \(\frac{dx}{dt}\) 表示因变量 \(x\) 关于 \(t\) 的变化率,是 \(t\) 的函数
    • 导数 \(\frac{dy}{dx}\) 可以表示因变量 \(y\) 关于 \(x\) 的变化率:
      $$ \frac{dy}{dx} = \frac{\frac{dy}{dt}}{\frac{dx}{dt}} $$
      • 注意: 从上面的证明可以看出,要求 \(dy\) 和 \(dx\) 都是在同一个自变量(这里是 \(t\),也可以是其他变量,比如 \(x\) )发生微小变化的时候得到的
  • 注意:
    • \(dy\) 表示微分,具体是关于 \(x\) 或 \(t\),亦或是其他变量的增量,要根据上下文来判断
    • \(\frac{dy}{dt}\) 表示 \(y\) 关于 \(t\) 的变化率,在不同的 \(t\) 点,变化率不同,所以 \(\frac{dy}{dt}\) 是关于 \(t\) 的函数, \(\frac{dy}{dt}\vert_{t=t_0}\) 可表示 \(y\) 关于 \(t\),在 \(t=t_0\) 处的变化率

梯度的定义与理解

  • 对函数 \(f(x, y, z)\) 而言
  • 方向导数:各个方向的导数,函数,标量
    • 关于x, y, x的偏导数: \(\frac {\partial f}{\partial x}, \frac {\partial f}{\partial y}, \frac {\partial f}{\partial z}\)
    • 对特定的某一点 \((x_{0}, y_{0}, z_{0})\) 而言,改点的偏导数是将对应的值带入后得到的数值,是一个确定的数值
  • 梯度:各个方向导数组成的向量,每一维为一个方向导数,矢量
    • 梯度: \((\frac {\partial f}{\partial x}, \frac {\partial f}{\partial y}, \frac {\partial f}{\partial z}\)),一个向量
    • 梯度方向表示函数局部上升最快的方向
    • 梯度的模 \(|\nabla f|\) 表示变化率

直观理解

  • 一维函数中,代表参数(自变量)的点在一条直线上运动,所以梯度的方向有正向和负向
  • 二维函数中,代表参数(自变量)的点在一个平面上运动,所以梯度的方向有无数种,但都在二维平面上
  • 三维函数中,代表参数(自变量)的点在一个空间中运动,所以梯度的方向有无数种,但都在三维空间中
  • 无论何时,梯度方向是函数上升最快的方向,指明参数朝着这个方向移动时,函数上升的速度最快
  • 梯度下降法中,求取梯度的意义就在于知道函数上升或者下降最快的方向

关于梯度的模 \(|\nabla f|\)

  • 梯度的方向与参数(自变量)的变化相关,梯度的模 \(|\nabla f|\) 与函数变化相关
  • 梯度的模可以理解为变化率,也就是在梯度对应的方向上移动单位长度后,函数能上升的数值大小为 \(|\nabla f|\) (当然,这是按照当前点周围的极小的曲面拟合出来的平面计算得到的数值,不是真正的函数数值)
  • 梯度下降法中,梯度的方向指明了参数移动的方向,梯度的模暗示着参数移动时函数的增量大小
  • 但为什么梯度下降法中,保留着梯度的模?而不是将梯度向量变成单位向量?梯度的模有什么特殊的意义吗?
    • 一个猜想:在梯度下降法时,如果超参数步长 \(\alpha\) 不变的话,每次迭代时参数(自变量)真正移动的长度是 \(\alpha\times |\nabla f|\),此时随着迭代次数的增加, \(|\nabla f|\) 值会越来越小(可以证明,因为越来越接近最地点,函数变化率越来越小),这会导致 \(\alpha\times |\nabla f|\) 越来越小,从而减少震荡?
    • 梯度的模的意义可用数学证明,移动梯度的模的 \(\alpha\) 倍是最优的,详情参考我的博客ML——最优化方法-无约束参数优化方法中用一阶泰勒展开推导梯度下降法的过程
      • 基本思路,将函数在参数的某个值 \(\theta_{t} + \delta\) 处一阶泰勒展开,然后对 \(\delta\) 加上正则项.最后在直接求导即可得到梯度下降法的更新表达式

附录:其他参考博客

  • 参考链接: 为什么梯度方向是函数局部上升最快的方向

Python——easydict包的使用


整体说明

  • EasyDict 是一个轻量级的 Python 库,旨在简化字典操作,它允许用户像访问对象属性一样访问字典的键值对,从而提高代码的可读性和简洁性
  • EasyDict 通过重写字典的几个关键方法,如__getattr__和__setattr__等,实现了将字典键转换为对象属性的功能
  • EasyDict 不仅支持顶级字典的属性访问方式,还能递归应用于内嵌的字典,使得处理多层次数据结构变得简单易行
  • EasyDict 实例仍然遵循标准字典的所有操作,保证了灵活性

安装 EasyDict

  • 可以使用pip进行安装,命令如下:
    1
    pip install easydict

使用示例

  • 简单使用示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from easydict import EasyDict as edict
    # 创建一个EasyDict对象
    data = edict({'name': 'John', 'age': 30, 'job': 'Engineer'})
    # 访问字典元素
    print(data.age)
    print(data.job)
    # 添加新的键值对
    data.gender = 'Male'
    print(data.gender)
  • 嵌套字典的访问:

    1
    2
    3
    4
    5
    6
    7
    8
    my_dict = edict({
    'level1': edict({
    'level2': edict({
    'key': 'value'
    })
    })
    })
    print(my_dict.level1.level2.key)
  • 动态设置属性:

    1
    2
    3
    my_dict = edict()
    my_dict.key1 = 'value1'
    print(my_dict.key1)
  • 常见的字典操作:

    1
    2
    3
    4
    5
    6
    7
    my_dict = edict({'key1': 'value1'})
    # 更新字典
    my_dict.update({'key2': 'value2'})
    print(my_dict.key2)
    # 删除一个键值对
    my_dict.pop('key1')
    print(my_dict.key1) # 会抛出AttributeError,因为'key1'不再存在
  • 获取默认值:

    1
    2
    3
    my_dict = edict({'name': 'Alice'})
    value = my_dict.get('nonexistent_key', 'default_value')
    print(value)

EasyDict 和 namedtuple 对比

  • EasyDict 和 namedtuple 都是 Python 中用于简化数据访问的工具
  • TDRL:namedtuple 是”先定义类,再用类创建实例”;EasyDict 是”直接用通用类创建实例,动态定义结构”
    • namedtuple 需要先定义特定结构的类(如Person),再创建该类的实例,适合固定结构的数据
    • EasyDict 直接使用通用的EasyDict类创建实例,实例的字段结构可以动态变化,适合灵活的数据场景
  • TDRL:若需 固定结构、不可变数据 ,追求性能和内存效率,用 namedtuple;若需 动态结构、灵活修改 ,优先便捷性,用 EasyDict

本质与继承关系

  • namedtuple 是 tuple 的子类,属于不可变(immutable)数据结构
    • 一旦创建,其字段值无法修改,类似元组的特性
  • namedtuple 定义时需要指定固定的字段名,结构是静态的,不能动态添加新字段
  • EasyDict 是 dict 的子类,属于可变(mutable)数据结构
    • 创建后可以随时修改字段值,也能动态添加/删除新字段,保留了字典的灵活性

数据访问方式

  • 两者都支持 属性式访问(如 obj.field)和 键值访问(如 obj['field']),但底层实现不同:
    • namedtuple 本质是元组,字段值存储在固定位置,访问速度更快
    • EasyDict 本质是字典,通过重写 __getattr__ 实现属性访问,性能略低于 namedtuple

可变性

  • namedtuple 不可变:创建后无法修改字段值,也不能添加新字段,类似常量集合,示例如下:

    1
    2
    3
    4
    from collections import namedtuple
    Person = namedtuple('Person', ['name', 'age'])
    p = Person('Alice', 30)
    p.age = 31 # 报错:'Person' object does not support item assignment
  • EasyDict 可变:支持修改现有字段、添加新字段、删除字段等操作,示例如下:

    1
    2
    3
    4
    5
    from easydict import EasyDict as edict
    p = edict(name='Alice', age=30)
    p.age = 31 # 允许修改
    p.gender = 'Female' # 允许添加新字段
    del p.age # 允许删除字段

定义类情况

  • namedtuple 显式定义了一个新的类(如Person),这个类继承自tuple,并且在定义时就固定了字段结构,例如:

    1
    2
    3
    4
    from collections import namedtuple
    # 这里显式创建了一个名为 Person 的类
    Person = namedtuple('Person', ['name', 'age'])
    print(type(Person)) # 输出:<class 'type'>,说明是一个类
    • 后续使用时,Person() 是创建该类的实例,每个实例都严格遵循预定义的字段结构
  • EasyDict 没有要求你显式定义新的类(如Person),但它本身是一个通用的 EasyDict 类,所有实例都属于这个类,例如:

    1
    2
    3
    4
    from easydict import EasyDict as edict
    # 直接创建 EasyDict 类的实例,无需预先定义结构
    p = edict(name='Alice', age=30)
    print(type(p)) # 输出:<class 'easydict.EasyDict'>
    • 你将 p 视为一个”动态对象”,它属于 EasyDict 类,但其字段可以灵活添加/修改,不需要提前定义特定的类(如Person)

适用场景

  • namedtuple 适合存储 固定结构、不可变的数据(如配置项、记录、坐标等),强调数据的稳定性和内存效率
    • 例如:表示点坐标 Point(x=1, y=2)、数据库查询结果等
  • EasyDict 适合处理 动态结构、需要灵活修改的数据(如嵌套配置、JSON 数据解析等),强调操作的便捷性
    • 例如:解析 API 返回的 JSON 数据(可动态添加/修改字段)、多层级的配置文件等

其他差异

  • 内存占用 :namedtuple 比 EasyDict 更轻量,内存占用更少
  • 序列化 :两者都支持序列化,但 namedtuple 可直接通过 _asdict() 转换为普通字典,EasyDict 本身就是字典,可直接序列化
  • 类型提示 :namedtuple 在定义时已明确字段,类型提示更友好;EasyDict 动态字段较多,类型提示较弱

Python——field的用法


整体说明

  • 在 Python 中,field 主要关联两个核心场景:
    • 一是标准库 dataclasses 模块的 field() 函数 ,用于定制数据类字段
    • 二是第三方库如 pydantic 的 Field 类 (注意:首字母是大写), 用于数据校验/序列化

dataclasses.field()

  • dataclasses 是 Python 内置的轻量级数据类工具
  • field() 用于精细化定义数据类的字段(替代默认的简单赋值),支持定制默认值、初始化行为、序列化等
    • 注:Python 3.7+ 内置

dataclasses.field() 基础语法

  • 用法示例:

    1
    2
    3
    4
    5
    from dataclasses import dataclass, field

    @dataclass
    class ClassName:
    name = field(...) # 字段名: 类型 = Field(参数1=值1, 参数2=值2, ...)
  • field() 核心参数说明

    • default
      • 字段默认值(仅当字段无默认值时使用,与 default_factory 二选一)
      • 示例:field(default=0)
    • default_factory
      • 动态生成默认值的工厂函数(如列表/字典等可变类型)
      • 示例:field(default_factory=list)
    • init
      • 是否参与 __init__ 方法(默认 True)
      • 示例:field(init=False)
    • repr
      • 是否出现在 __repr__ 输出中(默认 True)
    • compare
      • 是否参与比较(__eq__/__lt__ 等,默认 True)
    • hash
      • 是否参与 __hash__ 计算(默认 None,继承 compare 值)
    • metadata
      • 附加元数据(字典,供外部工具使用)
      • field(metadata={"desc": "用户ID"})

dataclasses.field() 常用示例

  • 示例:基础使用(默认值/工厂函数)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from dataclasses import dataclass, field

    @dataclass
    class User:
    # 简单默认值(不可变类型)
    id: int = field(default=0)
    # 可变类型默认值(必须用 default_factory,避免所有实例共享同一对象)
    tags: list[str] = field(default_factory=list)
    # 字符串默认值
    name: str = field(default="未知用户")

    # 实例化
    u1 = User()
    print(u1) # User(id=0, tags=[], name='未知用户')
    u1.tags.append("admin")
    u2 = User()
    print(u2.tags) # [](独立的列表,无共享问题)
  • 示例2:定制初始化/序列化行为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @dataclass
    class Product:
    name: str
    # 不参与 __init__(手动赋值)
    price: float = field(init=False)
    # 不显示在 repr 中
    stock: int = field(default=0, repr=False)
    # 不参与比较
    sku: str = field(default="", compare=False)

    # 实例化(无需传 price 和 stock/sku)
    p = Product("手机")
    p.price = 2999.99 # 手动赋值
    print(p) # Product(name='手机', price=2999.99)(stock 未显示)
    print(p == Product("手机")) # True(sku 不参与比较)
  • 示例3:附加元数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @dataclass
    class Student:
    id: int = field(metadata={"desc": "学生学号", "required": True})
    score: float = field(default=0.0, metadata={"min": 0, "max": 100})

    # 获取元数据
    s = Student(1001)
    # 方式1:通过 dataclasses.fields 获取
    from dataclasses import fields
    for f in fields(s):
    print(f.name, f.metadata)
    # 输出:
    # id {'desc': '学生学号', 'required': True}
    # score {'min': 0, 'max': 100}

pydantic.Field(第三方库,数据校验)

  • pydantic 是Python主流的数据校验库
  • Field 用于定义模型字段的校验规则、默认值、文档等,功能比 dataclasses.field 更丰富
  • 使用前先安装:
    1
    pip install pydantic

pydantic.Field 基础语法

  • 用法说明:

    1
    2
    3
    4
    from pydantic import BaseModel, Field

    class ClassName(BaseModel):
    name = field(...) # 字段名: 类型 = Field(默认值, 参数1=值1, 参数2=值2, ...)
  • 核心参数说明

    • default/default_factory:
      • 默认值/动态默认值(同dataclasses)
      • 示例:Field(default=10) / Field(default_factory=list)
    • alias
      • 字段别名(序列化/反序列化时可用)
      • 示例: Field(alias="user_id")
    • gt/ge/ lt/le
      • 数值大于/大于等于/小于/小于等于
      • 示例:Field(gt=0)(值必须>0)
    • min_length/max_length
      • 字符串最小/最大长度
      • 示例:Field(min_length=2, max_length=10)
    • pattern
      • 字符串正则匹配
      • 示例:Field(pattern=r"^[A-Z]+$")
    • description
      • 字段描述(文档生成)
      • 示例:Field(description="用户年龄")
    • nullable
      • 是否允许为None(Pydantic v1,v2需用 Optional)
      • 示例:Field(nullable=True)
    • examples
      • 示例值(OpenAPI文档)
      • 示例:Field(examples=[18, 20])

pydantic.Field常用示例

  • 示例1:基础校验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from pydantic import BaseModel, Field

    class User(BaseModel):
    name: str = Field(..., min_length=2, max_length=20, description="用户名(2-20字符)")
    age: int = Field(..., gt=0, le=120, description="年龄(1-120)")
    email: str = Field(None, pattern=r"^[\w-]+@[\w-]+\.[a-z]+$", description="邮箱(可选)")

    # 合法实例
    u1 = User(name="张三", age=25, email="zhangsan@example.com")
    print(u1.model_dump())
    # 输出:{'name': '张三', 'age': 25, 'email': 'zhangsan@example.com'}

    # 非法实例(触发校验错误)
    try:
    u2 = User(name="李", age=150, email="invalid-email")
    except Exception as e:
    print(e)
    # 输出:
    # 1 validation error for User
    # name
    # String should have at least 2 characters [type=string_too_short, input_value='李', input_type=str]
    # age
    # Input should be less than or equal to 120 [type=less_than_or_equal, input_value=150, input_type=int]
    # email
    # String should match pattern '^[\w-]+@[\w-]+\.[a-z]+$' [type=string_pattern_mismatch, input_value='invalid-email', input_type=str]
  • 示例2:别名与默认值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Product(BaseModel):
    # 别名:序列化时用 product_id,反序列化时可传 id 或 product_id
    id: int = Field(..., alias="product_id")
    # 动态默认值(每次实例化生成新列表)
    tags: list[str] = Field(default_factory=lambda: ["未分类"])

    # 用别名传参
    p = Product(product_id=1001)
    print(p.id) # 1001
    print(p.tags) # ['未分类']
    # 序列化(输出别名)
    print(p.model_dump(by_alias=True)) # {'product_id': 1001, 'tags': ['未分类']}
  • 示例3:结合文档(OpenAPI)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from pydantic import BaseModel, Field
    from pydantic.schema import schema

    class Order(BaseModel):
    order_id: str = Field(..., pattern=r"^ORD-\d{6}$", description="订单号(格式:ORD-6位数字)")
    amount: float = Field(..., gt=0, examples=[99.9, 199.0], description="订单金额(>0)")

    # 生成JSON Schema(用于OpenAPI文档)
    schema_dict = schema([Order])
    print(schema_dict)

三、pydantic.Field 和 dataclasses.field 区别

  • dataclasses.field:
    • 内置库
    • 简单数据存储、无校验需求
    • 无校验能力(仅基础类型注解)
  • pydantic.Field:
    • 第三方接口
    • 接口参数校验、数据清洗、API文档
    • 强大的数值/字符串/结构校验

使用注意:

  • 可变类型默认值 :
    • 无论是 dataclasses.field 还是 pydantic.Field,可变类型(list/dict/set)的默认值必须用 default_factory,否则所有实例会共享同一对象
    • 错误:tags: list = []
    • 正确:tags: list = field(default_factory=list)
  • Pydantic版本差异 :
    • v1 中 nullable=True 允许字段为None;v2 需用 Optional[类型](如 age: Optional[int] = Field(None))
    • v2 中 Field 的参数更简洁,推荐使用最新版
  • dataclasses 不可变字段 :
    • 若需不可变数据类,加 @dataclass(frozen=True),此时 init=False 的字段需在 __post_init__ 中赋值

Python——heapq模块-最大堆最小堆

由于queue不是Python标准库,所以在LeetCode等OJ上面不能直接使用,我们可以选择heapq来使用最大最小堆


使用示例

  • 堆排序示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import heapq

    nums = [2, 3, 5, 1, 54, 23, 132]
    heap = []
    for num in nums:
    heapq.heappush(heap, num)
    # 等价于
    heapq.heapify(nums)

    # heap sort by incresing
    print([heapq.heappop(heap) for _ in range(len(nums))])
  • 加入元素

    1
    heapq.heappush(heap, num)
  • 弹出元素

    1
    num = heapq.heappop(heap)
  • 获取最大最小值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import heapq

    nums = [1, 3, 4, 5, 2]
    print(heapq.nlargest(3, nums))
    print(heapq.nsmallest(3, nums))

    #Output:
    [5, 4, 3]
    [1, 2, 3]
  • 获取堆顶元素

    1
    top = nums[0]

最大堆的实现

  • 由于Python heapq模块只实现了最小堆, 最大堆需要我们自己实现
  • 一种简单可行的实现方案:
    • 在加入和弹出时,把元素取反 ,从而实现最大堆

Python——iter函数的用法


整体说明

  • 在 Python 里,iter() 函数主要用于生成迭代器
  • 迭代器用于遍历可迭代对象(像列表、元组、字典这样的),能逐个获取对象里的元素
  • 用法可总结如下:
    • iter() 函数的主要作用是把可迭代对象转变为迭代器
    • 迭代器通过 next() 函数来获取下一个元素
    • 可以通过自定义类并实现 __iter__() 和 __next__() 方法来自定义迭代器
    • 使用 StopIteration 异常或者设置哨值能够终止迭代

iter()函数的基本用法

  • 函数用法:

    1
    iter(iterable)
    • 这里的 iterable 可以是列表、元组、字符串、集合等可迭代对象
  • 示例:遍历列表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    my_list = [1, 2, 3, 4, 5]
    my_iter = iter(my_list)

    # # 错误用法,会抛出异常
    # for i in range(10):
    # print(next(my_iter)) # 依次输出:1,2,3,4,5,第6次调用时直接抛出异常 StopIteration

    # 正确用法
    for i in my_iter:
    print(i) # 依次输出:1,2,3,4,5 然后停止

自定义迭代器(无终止迭代)

  • 借助 iter() 函数,还能自定义迭代器,这需要在类中实现 __iter__() 和 __next__() 方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class MyNumbers:
    def __iter__(self):
    self.a = 1
    return self

    def __next__(self):
    x = self.a
    self.a += 1
    return x

    myclass = MyNumbers()
    myiter = iter(myclass)

    print(next(myiter)) # 输出:1
    print(next(myiter)) # 输出:2
    print(next(myiter)) # 输出:3

自定义迭代器(终止迭代)

  • 在自定义迭代器时,可以使用 StopIteration 异常来终止迭代
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class MyNumbers:
    def __iter__(self):
    self.a = 1
    return self

    def __next__(self):
    if self.a <= 3:
    x = self.a
    self.a += 1
    return x
    else:
    raise StopIteration

    myclass = MyNumbers()
    myiter = iter(myclass)

    for x in myiter:
    print(x) # 依次输出1,2,3后停止(注意程序是自然退出的,不会抛出异常)

附录:Iterable 和 Iterator 的区别

  • 可迭代对象(Iterable) :任何可以被 iter() 函数调用并返回一个迭代器的对象
    • 常见例子:列表(list)、元组(tuple)、字符串(str)、字典(dict)、集合(set)等
    • 可以用 for 循环遍历,不存储迭代状态(即每次调用 iter() 都会生成一个新的迭代器)
    • 可以被多次迭代(每次都是新的迭代器)
  • 迭代器(Iterator) :实现了 __next__() 方法和 __iter__() 方法的对象
    • 常见例子:由 iter() 函数返回的对象、生成器(generator)等
    • 有“状态”,记录当前迭代位置
    • 调用 next() 方法会返回下一个元素,直到耗尽后抛出 StopIteration
    • 只能迭代一次(无法重置,耗尽后失效)
    • __iter__() 方法返回自身(所以迭代器也是一种可迭代对象)
  • 特别说明:DataLoader 本身是一个可迭代对象(iterable),而非一次性迭代器(iterator)

附录:特别说明 iter() 的第二个参数

  • iter() 函数还有一种不太常见的用法,就是接收两个参数
    • 第一个参数得是个可调用对象(像函数)
    • 第二个参数是哨值
  • 当可调用对象返回的值等于哨值时,迭代就会停止
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def my_function():
    value = input("请输入内容(输入 'q' 结束):")
    return value

    # 创建迭代器,当输入 'q' 时停止
    my_iter = iter(my_function, 'q')

    for value in my_iter:
    print(f"你输入的是:{value}")

    # 请输入内容(输入 'q' 结束):123
    # 你输入的是:123
    # 请输入内容(输入 'q' 结束):q

附录:for 循环和 __iter__ 函数的用法

  • 在 for i in x 循环中,x.__iter__() 只会被调用一次 ,且该方法的返回值必须是一个 Iterator(迭代器)
    • 这属于 Python 迭代协议(Iteration Protocol)的核心要求
  • __iter__ 的调用 1 次后,循环的所有迭代过程,都基于 __iter__ 返回的同一个迭代器
  • __iter__ 的返回值要求:必须返回一个实现了迭代器协议的对象(即同时具有 __iter__() 和 __next__() 方法的对象)
    • 可迭代对象的 __iter__:“生产迭代器”(返回新的迭代器实例);
    • 迭代器的 __iter__:“暴露自己”(返回自己,因为自己就是 “干活的”)
    • 迭代器的 __next__(),真正用于返回下一个元素
  • 支持 for 循环的对象,一定是具有 __iter__() 函数的

原理拆解:for 循环的执行流程

  • for i in x 的底层逻辑完全遵循迭代协议,步骤如下:
    • 1)调用 x.__iter__(),获取一个迭代器对象(记为 it);
    • 2)反复调用 it.__next__(),每次返回的结果赋值给 i,执行循环体;
    • 3)当 it.__next__() 抛出 StopIteration 异常时,循环捕获该异常并正常终止(不会暴露给用户)
  • 注:整个过程中,x.__iter__() 只在第一步执行一次,后续所有迭代都依赖第一步返回的那个 it 迭代器

如何自定义 iterable 对象?

  • 方法一:实现 iter() 方法
  • 方法二:getitem() + len() 方法
  • 在使用类似 for i in x 时,Python 的迭代机制会:
    • 首先尝试调用 iter() 方法
    • 如果没有 iter(),则尝试使用 getitem() 和 len()
      • 此时 Python 会自动从 idx=0 开始调用 getitem(0), getitem(1), … 直到抛出 IndexError

General——各种镜像源的管理

各种镜像源管理


pip 镜像源

  • 一般来说pip默认使用的源可能会比较慢,此时需要修改成国内的源

查看源

  • 查看当前 pip 源
    1
    pip config list

修改方法:

临时修改
  • 在命令后面添加如下参数即可将安装源换成阿里云

    1
    -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com
  • 只在当前命令中修改,以后想要使用时需要继续添加参数

  • 特别说明: 在阿里云的服务器上使用这个指令时效果非常明显

永久修改
  • 修改文件~/.pip/pip.conf内容, 如果没有该文件则新建一个

    1
    2
    3
    4
    5
    vim ~/.pip/pip.conf
    # write the following contents and save
    # the example is USTC
    [global]
    index-url = https://pypi.mirrors.ustc.edu.cn/simple/
  • 这个命令修改当前用户的默认pip命令镜像

镜像列表

  • 各种镜像列表:

    1
    2
    3
    4
    5
    6
    7
    官方:https://pypi.org/simple
    清华:https://pypi.tuna.tsinghua.edu.cn/simple
    阿里云:http://mirrors.aliyun.com/pypi/simple/
    中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
    华中科技大学:http://pypi.hustunique.com/
    山东理工大学:http://pypi.sdutlinux.org/
    豆瓣:http://pypi.douban.com/simple/
  • 其中清华的比较常用


Ubuntu 源

  • Linux 一般默认使用自己系统的源,比如 Ubuntu 使用的就是自己的 Ubuntu 官网源

修改方法

  • 修改文件/etc/apt/source.list
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    sudo /vim/apt/source.list

    # write new image source
    # the example of aliyun
    deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

    # update and upgrade
    sudo apt-get update
    sudo apt-get upgrade

镜像源列表

中科大源
  • 中科大源列表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    deb https://mirrors.ustc.edu.cn/ubuntu/ bionic main restricted universe multiverse
    deb-src https://mirrors.ustc.edu.cn/ubuntu/ bionic main restricted universe multiverse
    deb https://mirrors.ustc.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src https://mirrors.ustc.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    deb https://mirrors.ustc.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src https://mirrors.ustc.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    deb https://mirrors.ustc.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    deb-src https://mirrors.ustc.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    deb https://mirrors.ustc.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src https://mirrors.ustc.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
163 源
  • 163 源列表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse
清华源
  • 清华源列表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
    deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
    deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-proposed main restricted universe multiverse

Centos 源

修改方法

  • 修改文件/etc/yum.repos.d/CentOS-Base.repo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # backup
    sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo_bak
    # create new config file
    # the example of aliyun, the config file could be downloaded from remote directly
    sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    # update chche
    sudo yum makechche
    # update
    sudo -y update

镜像源列表

网易源
  • Centos6: http://mirrors.163.com/.help/CentOS6-Base-163.repo
  • Centos7: http://mirrors.163.com/.help/CentOS7-Base-163.repo
阿里源
  • Centos6: http://mirrors.aliyun.com/repo/Centos-6.repo
  • Centos7: http://mirrors.aliyun.com/repo/Centos-7.repo

Mac brew 源

  • 参考链接:(Mac 下 brew 切换为国内源)[https://cloud.tencent.com/developer/article/1614039]

conda 源

  • 查看 conda 源:

    1
    conda config --show channels
  • 删除 conda 源:

    1
    conda config --remove channels [target_url]
  • 清空 conda 源:

    1
    conda config --remove-key channels
    • 这个命令不会删除 defaults 源,如果要删除该源,需要手动删除
  • 添加 conda 源:

    1
    conda config --add channels [new_channel_url]
  • 安装时临时指定镜像

    1
    conda install -c [channel_url] [package_name]

conda 源的分类

  • Conda 源的路径后缀可看出其用途:
    • /cloud/pytorch/ :提供PyTorch深度学习框架及其依赖库
    • /cloud/menpo/ :提供计算机视觉相关工具(如dlib、OpenCV)
    • /cloud/conda-forge/ :社区维护的开源包(覆盖科学计算、数据分析等领域)
    • /pkgs/free/ :Anaconda早期免费版仓库(现多合并至main)
    • /pkgs/main/ :Anaconda官方核心包(Python、NumPy、SciPy等基础库)

以清华源为例

  • 示例添加清华源:

    1
    2
    3
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
    conda config --set show_channel_urls yes
    • conda config --set show_channel_urls yes 可让后续的安装都打印 conda 源信息
  • 一条指令恢复默认源(清空所有源):

    1
    conda config --remove-key channels

Git——GitHub-Pages的CNAME设置


CNAME是什么

  • CNAME是DNS解析中的一种别名记录,允许同一个网站有两个不同的记录解析过去
  • CNAME在GitHub Pages中体现为可以将xxx.github.io的域名添加别名为自定义的域名(这个域名通常是自己买的,在域名那里也要配置解析到当前xxx.github.io)

GitHub Pages中使用CNAME时遇到的问题

  • 我们可以在GitHub账户中设置CNAME
  • 重新提交commit并推送数据到GitHub上后,之前设置的CNAME会被删除,需要重新设置,也就是说每次push操作后都需要重新设置
    • 这个问题在hexo d后也会出现

解决方案

  • 在当前项目的GitHub Pages对应的分支下面新建一个文件,命名为CNAME
  • 打开文件并新建一行为目标网站的域名(如果是中文域名则需要编码转换)
  • 在Hexo中,我们可以在source文件夹下面新建该文件
    • hexo generate时会将source文件夹下面的文件都拷贝到public文件夹下面

Git——使用总结

  • 参考链接:
    • 值得参考的博客:https://segmentfault.com/a/1190000008617626
    • 更详细解释一般直接查看 git (command) -h 即可

总体概况总结

  • 简单结构图:
  • 全局结构图:

常见的分支管理

  • 查看本地分支

    1
    git branch
  • 查看所有分支(包括远程)

    1
    git branch -a
  • 删除本地分支

    1
    2
    3
    4
    # 安全删除(safe delete),Git 会检查该分支是否已经完全合并到当前分支(或者 HEAD 所指的分支);如果分支上还有未合并的提交,Git 会阻止删除
    git branch -d branch_name
    # 强制删除(force delete);等价于:'git branch --delete --force <branch>',不管分支是否已合并,都会直接删除
    git branch -D branch_name
  • 删除远程分支

    1
    git push origin :branch_name
    • 将空的东西推送到远程的branch_name分支,也就是删除远程分支
  • 新建本地分支

    1
    2
    3
    4
    5
    6
    # 将远程分支拉取到本地的 Repository 中,但不修改本地工作目录,如果本地分支不存在,则新建分支
    git fetch origin master:branch_name
    # 从当前分支 fork 一个分支出来
    git checkout -b branch_name
    # 若 branch_name 分支在本地工作目录不存在,但是 origin 上存在,则本地工作目录上会创建 branch_name
    git checkout branch_name
  • 新建远程分支

    1
    git push origin master:branch_name
    • 将本地分支推送到远程,如果branch_name不存在,则新建分支

冲突管理

远程分支和本地分支有不同的 commit

  • git pull和git push均产生reject异常

  • 使用下面语句拉取远程分支到本地old分支并合并

    1
    2
    git fetch origin master:old
    git merge old
  • 上面两句等价于

    1
    git pull origin master:old
    • 注意:不建议使用 pull 拉取其他分支,容易产生操作失误
  • 如果能够快速合并,也就是相同文件没有同时被不同提交修改:

    • 上面的语句将弹出一个合并窗口提示输入合并这个操作(提交)的 Comment,按照提示提交保存即可
    • 保存后自动生成一个以刚才的 Comment 命名的提交
  • 不能快速合并时

    • 上面的语句会提示我们哪些文件有合并冲突需要解决的
    • 我们需要根据提示找到并修改文件中冲突
    • 然后重新提交(像正常提交代码一样即可)
      1
      2
      git add .
      git commit -m " "
  • 合并完成后删除多余分支

    1
    git branch -d old

附录:fetch 和 pull 两者比较:

1
2
git pull == git fetch + git merge
git pull origin master:old == git fetch origin master:old + git merge old

git diff

  • git diff A B
    • 基于 A 查看 B 有何变化
    • 显示时会自动识别为基于 a/A 看 b/B 有何变化

文件恢复

恢复本地缓冲区文件到disk

  • 恢复某个文件:git checkout -- xx/xx.py
  • 恢复某个文件夹下所有文件:git checkout -- xx/*
  • 指定恢复某个分支到指定文件:git checkout master -- xx/xx.py

恢复HEAD到缓冲区

  • 仅恢复到缓冲区:git reset or git reset HEAD
  • 不仅恢复到缓冲区,同时恢复到disk: git reset HEAD --hard

从远程拉取一个新分支

  • 从远程拉取分支到本地:git fetch origin xxx
    • 此时使用 git branch -a 可以看到远程分支引用在本地
    • git fetch origin xxx 后,FETCH_HEAD 会指向远程 xxx 分支
      • FETCH_HEAD 是个临时的引用,可以对该分支做任意想做的操作,比如此时可用 git merge FETCH_HEAD 来合并新拉取的分支
  • 创建本地同名新分支:git checkout xxx
    • 必须同名

git clone 进阶

  • git clone ssh:xxx 默认拉取master分支
  • git clone -b [branch] ssh:xxx 拉取 [branch] 分支

git clone 仅拉取某个分支

  • 仅拉取某个分支,用于大型项目

    1
    git clone --single-branch --branch [branch] ssh:xxx
  • 如果想进一步降低下载量(不关心历史记录),可以加上 --depth 1 参数

  • 注意:如果使用下面的命令(即不添加 --single-branch 参数),会拉取所有分支内容 ,但是本地仅检出目标分支

    1
    2
    3
    git clone --branch [branch] ssh:xxx
    # 等价简写形式
    git clone -b [branch] ssh:xx

删除本地跟踪远程分支

  • git branch -d --remotes origin/xxx
    • 测试发现:git 1.7.1会报错,git 2.24.3没问题

git pull 和 git push 默认分支设定

  • git branch --set-upstream-to=origin/xxx xxx
    • 经测试:git 1.7.1会报错,git 2.24.3没问题(但git pull不会生效)

添加文件到.gitignore

  • 如果文件已经被添加到Git仓库中(常常出现在一些不规范的项目中),则可以考虑使用以下步骤解决:
    • 假设Git仓库中已经把.DS_Store添加到Git仓库中
    • 首先拉取项目并在.gitignore中添加*.DS_Store
    • 执行git rm --cached *.DS_Store, 从缓冲区中删除所有*.DS_Store文件,但保留本地文件
    • 执行git add .并重新提交

在目录内部忽略自身

  • 可以不修改外部的 .gitignore 文件(即不修改项目根目录下的 .gitignore 文件),通过在某个目录下增加 .gitignore 文件来定义子目录下的忽略规则

  • 用法示例:./venv/.gitignore

    1
    *
    • 表示忽略该 ./venv/ 目录下的所有文件
  • 这种方法很有益于管理本地多余的文件夹,因为不需要修改到 项目本身的 .gitignore 文件


Git 标签的使用

  • Git 标签(tag)是用于标记仓库中特定提交节点的引用,常用于版本发布(如 v1.0.0)、重要里程碑等场景,方便后续快速定位和回溯

标签类型

  • 轻量标签(lightweight)
    • 仅作为某个提交的“指针”,不包含额外信息(如创建者、时间、注释),本质是一个 commit_id 的引用
    • 适合本地临时标记
  • 带注释标签(annotated)
    • 完整的标签对象,包含标签名、创建者、时间戳、详细注释等信息,会被 Git 永久存储在仓库中
    • 适合正式版本发布(推荐使用)

创建标签

  • 创建带注释标签(推荐)

    1
    2
    git tag -a <标签名> -m "<标签注释>"
    # 示例:git tag -a v1.0.0 -m "正式发布 v1.0.0 版本"
    • -a:指定创建带注释标签
    • -m:直接添加注释(若省略,会打开编辑器输入)
  • 给历史提交打标签:默认标签是打在当前最新提交上,若要给历史提交打标签,需指定 commit_id (可通过 git log 查看):

    1
    2
    git tag -a <标签名> <commit_id> -m "<注释>"
    # 示例: git tag -a v0.9.0 a1b2c3d -m "修复 bug 后的预发布版本"
  • 创建轻量标签:无需 -a 和 -m,直接指定标签名:

    1
    2
    3
    git tag <标签名>  # 默认为当前提交
    # 或指定历史提交
    git tag <标签名> <commit_id>

查看标签

  • 列出所有标签(仅列出标签名)

    1
    git tag
  • 按字母顺序排列(非创建时间,仅列出标签名),可加筛选(如查看 v1 开头的标签)

    1
    git tag -l "v1.*"  # -l 表示筛选(list)
  • 查看标签详情:查看带注释标签的完整信息(包括创建者、时间、注释、对应提交等)

    1
    2
    git show <标签名>
    # 示例:git show v1.0.0 # 查看 `v1.0.0` 的详情
  • 列出远程标签(包含标签 id 和 commit_id 等)

    1
    git ls-remote --tags origin
    • 列出的结果会同时包含标签自己的实体 id(如 v1.1.0) 和 对应的 commit_id (如 v1.1.0^{})
  • 列出本地标签(包含标签 id)

    1
    git show-ref --tags

推送和拉取远程仓库标签

  • 创建的标签默认只保存在本地,需手动推送到远程仓库

  • 推送单个标签

    1
    2
    git push origin <标签名>
    # 示例:git push origin v1.0.0
  • 推送所有本地未推送的标签

    1
    git push origin --tags
  • 拉取远程仓库所有标签

    1
    git fetch origin --tags
  • 拉取远程仓库单个标签到指定标签

    1
    2
    3
    git fetch origin refs/tags/v1.2.0:refs/tags/v1.2.0
    # 等价命令
    git fetch origin v1.2.0:refs/tags/v1.2.0 # 在不会引起误会的情况下,前面的前缀 refs/tags/ 可以删除,但后面的不可以
    • 本地会新增 v1.2.0 标签,指向与远程该标签相同的 commit
    • 注:refs/tags/v1.2.0 中的 refs/tags/ 是标签的前缀完整命名,是必要的,否则会被当做 branch(实际上 branch 的完整命名是 refs/heads/xx)

删除标签

  • 删除本地标签

    1
    git tag -d <标签名>
  • 删除远程仓库的标签:需先删除本地标签,再推送删除操作到远程:

    1
    2
    git tag -d <标签名>  # 先删本地
    git push origin --delete <标签名> # 再删远程

检出标签(查看标签对应的代码)

  • 标签是静态的(不可修改),检出标签时会进入“分离头指针”状态(detached HEAD),此时修改不会影响任何分支,适合临时查看历史版本:

    1
    git checkout <标签名>
  • 若要基于标签修改代码,需创建新分支:

    1
    git checkout -b <新分支名> <标签名>

标签管理最佳实践

  • 命名时,建议使用语义化版本(如 v<主版本>.<次版本>.<修订号>,例 v2.1.3),清晰区分版本迭代
  • 优先使用带注释标签,包含完整信息,便于协作和追溯
  • 推送标签前确认,标签一旦推送到远程,尽量避免删除(尤其是已发布的版本标签),如需删除需同步团队
  • 发布版本时,在 release 或 main 分支打标签,确保标签对应稳定代码

Git 配置相关

  • 用户配置查看

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 查看所有配置(含用户信息)
    git config --list

    # 查看「当前生效」的用户名/邮箱
    git config user.name
    git config user.email

    # 查看「当前仓库」的用户配置(仅对当前项目生效)
    git config --local user.name
    git config --local user.email

    # 查看全局「用户」配置(对所有仓库生效,默认常用)
    git config --global user.name
    git config --global user.email

    # 查看系统级用户配置(需管理员权限,Windows 可能需要以管理员打开终端,这个命令很少用)
    git config --system user.name
    git config --system user.email
  • 用户配置设置

    1
    2
    3
    4
    5
    6
    7
    # 全局配置(所有仓库通用,推荐)
    git config --global user.name "用户名"
    git config --global user.email "邮箱"

    # 仅当前仓库配置(覆盖全局,适合单独项目需求)
    git config --local user.name "用户名"
    git config --local user.email "邮箱"

Git Blame 使用

整体说明

  • git blame 的作用是逐行显示文件的修改记录 ,包括:
    • 每行代码的最后一次提交哈希;提交作者;提交时间;提交行号;代码说明
    • 注意:默认会打印每一行的情况
  • 常用于排查 Bug(定位是谁改了这行代码)、了解代码逻辑的修改背景

基础用法说明

  • 基本用法

    1
    2
    # 查看指定文件的逐行修改记录
    git blame 文件名
    • 打印每一行的情况,文件的每行对应 terminal 的一行输出
  • 常用参数

    • -L:指定查看的行范围(行号/正则)
      • 如:git blame -L 5,10 README.md(查看5-10行)
    • -e:显示作者邮箱(默认只显示用户名)
    • -w:忽略空格变化(避免因空格修改误判)
    • -C:追踪代码的移动/复制(跨文件也能追踪)
      • 默认情况下,git blame 只会显示某行代码最后一次修改的提交记录,但如果这行代码是从其他地方(同一文件/其他文件)复制 / 移动过来的,-C 会穿透这种复制 / 移动操作,追踪到代码最初被添加的提交和文件
      • 注:Git 会将文件拆分成若干个连续的文本块(默认最小 20 行,可通过 –line-porcelain 调整),并为每个块计算一个哈希值(类似文件的 MD5 校验和)
      • 更多参数:
        • -C:只在当前文件的历史版本中比对指纹(识别同一文件内的移动);
        • -CC:在本次提交的所有文件中比对指纹(识别同提交内的跨文件复制);
        • -CCC:在整个仓库的所有历史提交 + 所有文件中比对指纹(识别任意来源的复制)
    • --date:自定义时间格式(relative/short/iso)
      • 如:git blame --date=relative README.md(显示“3天前”)

常见用法示例

  • 查看指定行范围

    1
    2
    3
    4
    5
    6
    7
    8
    # 查看 5 到 10 行的修改记录
    git blame -L 5,10 src/main.py

    # 查看从第5行到文件末尾
    git blame -L 5, src/main.py

    # 通过正则匹配行(比如找包含"def login"的行)
    git blame -L '/def login/,+5' src/main.py
  • 结合提交哈希查看详情

    • git blame 输出的提交哈希可以配合 git show 查看完整提交信息:

      1
      git show [commit_id]
    • 这可以看到对应提交的修改

  • 忽略空行/注释修改

    1
    2
    # 忽略空格、空行、注释的修改(更聚焦代码逻辑)
    git blame -w -M -C README.md
1…626364
Joe Zhou

Joe Zhou

Stay Hungry. Stay Foolish.

631 posts
53 tags
GitHub E-Mail
© 2026 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4