Jiahong 的个人博客

凡事预则立,不预则废


  • Home

  • Tags

  • Archives

  • Navigation

  • Search

MySQL——Ubuntu18.04安装及配置

解决Ubuntu18.04安装Ubuntu后普通用户没有权限登录问题


安装

  • 安装命令
    1
    2
    3
    4
    5
    6
    7
    8
    # 安装mysql服务
    sudo apt-get install mysql-server
    # 安装客户端
    sudo apt install mysql-client
    # 安装依赖
    sudo apt install libmysqlclient-dev
    # 检查状态
    sudo netstat -tap | grep mysql

远程链接设置

默认远程链接问题

Ubuntu18.04 安装mysql后,普通用户没有连接mysql数据库权限(local或者remote均没有权限)

  • mysql -u root或者直接用使用MySQL Workbench连接均失败,显示如下错误

    ERROR 1045: Access denied for user: ‘root@localhost’ (Using password: YES)

  • 使用sudo mysql -u root能正确连接

打开远程链接数据

(删除之前的root并重新创建账户)

  • 登录

    1
    sudo mysql -u root
  • 然后查看当前用户

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    select User,Host from mysql.user;
    # Output:
    +------------------+-----------+
    | User | Host |
    +------------------+-----------+
    | admin | localhost |
    | debian-sys-maint | localhost |
    | magento_user | localhost |
    | mysql.sys | localhost |
    | root | localhost |
  • 删除root账号

    1
    drop user 'root'@'localhost';
  • 创建新的root账号

    1
    create user 'root'@'%' identified by '123456';
  • 为新账号授权

    1
    2
    grant all privileges on *.* to 'root'@'%' with grant option;
    flush privileges;
  • 退出

    1
    exit;
  • 以普通用户身份登录

    1
    mysql -u root -p

Mac——HomeBrew简介


HomeBrew是什么?

  • HomeBrew是一个Mac OS上的软件包管理器,命令是brew,类似于Ubuntu上的DPKG(apt-get)或者Centos上的RPM(yum)等

HomeBrew的安装

  • 安装命令

    1
    /usr/bin/ruby -e"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • 查看安装结果

    1
    brew -v

HomeBrew管理软件包

  • HomeBrew的安装的软件包默认在/usr/local/Cellar下
  • HomeBrew用@指明版本号

搜索云端软件

返回结果中可以看到版本号,后续安装可指定版本号安装

1
brew search key_str

安装

1
brew install pkg_name

卸载

1
brew remove pkg_name

更新

1
brew upgrade pkg_name

列出所有已安装软件

1
brew list

查看某个云端软件包信息

1
brew info pkg_name

HomeBrew管理服务

启动服务

1
brew services start service_name

停止服务

1
brew services stop service_name

重启服务

1
brew services restart service_name

列出所有HomeBrew管理的服务

1
brew services list

Mac——查看文件占用情况


整体说明

  • 快速查看非隐藏第一层目录大小:du -sh */
  • 包含隐藏目录:find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \;
  • 按大小排序:在上述命令后加 | sort -hr
  • 查看逻辑大小(对应稀疏文件):du -shL */

最常用:显示第一层目录大小(人类可读格式,如 M/G)

  • 命令详情:

    1
    du -sh */
  • 命令解释:

    • du:统计目录/文件的磁盘占用;
    • -s(--summarize):只显示总大小(不列出子文件/子目录的详细大小);
    • -h(--human-readable):用人类易读的单位(K/M/G)显示;
    • */:通配符,只匹配当前目录下的「第一层子目录」(结尾的 / 是关键,排除文件,只选目录);
  • 简单直接,默认显示「实际磁盘占用」(和 Linux du -sh */ 逻辑一致),适合快速查看


精准筛选第一层目录(避免通配符遗漏,如隐藏目录)

  • */ 会匹配所有非隐藏的第一层目录,但如果有「隐藏目录」(如 .hidden_dir),会被遗漏

  • 如果需要包含隐藏目录,用 find 筛选第一层目录,再传递给 du:

    1
    2
    # 包含隐藏目录的第一层目录大小(人类可读)
    find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \;
  • 命令解释:

    • find .:从当前目录(.)开始查找;
    • -maxdepth 1:只查找「第一层」(不递归子目录);
    • -type d:只匹配目录(排除文件);
    • ! -name ".":排除当前目录本身(只保留子目录);
    • -exec du -sh {} \;:对找到的每个目录,执行 du -sh 统计总大小;

按大小排序(方便找出最大目录)

  • 如果想按目录大小「从大到小排序」,结合 sort 命令(Mac 自带 BSD sort,参数和 Linux 略有差异):

    1
    2
    3
    4
    5
    # 第一层目录大小(非隐藏),按大小降序排序
    du -sh */ | sort -hr

    # 包含隐藏目录,按大小降序排序
    find . -maxdepth 1 -type d ! -name "." -exec du -sh {} \; | sort -hr
  • 命令解释:

    • sort -hr:-h 识别人类可读单位(如 M/G),-r 反向排序(从大到小);

显示「逻辑大小」(而非磁盘占用,对应稀疏文件场景)

  • 如果想查看目录的「逻辑总大小」(而非磁盘占用,和 ls 统计逻辑一致),用 du -shL */:

    1
    2
    # 第一层目录的逻辑总大小(人类可读)
    du -shL */
  • 命令解释:

    • -L(--dereference):跟随符号链接,并统计链接指向文件的「逻辑大小」(而非磁盘占用);
    • 适合用于确认目录的逻辑总数据量(比如对比 Linux 上的逻辑大小)

关键补充:Mac 和 Linux 的 du 差异

  • 单位一致性:-h 参数在 Mac 和 Linux 上行为一致(K/M/G 单位);
  • 隐藏目录:Mac 上 */ 不匹配隐藏目录,需用 find 命令包含;
  • 稀疏文件:Mac 上 du 默认统计「实际磁盘占用」,如果目录内有稀疏文件(未展开),du -sh 显示实际占用,du -shL 显示逻辑大小

统计一个文件夹下所有数据逻辑大小

  • 递归列出所有数据,加起来,并以 MB(兆字节)为单位输出(Mac 和 Linux 通用):

    1
    ls -lR ./ | awk '{sum += $5} END {print sum/1024/1024 "M"}'
  • 命令解释

    • ls -lR ./:递归输出当前目录下所有文件/目录的详细信息(作为数据源)
      • -R(recursive,递归):不仅列出当前目录的文件/目录,还会递归列出所有子目录下的文件/目录
      • 注意:不包括隐藏文件和文件夹,可以通过改为下面的指令来显示隐藏文件
        • ls -laR ./,包含 . 和 ..(ls -l 中目录的第5列是“目录元数据大小”(不是目录内文件总大小),数值极小,可以忽略)
        • ls -lAR ./,不包含 . 和 ..
    • awk '{sum += $5} END {print sum/1024/1024 "M"}':计算所有文件的逻辑大小总和,并转换为 MB 单位
      • awk 是文本处理工具,这里用于“提取第5列的字节数,求和后转换为 MB”:
      • 循环累加({sum += $5}):
        • $5:表示取每一行的「第5个字段」(awk 中用 $n 表示第n个字段,字段默认用空格分隔)
        • sum += $5:定义一个变量 sum,把每一行第5列的数值(文件逻辑大小,字节)累加到 sum 中
        • 注意:目录的第5列(几十字节)也会被累加,但因为数值极小,对总结果几乎无影响(比如100个目录的元数据总和可能只有几 KB,相对于几百 MB 的文件总和可忽略)
      • 最终输出(END {print sum/1024/1024 "M"}):
        • END:表示“所有行都处理完后,执行以下操作”(仅执行一次)
        • sum/1024/1024:单位转换:字节 -> KB(除以1024)-> MB(再除以1024)
        • "M":拼接字符串,让输出结果带单位(比如 600M 而非纯数字)
        • print:输出最终结果

注意统计的是「逻辑大小」,不是「磁盘实际占用」

  • 逻辑大小:文件本身的“理论大小”(比如稀疏文件的预留空间、普通文件的实际数据大小),和 ls -lh 显示的大小一致;
  • 磁盘实际占用:文件在磁盘上真正占用的空间(比如稀疏文件的实际写入数据大小),需用 du 统计;
  • ls -l 中目录的第5列是“目录元数据大小”(不是目录内文件总大小),但因为数值极小(通常几十字节),累加后对总结果(几百 MB)几乎无影响,无需刻意排除

Pyhton——defaultdict的用法


整体说明

  • defaultdict 是 Python 标准库 collections 模块中的一个工具,继承自普通字典 dict
  • defaultdict 的核心特点是:访问不存在的键时,会自动创建该键并赋予默认值
    • 无需手动判断 key in dict 或使用 dict.get(key, 默认值)
  • defaultdict 的核心是 “自动处理不存在的键” ,适合以下场景:
    • 统计计数(defaultdict(int))
    • 分组聚合(defaultdict(list)/set)
    • 避免频繁判断 key in dict 或 dict.get()

defaultdict 基本用法

  • 初始化:指定“默认值工厂函数”:defaultdict 的构造函数接收一个 可调用对象(工厂函数) ,当访问不存在的键时,会调用该函数生成默认值
  • 常见的工厂函数可以是:
    • 内置类型:int(默认 0)、list(默认空列表)、set(默认空集合)、str(默认空字符串)
    • 自定义函数:返回固定值或动态生成的值
  • 可以用于解决普通字典的痛点:访问不存在的键会抛出 KeyError
    1
    2
    3
    4
    5
    6
    7
    8
    # 普通字典:访问不存在的键报错
    d = {}
    print(d["foo"]) # KeyError: 'foo'

    # defaultdict:自动创建键并赋予默认值
    from collections import defaultdict
    dd = defaultdict(int) # 默认值为 0
    print(dd["foo"]) # 输出 0,且 dd 现在是 {'foo': 0}

defaultdict 使用示例

  • 统计元素出现次数(用 int 作工厂)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from collections import defaultdict

    words = ["apple", "banana", "apple", "orange", "banana", "apple"]
    count = defaultdict(int) # 键不存在时默认值为 0

    for word in words:
    count[word] += 1 # 无需判断键是否存在,直接累加

    print(dict(count)) # 转为普通字典:{'apple': 3, 'banana': 2, 'orange': 1}
  • 分组(用 list 作工厂):将元素按某个规则分组,值为列表(自动创建空列表,避免手动 append 时报错):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from collections import defaultdict

    students = [("Alice", "Math"), ("Bob", "English"), ("Alice", "Physics"), ("Bob", "Math")]
    group = defaultdict(list) # 键不存在时默认值为 []

    for name, subject in students:
    group[name].append(subject) # 直接向列表添加元素

    print(dict(group))
    # 输出:{'Alice': ['Math', 'Physics'], 'Bob': ['English', 'Math']}
  • 去重分组(用 set 作工厂):值为集合 set,自动去重:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from collections import defaultdict

    data = [("a", 1), ("b", 2), ("a", 1), ("b", 3)]
    group = defaultdict(set) # 键不存在时默认值为 set()

    for key, val in data:
    group[key].add(val) # 集合自动去重

    print(dict(group)) # 输出:{'a': {1}, 'b': {2, 3}}
  • 自定义默认值(用自定义函数作工厂):如果需要非内置的默认值(如 None、固定字符串、动态值),可传入自定义函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from collections import defaultdict

    # 自定义工厂函数:返回固定值 "unknown"
    def default_val():
    return "unknown"

    dd = defaultdict(default_val)
    print(dd["foo"]) # 输出 "unknown",dd 变为 {'foo': 'unknown'}

    # 简化:用 lambda 表达式(适合简单默认值)
    dd2 = defaultdict(lambda: None) # 默认值为 None
    print(dd2["bar"]) # 输出 None

    dd3 = defaultdict(lambda: [1, 2, 3]) # 默认值为 [1,2,3]
    print(dd3["baz"]) # 输出 [1,2,3]

特别注意 dict.fromkeys()

  • dict.fromkeys() 也能设置默认值,但会为所有键共享同一个可变对象(如列表),容易踩坑:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 普通 dict.fromkeys() 的坑:所有键共享同一个列表
    d = dict.fromkeys(["a", "b"], [])
    d["a"].append(1)
    print(d) # {'a': [1], 'b': [1]}(意外修改了 b 的值)

    # defaultdict 无此问题:每个键的列表是独立的
    dd = defaultdict(list)
    dd["a"].append(1)
    print(dd) # {'a': [1]}(b 未被创建)

Pyhton——原生random模块的使用


整体说明

  • 随机种子(seed)是初始化随机数生成器的状态,相同种子产生完全相同的随机序列(可复现性)
    • 不设置种子时,使用系统时间(time.time())作为种子,每次运行结果不同
    • 种子可以是整数、字符串、字节等(内部会转换为整数)
  • 随机状态(state)本质是生成器的内部状态(包含所有必要信息,确保后续随机数可预测)
    • random.getstate():保存当前状态(返回一个元组)
    • random.setstate(state):恢复到之前保存的状态
  • 全局 random 模块在所有地方共享一个状态,不是线程安全的(多线程会竞争状态)
    • 建议多使用 局部 random.Random 实例而不是全局 random 模块

random 模块示例

  • 以下是一个原生的 Python random 模块使用示例:
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    import random

    print("=" * 50)
    print("随机种子的可复现性演示")
    print("=" * 50)

    print("\n【不设置种子(全局随机)】")
    random.seed() # 重置为默认状态(系统时间种子)
    print(f"第一次随机整数序列: {[random.randint(1, 100) for _ in range(3)]}")
    print(f"第二次随机整数序列: {[random.randint(1, 100) for _ in range(3)]}")

    print("\n【设置固定种子】")
    random.seed(42) # 固定种子,注意 seed 是一个函数,不要写成 random.seed = 42,这样会导致 seed 失效
    print(f"种子42-序列: {[random.randint(1, 100) for _ in range(3)]}") # 结果为固定值,跨平台跨进程可复现

    random.seed(42) # 固定种子,重新设置相同种子,会重置随机序列到初始状态
    print(f"种子42-序列: {[random.randint(1, 100) for _ in range(3)]}") # 结果复现上面的结果

    print("\n" + "=" * 50)
    print("随机状态的保存与恢复")
    print("=" * 50)

    random.seed(100) # 先设置种子,确保初始状态一致
    print(f"\n初始状态-随机数序列: {[random.randint(1, 100) for _ in range(3)]}")

    state = random.getstate() # 保存当前随机状态(返回一个不可变对象,包含完整的随机生成器状态)
    print(f"状态改变后-随机数序列: {[random.randint(1, 100) for _ in range(3)]}") # 继续生成几个随机数

    random.setstate(state)# 恢复之前保存的状态,从当时状态开始继续除数,就像是 seed(100) 后已经输出过多个 随机数一样
    print(f"恢复状态后-随机数序列: {[random.randint(1, 100) for _ in range(3)]}") # 继续生成几个随机数,得到的结论是跟上面一致的

    print("\n" + "=" * 50)
    print("全局随机 vs 局部随机实例")
    print("=" * 50)

    # 全局 random:所有模块共享同一个状态
    print("\n【全局随机(共享状态)】")
    random.seed(200)
    print(f"全局-随机数1: {random.uniform(0, 10)}")
    print(f"全局-随机数2: {random.uniform(0, 10)}")

    # 局部 Random 实例:独立状态,不影响全局
    local_rand1 = random.Random(300) # 局部实例1,种子300
    local_rand2 = random.Random(300) # 局部实例2,种子300
    local_rand3 = random.Random(400) # 局部实例2,种子400

    print("\n【局部随机实例(独立状态)】")
    print(f"局部1-随机数(seed=300): {local_rand1.randint(1, 10)}")
    print(f"局部2-随机数(seed=300): {local_rand2.randint(1, 10)}")
    print(f"局部3-随机数(seed=400): {local_rand2.randint(1, 10)}")

    # ==================================================
    # 随机种子的可复现性演示
    # ==================================================
    #
    # 【不设置种子(全局随机)】
    # 第一次随机整数序列: [100, 29, 44]
    # 第二次随机整数序列: [16, 34, 5]
    #
    # 【设置固定种子】
    # 种子42-序列: [82, 15, 4]
    # 种子42-序列: [82, 15, 4]
    #
    # ==================================================
    # 随机状态的保存与恢复
    # ==================================================
    #
    # 初始状态-随机数序列: [19, 59, 59]
    # 状态改变后-随机数序列: [99, 23, 91]
    # 恢复状态后-随机数序列: [99, 23, 91]
    #
    # ==================================================
    # 全局随机 vs 局部随机实例
    # ==================================================
    #
    # 【全局随机(共享状态)】
    # 全局-随机数1: 0.4560930208539393
    # 全局-随机数2: 2.0344697486239927
    #
    # 【局部随机实例(独立状态)】
    # 局部1-随机数(seed=300): 10
    # 局部2-随机数(seed=300): 10
    # 局部3-随机数(seed=400): 6

附录:特别说明

  • random.seed 是一个函数而不是一个数字或字符串,需要使用 random.seed(1) 而不是 random.seed=1 来设置种子
    • 这里容易理解错误
  • 所有设置了固定种子的部分(如 seed=42、local_rand1 = random.Random(300)),每次运行结果完全一致
  • 全局随机在未设置种子时,每次运行结果不同;但恢复状态后,会延续之前的序列
  • 局部实例的操作不会影响全局或其他局部实例的状态,实现了完全隔离
  • random.shuffle(input) 是个 in-place 修改方法,会直接修改 input 对象的值

附录:random 隔离实用技巧

  • 临时固定状态:保存原始状态 -> 设置临时种子 -> 执行操作 -> 恢复原始状态(避免污染全局)
  • 独立随机流:为不同任务/模块分配独立种子(比如 task_seed = base_seed + task_id),确保并行任务结果可复现
  • 局部状态持久化:保存局部实例的状态(如 local_rand.getstate()),后续可在其他地方恢复继续使用
  • 禁止全局污染:封装局部实例,强制代码使用独立随机生成器(避免误改全局状态)

Python——@dataclass注解的使用


整体说明

  • @dataclass 是 Python 3.7 引入的一个装饰器,属于 dataclasses 模块,用于简化类的定义
  • @dataclass 在初始化对象后,还会自动生成常用方法如 __init__、__repr__、__eq__ 等

@dataclass 用法示例

  • 综合示例:汇总 @dataclass 各种用法

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    from dataclasses import dataclass, field
    from typing import Union, Dict, List, Callable, Optional
    from easydict import EasyDict as edict

    # 下面的语句中的参数是可选的,常常用 @dataclass 即可
    @dataclass(
    init=True, # 自动生成 __init__
    repr=True, # 自动生成 __repr__
    eq=True, # 自动生成 __eq__
    order=True, # 自动生成比较方法(<、<=、>、>=)
    unsafe_hash=False, # 不自动生成 __hash__
    frozen=False # 允许属性修改, 若设置为 True 则不允许修改属性,报错dataclasses.FrozenInstanceError: cannot assign to field 'xx'
    )
    class DemoDataClass:
    # 类型注解 + 必须参数(@dataclass注解过的类,字段的类型注解是必须需要的)
    # 字段的类型注解仅做类型检查(如 mypy、Pyright)看的,实际上仍然可以赋值为任意类型
    name: str

    # 类型注解 + 默认值
    age: int = 18

    # 可能是 字典{str:edict} 或 列表[str],默认值取 None
    tools: Union[Dict[str, edict], List[str]] = None

    # 可以是 int,也可以是 None
    children: Optional[int] = None

    # 类型注解 + 默认工厂函数
    tags: list = field(default_factory=lambda: ["python", "dataclass"])

    # 不参与 __init__,表示该字段不会作为参数传递给构造函数,无法通过参数传入
    # # 后续可在 __post_init__ 函数中自己定义或修改
    # # 字段仍然是对象属性,可以被访问和修改,且仍然可以被 __repr__、__eq__ 等方法使用(除非通过 repr=False 或 compare=False 排除)
    # # 通常用于那些需要在对象创建后由其他逻辑赋值的字段,比如自增主键、计算得出的值
    id: int = field(init=False, default=0)

    # 排除字段(不会参与比较和展示)
    secret: str = field(default="hidden", repr=False, compare=False)

    # 排除字段(不会参与比较和展示)
    temp_data: dict = field(default_factory=dict, repr=False, compare=False)

    # 函数字段定义
    print_fn: Callable = lambda x: print(x)

    # 用函数的方式定义字段,实际访问时必须按照字段语法访问
    @property
    def age_name(self):
    return "%s_%s" % (self.age, self.name) # 可使用类的字段访问

    # 自定义初始化逻辑,在自动生成的 __init__ 函数执行后会被调用
    def __post_init__(self):
    self.id = hash(self.name + str(self.age)) # 仅初始化一次,以后再修改 name 或 age 不会引起 self.id 的变化(除非显示调用.__post_init__())

    # 使用示例
    demo1 = DemoDataClass(name="Alice")
    # demo1 = DemoDataClass(name="Alice", id=100) # 报错:TypeError: DemoDataClass.__init__() got an unexpected keyword argument 'id'
    demo2 = DemoDataClass(name="Bob", age=25, tags=["dev"], temp_data={"x": 1})

    print(demo1) # DemoDataClass(name='Alice', age=18, tools=None, children=None, tags=['python', 'dataclass'], id=1490295676558033675, print_fn=<function DemoDataClass.<lambda> at 0x10e504a60>)
    print(demo2) # DemoDataClass(name='Bob', age=25, tools=None, children=None, tags=['dev'], id=6412555795401615714, print_fn=<function DemoDataClass.<lambda> at 0x10e504a60>)
    print(demo1 == demo2) # False;比较结果
    print(demo1.tags) # ['python', 'dataclass'];默认工厂
    print(demo1.secret) # hidden
    print(demo1.age_name) # 18_Alice;须按照字段方式读取
    # print(demo1.age_name()) # 报错 TypeError: 'str' object is not callable
    demo1.tools = 100 # 请记住:字段类型仅作为声明检查,并不会直接报错
    print(demo1) # DemoDataClass(name='Alice', age=18, tools=100, children=None, tags=['python', 'dataclass'], id=1490295676558033675, print_fn=<function DemoDataClass.<lambda> at 0x10e504a60>)
    demo1.print_fn("print me") # print me
  • 示例说明

    • 类型注解:所有字段都需要类型注解,@dataclass 会自动识别,没有给出类型的字段会报错
    • 默认值:通过直接赋值或 field(default=...) 指定
    • 默认工厂:如 default_factory 用于可变类型(如列表、字典)
    • init=False:字段不参与初始化,只在类内部赋值,__init__ 内不可读
    • repr=False, compare=False:字段不参与对象展示和比较
    • __post_init__:用于自定义初始化逻辑
    • order=True:自动生成排序方法
    • frozen=True:设置后对象不可变(本例未启用)

附录:在 dataclass 中使用 field 和不使用 field 的区别

  • 使用 field 的字段
    • 通过 field() 传递更多参数来控制字段行为
    • 可以精细控制字段的初始化、展示、比较、哈希、默认值生成等行为,适合复杂需求
    • 常用参数包括
      • default:指定默认值(同直接赋值)
      • default_factory:指定一个工厂函数,用于生成默认值(常用于可变类型,如列表、字典)
      • init:是否包含在 __init__ 方法参数中(True/False)
      • repr:是否包含在 __repr__ 方法中(True/False)
      • compare:是否用于比较(__eq__、__lt__ 等)
      • hash:是否用于哈希
      • metadata:可存储任意元数据
  • 不使用 field 的字段
    • 直接用类型注解和可选的默认值定义字段
    • 只能简单指定类型和默认值,适合简单场景
    • 默认动作:
      • 默认会参与 __init__ 方法(即可以通过构造函数传参)
      • 默认会参与 __repr__、__eq__、__hash__ 等自动生成的方法
      • 默认不可用 default_factory,只能用普通的默认值(如字符串、数字、布尔等不可变类型)
  • TLDR:
    • 简单字段可直接定义,不用 field
    • 需要更细致控制(如可变类型、参与方法、元数据等)时,应使用 field()

Python——contextlib包的使用


整体说明

  • contextlib 模块是 Python 标准库的一部分,提供了一系列简化上下文管理器实现的实用工具

@contextmanager 装饰器

  • @contextmanager 允许将生成器函数转换为上下文管理器,无需显式定义类

  • @contextmanager 核心逻辑通过 yield 分割为“进入上下文”和“退出上下文”两部分

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from contextlib import contextmanager

    @contextmanager
    def file_manager(file_path, mode):
    file = open(file_path, mode)
    yield file
    file.close()

    with file_manager('test.txt', 'w') as f:
    f.write('Hello, contextlib!')
    • 在这个例子中,yield 之前的代码 file = open(file_path, mode) 用于获取资源,yield 之后的代码 file.close() 用于释放资源
    • 注:yield 之后的语句在第二次调用函数时被调用(第一次调用函数返回 yield 的结果)

closing类

  • 对于只提供 close() 方法但未实现上下文协议的对象,closing 可确保其 close() 被调用

    1
    2
    3
    4
    5
    from contextlib import closing
    import urllib.request

    with closing(urllib.request.urlopen('https://www.example.com')) as response:
    html = response.read()
    • 上述代码等价于手动使用try-finally块来调用close()方法,但closing类使代码更加简洁

suppress上下文管理器

  • 在需要忽略某些非关键异常时,suppress可替代繁琐的try-except

    1
    2
    3
    4
    5
    6
    from contextlib import suppress

    with suppress(FileNotFoundError):
    with open('nonexistent_file.txt', 'r') as f:
    content = f.read()
    print("程序继续执行,不抛出异常")
  • suppress还可以同时抑制多个异常,如with suppress(FileNotFoundError, PermissionError):


nullcontext上下文管理器

  • 当代码需要根据条件决定是否使用上下文管理器时,nullcontext提供“空上下文”,避免重复代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from contextlib import nullcontext

    def process_data(data, use_file=True):
    context = open('output.txt', 'w') if use_file else nullcontext()
    with context as f:
    if f:
    f.write(str(data))
    else:
    print(f"直接输出:{data}")

    process_data("临时数据", use_file=False)
    process_data("重要数据", use_file=True)

ExitStack类

  • contextlib 支持通过 with 语句嵌套或使用 ExitStack 批量管理多个上下文,尤其适合动态生成的资源列表

    1
    2
    3
    4
    5
    6
    7
    from contextlib import ExitStack

    file_names = ('file1.txt', 'file2.txt', 'file3.txt')
    with ExitStack() as stack:
    files = [stack.enter_context(open(name, 'w')) for name in file_names]
    for f in files:
    f.write('示例内容')
    • 在这个例子中,ExitStack 会自动管理多个文件的上下文,确保在退出 with 块时所有文件都被正确关闭。

Ubuntu——显卡驱动安装


整体说明

  • Ubuntu 手动安装英伟达显卡比较麻烦,还涉及到 gcc 等各种安装
  • 在安装成功后还容易出现系统重启无法进入等问题
  • 本文特意强调如何使用简单的流程实现 Ubuntu 安装

(推荐)Ubuntu 安装 NVIDIA 显卡驱动安装

  • 如果之前安装过英伟达显卡驱动,请先删除

    1
    sudo apt-get purge nvidia*
  • 建议使用命令行工具安装系统推荐的 NVIDIA 驱动版本(自动推荐)

    1
    2
    3
    4
    5
    # 确保驱动列表是最新的
    sudo apt-get update

    # 安装推荐的驱动
    sudo ubuntu-drivers autoinstall
    • 亲测最快最方便,使用官网下载安装的方式容易导致系统无法启动!

Ubuntu——安装Ubuntu后要首先要做的事情

原生的Ubuntu有许多没用的软件和包,也有很多我们需要但是没装的软件和包,论文将介绍安装Ubuntu后一般来说需要对系统做哪些自定义的修改,可按照需要选择适合的软件


删除几乎不用的软件

  • 以下软件均可删除

    1
    2
    3
    4
    sudo apt-get remove libreoffice-common
    sudo apt-get remove unity-webapps-common
    sudo apt-get remove thunderbird totem rhythmbox empathy brasero simple-scan gnome-mahjongg aisleriot gnome-mines cheese transmission-common gnome-orca webbrowser-app gnome-sudoku landscape-client-ui-install
    sudo apt-get remove onboard deja-dup
  • 删除的软件参考自其他博客:安装Ubuntu 21.04后要做的事


安装Vim

  • 命令:
    1
    sudo apt-get install vim

安装 Google Chrome

  • 命令:
    1
    2
    3
    4
    5
    6
    7
    8
    cd ~/Downloads
    wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    sudo apt-get install libappindicator1 libindicator7
    sudo dpkg -i google-chrome-stable_current_amd64.deb
    sudo apt-get -f install

    # 运行chrome
    google-chrome

安装 Oracle Java

  • 命令:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    sudo add-apt-repository ppa:webupd8team/java  
    sudo apt-get update
    sudo apt-get install oracle-java8-installer

    # 删除残留
    sudo rm /usr/share/upstart/sessions/jayatana.conf

    # 测试安装成果
    java -version
    # 如果第一行是版本号则成功

安装经典菜单指示器

  • ClassicMenu Indicator, 用于代替Ubuntu自带的应用检索器
    1
    2
    3
    sudo add-apt-repository ppa:diesch/testing
    sudo apt-get update
    sudo apt-get install classicmenu-indicator

安装系统指示器 SysPeek

  • 查看系统管理,包括内存和CPU消耗等
    1
    2
    3
    sudo add-apt-repository ppa:nilarimogard/webupd8  
    sudo apt-get update
    sudo apt-get install syspeek

安装 Git

  • 命令:
    1
    sudo apt-get install git

安装 unrar

  • 命令:
    1
    2
    3
    4
    sudo apt-get install unrar

    # 使用命令
    unrar x test.rar

安装 flux 的 gui 版本 fluxgui

  • 脚本:
    1
    2
    3
    sudo add-apt-repository ppa:nathan-renniewaldock/flux
    sudo apt-get update
    sudo apt-get install fluxgui

安装网易云音乐

Note: 新版本1.1.0有问题,所以选择1.0.0版本
网易云1.0.0版本下载地址


安装Remmina

  • 一款开源的优雅的远程桌面GUI客户端
    1
    2
    3
    sudo apt-add-repository ppa:remmina-ppa-team/remmina-next
    sudo apt-get update
    sudo apt-get install remmina remmina-plugin-rdp libfreerdp-plugins-standard

如有问题参考Remmina安装链接


安装词典 GoldenDict

  • 一款崇尚自定义的词典

安装

  • 命令:
    1
    2
    3
    4
    # 安装词典
    sudo apt-get install goldendict
    # 安装En-En在线词库【可选】
    sudo apt-get install goldendict-wordnet

配置

  • 配置在线有道词典
    • Edit->Dictionaries->Websites->Add
    • Name: Youdao
    • Address: http://dict.youdao.com/search?q=%GDWORD%&ue=utf8
    • Enabled: Checked
    • ->Apply->OK
  • 配置 Bing 在线词典
    • 参考在线有道词典的配置
    • Name: Bing
    • Address: https://cn.bing.com/dict/search?q=%GDWORD%
  • 配置离线词典
    • 下载需要的词典: http://download.huzheng.org/zh_CN/
    • 解压
    • 将解压后的文件目录添加到字典中:
      • Edit->Dictionaries->Files->Add
      • 选中刚才的文件目录
      • ->Apply->OK
  • 开启划词翻译
    • 在 GoldenDict 主页点击小笔即可

安装 Shadowsocks

安装 Shadowsocksy 有两种方式,分别为命令行和Gui版本, 两种方式安装后都需要设置浏览器才能使用VPN

命令行版本安装

  • 安装命令:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 安装
    sudo apt-get update
    sudo apt-get install python-pip
    # 下面这行有时候可选
    sudo apt-get install python-setuptools m2crypto
    pip install shadowsocks
    sudo gedit /etc/shadowsocks.json

    # 配置文件
    {
    "server":"xx.xx.xx.xx",
    "server_port":xxxx,
    "local_address": "127.0.0.1",
    "local_port":1080,
    "password":"xxxxxxxx",
    "timeout":600,
    "method":"xxx",
    "fast_open": true,
    "workers": 1
    }

    # 运行
    sslocal -c /etc/shadowsocks.json

Shadowsocks Gui 版本安装

  • 从网站下载 release 版本: shadowsocks-qt5 GitHub

  • 添加运行权限:

    1
    chmod +x xxx
  • 现在双击即可运行

  • 在打开的 Gui 中导入 json 即可

  • 如果想把 Shadowsocks 添加到启动器,参考Utuntu——添加自定义的软件到启动器

浏览器配置

  • 以上两种版本安装配置后,想要用浏览器科学上网还需要配置浏览器
Firefox
>Menu
-> Preferences
-> Network Proxy Setting
-> Manual proxy configuration
-> Socks Host: 127.0.0.1:1080
-> SOCKS v5
Chrome
  • 分两种方式,一种是不用安装任何插件,在命令行启动时制定代理即可,一种需要安装SwitchyOmega插件

  • 直接使用命令行

    1
    2
    # 不用安装任何代理
    google-chrome --proxy-server=socks5://127.0.0.1:1080
  • 安装代理: Switchy Omega

  • 安装SwitchyOmega插件时需要科学上网,所以可以先用上面的命令行启动,然后使用Chrome安装SwitchyOmega插件*

  • 配置方面参考SwitchyOmega官网(自动切换模式配置方便): SwitchyOmega官网/Settings*


安装wps和字体

  • 安装libpng

    • 网站里面有多个源,可随意选一个下载
    • 也可使用命令直接下载
      1
      wget http://ftp.cn.debian.org/debian/pool/main/libp/libpng/libpng12-0_1.2.49-1+deb7u2_amd64.deb
  • 安装wps-office

  • 安装字体wps-office-fonts_1.0_all.deb


为Ubuntu添加Windows的字体

这个字体可以保证终端等能使用中文,同时能保证wps能正常使用

  • 从 Windows 系统的 Windows/Fonts/ 拷贝所有文件,大小大概500M+
  • 在 Ubuntu 上新建文件夹,建议放到 /usr/share/fonts/ 下面, 比如 /usr/share/fonts/win-fonts/
  • 将字体文件拷贝到新建立的文件夹下面
  • 执行下面命令
    1
    2
    3
    4
    cd /usr/share/fonts/
    sudo mkfontdir
    sudo mkfontscale
    sudo fc-cache

设置截图快捷键

在Windows和Mac下使用QQ快捷键截图习惯了后,到了Ubuntu会不习惯, 因为Ubuntu默认截图是保存到Pictures文件夹的,不是粘贴板
这里给出一种利用Ubuntu自带的软件gnome-screenshot实现QQ快捷键相同功能的方法

  • 添加快捷键Ctrl+Alt+A绑定到命令gnome-screenshot -ac
  • gnome-screenshot -c是全屏截图,也可以设置成自己喜欢的快捷键
  • gnome-screenshot参数简介
    • -c, 保存到剪贴板
    • -w, 截取当前窗口
    • -a, 选择一个区域
    • 如果没有任何参数默认是将当前全屏截图,并保存到Pictures文件夹
    • 更多gnome-screenshot参数参考gnome-screenshot -h

安装 sublime

  • 添加安装源

    1
    2
    3
    wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add -
    sudo apt-get install apt-transport-https
    echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list
  • 更新库

    1
    sudo apt-get update
  • 用apt-get命令安装sublime

    1
    sudo apt-get install sublime-text
  • Sublime中输入中文

    1
    2
    3
    4
    5
    git clone --depth=1 https://github.com/lyfeyaj/sublime-text-imfix.git
    cd sublime-text-imfix
    ./sublime-imfix
    cd ..
    rm -rf sublime-text-imfix
    • 说明: 如果不执行这一步,Sublime 在 Ubuntu 中是不能直接输入中文的
  • 添加一点说明

    • 如果上面的方法不能安装最新版或者安装失败,可以尝试自己下载软件发行版并自己添加 sublime 到启动器,添加自定义程序到启动器的方法可参考 Utuntu——添加自定义的软件到启动器

关闭 sublime 的自动更新

  • Settings 中添加 "update_check": false,

Ubuntu——添加自定义的软件到启动器

日常使用Ubuntu时,某些自己编写的脚本(程序)或者下载的程序不能从启动器搜索到


问题描述

  • 自己编写的脚本
  • 自己编写的程序
  • 网上自己下载的程序(不是通过apt-get或者APPStore安装)

解决问题

编写程序启动脚本

如果需要运行的就是脚本这一步可以不用

  • 编写shell脚本,脚本内容为启动运行程序
    • 涉及到程序的名称这里应该用绝对路径
  • 脚本可以放到任意地方,一般和当前程序在一个文件夹下即可

添加脚本执行权限

1
chmod +x exmaple.sh

新建启动

  • 新建文件到指定文件夹

    1
    2
    cd /usr/share/applications
    sudo gedit example.desktop
  • 编辑文件如下格式

    • Name是程序搜索时会出现的名字
    • Exec是执行脚本路径,必须有执行权限,否则在启动器中仍然搜索不到该程序
    • Icon是软件的图标,这里可以任意自定义图标,从网上下载或者自己生成均可
      1
      2
      3
      4
      5
      6
      7
      8
      [Desktop Entry]
      Version=1.0
      Name=Example
      Exec=/home/username/example.sh
      Terminal=false
      Icon=/home/username/example.png
      Type=Application
      Categories=Development

测试

  • 按键: Win键
  • 输入Example
  • 如果出现图标和名字对应的程序,说明成功
  • 如果不成功,复查以下问题
    • 启动脚本路径是否正确且为绝对路径
    • 执行权限是否已经成功设置
    • Name是否设置正确
1…585960…64
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