Python Base(one)

Python编程的基本概念

1-1 Python程序构成

欢迎来到 Python 的核心!对于初学者来说,理解 Python 的程序结构就像学习建筑的框架。虽然 Python 看起来很像英语,但它有一套严格的“组件布局”规则。

为了让你看清全貌,我们来看一个基础但完整的“薪资计算器” Demo。


1. 入门级 Demo:薪资核算小程序

这个程序虽然简单,但包含了 Python 程序的所有核心组成部分。

# -*- coding: utf-8 -*-
"""
程序名称:简易薪资计算器
功能:根据工时计算周薪,并判断等级。
作者:edward
"""

import math  # 1. 导入模块

TAX_RATE = 0.2  # 2. 全局变量(常量)

def calculate_pay(hours, rate): # 3. 函数定义
    """计算扣税后的实际薪资"""
    gross_pay = hours * rate
    net_pay = gross_pay * (1 - TAX_RATE)
    return round(net_pay, 2)

def main(): # 4. 主逻辑函数
    print("--- 欢迎使用薪资系统 ---")
    
    # 5. 输入与数据转换
    try:
        user_name = input("请输入员工姓名: ")
        work_hours = float(input("请输入本周工时: "))
        hourly_rate = float(input("请输入时薪: "))
        
        # 6. 逻辑调用
        final_salary = calculate_pay(work_hours, hourly_rate)
        
        # 7. 条件判断
        if final_salary > 1000:
            level = "高级"
        else:
            level = "标准"
            
        # 8. 格式化输出
        print(f"\n员工: {user_name}")
        print(f"实际到手薪资 (${level}): {final_salary}")
        
    except ValueError:
        print("错误:请输入有效的数字!")

# 9. 入口判断
if __name__ == "__main__":
    main()

2. 详细拆解:Python 程序的 9 个组成部分

① 文档注释 (Docstrings & Comments)

  • # 开头的是单行注释,解释代码意图。
  • """ ... """文档字符串。放在文件开头是程序说明,放在函数内部是功能说明。
  • 全栈视角:在团队协作中,好的注释能节省 80% 的沟通成本。

② 导入模块 (Imports)

  • 使用 import 引入 Python 自带的工具箱(标准库)或第三方库。
  • Python 的强大在于其丰富的“插件”,你需要什么功能,通常先找对应的模块。

③ 全局变量与常量 (Global Variables/Constants)

  • 在 Python 中,通常用全大写字母表示常量(虽然 Python 语法上不强制禁止修改它,但这是开发者之间的约定)。

④ 函数定义 (Functions)

  • 关键字:使用 def 定义。
  • 结构def 函数名(参数):
  • 返回值:使用 return 返回结果。

⑤ 缩进 (Indentation) —— 最重要的一点!

  • 在 Java 或 C 中,我们用 {}。在 Python 中,我们使用缩进(通常是 4 个空格)。
  • 注意:同一个代码块的缩进必须完全一致,否则由于 Python 的解释特性,程序会直接报错。

⑥ 输入与输出 (Input & Output)

  • input():从控制台获取用户输入,返回的是字符串(String)。
  • print():将结果输出到控制台。
  • f-string:如 f"姓名: {name}",这是 Python 3.6+ 最推荐的字符串格式化方式,非常简洁。

⑦ 数据类型转换 (Type Casting)

  • float()int()str():由于 input() 得到的是文本,如果要进行数学计算,必须强制转换类型。

⑧ 异常处理 (Exception Handling)

  • try...except:为了防止用户乱输入(比如在工时里输入“打工人”而不是数字)导致程序崩溃,我们要用异常处理来捕捉错误。

⑨ 程序入口 (if __name__ == "__main__":)

  • 这是 Python 程序的“启动开关”。
  • 它确保了当你直接运行这个文件时,main() 函数才会执行。如果你把这个文件当做插件导入到别的程序里,它就不会自动运行,避免了干扰。

3.给初学者的特别提醒:

  1. 冒号 (😃 的存在:你会发现 ifdeffor 之后都有个冒号,这代表“下面是一段缩进的代码块”,千万别漏掉。
  2. 变量不需要定义类型:你不需要写 int a = 1,直接写 a = 1。Python 会自动识别。
  3. 空行:虽然 Python 不强制,但在函数之间留 2 行空格,在逻辑块之间留 1 行空格,会让你的代码看起来像出自大厂专家之手。

1-2 Python之对象和内存

在 Python 的世界里,有一句名言:“万物皆对象 (Everything is an object)”

  1. Python中,一切皆对象。

  2. 每个对象由:标识(identity)、类型(type)、value(值)组成


  3. 标识用于唯一标识对象,通常对应于对象在计算机内存中的地址。使用内置函数id(obj)可返回对象obj的标识。

  4. 类型用于表示对象存储的“数据”的类型。类型可以限制对象的取值范围以及可执行的操作。可以使用type(obj)获得对象的所属类型。

  5. 值表示对象所存储的数据的信息。使用print(obj)可以直接打印出值。

对象的本质就是:

一个内存块,拥有特定的值,支持特定类型的相关操作


1. 核心概念:变量是“标签”,不是“盒子”

在 C++ 或 Java 等语言中,变量像是一个盒子,你把值放进盒子里。
在 Python 中,变量更像是贴在对象上的“标签”(引用/指针)。对象存在于内存中,变量只是指向它的名字。

示例代码:

a = [1, 2, 3]
b = a
b.append(4)

print(a)  # 输出 [1, 2, 3, 4]

解释:这里并没有两个列表。ab 这两个“标签”都贴在了内存中同一个列表对象上。修改 ba 也会同步变化。


2. 一个 Python 对象的内部结构

每个 Python 对象在内存中被创建时,至少包含三个核心部分:

  1. 标识 (Identity / ID):对象的唯一行政代号(可以理解为内存地址)。使用 id(obj) 查看。
  2. 类型 (Type):告诉 Python 这个对象能做什么。使用 type(obj) 查看。
  3. 值 (Value):对象存储的实际数据。
x = 100
print(id(x))   # 内存中的地址,如 1407312345678
print(type(x)) # <class 'int'>
print(x)       # 100

a=3
print(a)
print(id(a))
print(type(a))
b='我爱你'
print(b)
print(id(b))
print(type(b))

image-20260129162511257

3. 不可变对象 vs 可变对象 (核心坑点)

这是全栈开发中最常遇到 Bug 的地方。

  • 不可变对象 (Immutable):一旦创建,值就不能更改。如果要改,Python 会创建一个新对象
    • 代表:int, float, str, tuple, bool
  • 可变对象 (Mutable):可以直接在原地修改对象的内容。
    • 代表:list, dict, set

实验对比:

# 不可变对象测试
s = "hello"
old_id = id(s)
s = s + " world" 
print(id(s) == old_id) # False!s 现在指向了一个全新的字符串对象

# 可变对象测试
lst = [1]
old_id = id(lst)
lst.append(2)
print(id(lst) == old_id) # True!lst 还在原来的位置,只是内容变了

4. 内存管理机制:Python 是如何“扫地”的?

作为解释型语言,Python 自动管理内存,主要靠两套机制:

A. 引用计数 (Reference Counting) —— 主要手段

每个对象都有一个计数器,记录有多少个变量指向它。

  • b = a 时,引用计数 +1。
  • del a 时,引用计数 -1。
  • 当引用计数降为 0 时: 对象会被立即回收,内存释放。

B. 垃圾回收 (Garbage Collection) —— 辅助手段

有时会出现“循环引用”(A 引用 B,B 引用 A,但没人用它们了)。
Python 的垃圾回收器会定期扫描,发现并清理这种“孤岛”内存,防止内存泄漏。


5. 小整数池与字符串驻留 (进阶优化)

为了性能,Python 做了一些“耍赖”的技巧:

  • 小整数池:Python 启动时会预先创建 -5 到 256 之间的整数对象。无论你写多少次 a=10, b=10,它们都指向同一个内存地址。
  • 字符串驻留 (Interning):短的字符串有时也会被复用。
a = 10
b = 10
print(a is b) # True,因为 10 在小整数池里

x = 500
y = 500
print(x is b) # False(通常),因为 500 超出了预设范围,创建了两个独立对象

1-3 Python之引用

在Python中,变量也称为:对象的引用(reference)。变量存储的就是对象的地址。

变量通过地址引用了“对象”。

image-20211024121259143

变量位于:栈内存(压栈出栈等细节,后续再介绍)。

对象位于:堆内存。

如下源代码对应的内存图:

a=3
b="我爱你"

image-20211024104544493

⚠️Python是动态类型语言

变量不需要显式声明类型。根据变量引用的对象,Python解释器自动确定数据类型

你的直觉非常敏锐!作为一个全栈开发人员,如果你有 C、C++ 或 Java 的背景,这个结论可能会让你感到既惊讶又合理:

是的,在 CPython(最常用的 Python 实现)中,所有的对象都存储在“堆”(Heap)上。

为了让你透彻理解这一点,我们需要拆解一下这句话背后的深层含义。


1. 为什么“万物皆对象”?

在 C 语言中,一个 int 变量只占用 4 个字节,直接存放在栈(Stack)里。
但在 Python 中,即使是最简单的 a = 1,Python 也会在内存中创建一个完整的 PyObject 结构体

这个结构体至少包含:

  1. 引用计数 (ob_refcnt):用于垃圾回收。
  2. 类型指针 (ob_type):指向 int 类型对象的描述。
  3. 值 (ob_size / ob_digit):存储实际的数字。

因为每个对象都有这些额外的信息,它们的大小是不固定的,所以必须存放在私有堆(Private Heap)中以便动态管理。


2. 栈(Stack)里存的是什么?

既然对象都在堆里,那栈里还有东西吗?有,但栈里只存“引用”和“执行上下文”

当我们执行一个函数时,Python 会在栈上创建一个 “栈帧”(Stack Frame)。栈帧里包含:

  • 变量名(也就是引用/指针):这些名字(如 x, y, my_list)存放在栈帧里,但它们存储的是堆中对象的内存地址
  • 执行状态:当前执行到了哪一行代码。

形象比喻:

  • 堆(Heap):像是超市的货架,所有的货物(对象:数字、字符串、列表)都堆在这里。
  • 栈(Stack):像是你手里的购物清单(变量名)。清单上只写着“苹果在 A3 货架”、“牛奶在 B1 货架”。你手里拿的是位置信息,而不是实物。

3. 这个设计对性能的影响(全栈开发者的必知点)

为什么 Python 通常比 C 或 Java 慢?“全员堆对象”是原因之一:

  1. 内存开销:在 C 语言中存 1000 个整数几乎不占额外空间;在 Python 中,1000 个整数就是 1000 个 PyObject,每个都要几十个字节。
  2. 寻址开销:每次你要计算 a + b,Python 必须先去栈里找 a 的地址,再去堆里访问那个地址,读取里面的值。这比直接从栈里取数要慢。
  3. 垃圾回收压力:因为所有东西都在堆里,引用计数和垃圾回收器必须时刻盯着堆内存,增加了 CPU 负担。

4. 极端例子:函数和类也在堆里

在 Python 中,def 定义的函数class 定义的本身也是对象。

def say_hi():
    print("Hi")

# say_hi 这个名字也是一个标签,指向堆里的一个“函数对象”
func_ptr = say_hi 
print(id(say_hi)) # 获取这个函数在堆里的地址

这意味着你可以像传递数字一样传递函数(这也就是为什么 Python 支持高阶函数和装饰器的根本原因)。


5. 总结:你的理解是正确的

  • 所有的值(对象)都在堆中。
  • 变量名仅仅是栈里的一个指针。
  • 这种设计牺牲了性能,但换取了极大的灵活性(动态类型、反射、元编程等)。

1-4 Python基础之标识符

在 Python 的编程世界里,标识符(Identifier) 就是由于程序员定义的、用来指代变量、函数、类、模块或其他对象的“名字”。

以下是关于 Python 标识符的详细技术文档:

1. 什么是标识符

简单来说,标识符就是起名字。无论你是定义一个变量 x = 10,还是定义一个函数 def login():,其中的 xlogin 就是标识符。


2. 强制性命名规则

Python 解释器对标识符有严格的语法要求,不符合以下规则的代码将无法运行(报 SyntaxError):

  • 字符组成:可以由 字母 (A-Z, a-z)、数字 (0-9) 和 下划线 (_) 组成。
  • 数字开头限制:标识符不能以数字开头
    • user1 (✅ 合法)
    • 1user (❌ 非法)
  • 大小写敏感 (Case Sensitive):Python 严格区分大小写。
    • usernameUserName 是两个完全不同的变量。
  • 特殊字符限制:不能包含 @$% 等特殊字符。
  • 禁止使用关键字:不能使用 Python 预留的关键字(如 if, while, class 等)。

3. Python 关键字 (Reserved Keywords)

你可以通过以下代码查看当前版本 Python 的所有关键字:

import keyword
print(keyword.kwlist)

常见关键字举例:
False, None, True, and, as, assert, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield


4. 行业约定的命名规范 (PEP 8)

虽然语法允许你乱起名字,但作为全栈开发人员,遵循 PEP 8(Python 官方代码风格指南)是专业素质的体现。

类型 命名方式 示例
项目/包名 全小写,尽量简短 my_project
模块名 全小写,下划线分隔 auth_service.py
变量/函数名 蛇形命名法 (snake_case) user_id, calculate_total()
类名 大驼峰命名法 (PascalCase) UserProfile, DatabaseClient
常量 全大写,下划线分隔 MAX_RETRIES, API_KEY

5. 下划线的特殊含义

在 Python 中,标识符前后的下划线往往带有特定含义,这与内存管理和封装有关:

  • 单下划线开头 (_variable):暗示这是一个“私有变量”,不希望被外部直接访问(虽然语法上仍可访问,这是一种约定)。
  • 双下划线开头 (__variable):触发“名称修饰”,在类中用于更强的私有化。
  • 双下划线开头和结尾 (__init__)魔法方法 (Magic Methods)。这些是 Python 内置的特殊方法,开发者不应当随便起类似的名字。
  • 单下划线 (_)
    • 在解释器交互模式下,表示最后一个表达式的结果。
    • 在代码中,常作为丢弃变量(不需要使用的临时变量)。
    for _ in range(5):
        print("Hello") # 只循环5次,不关心循环变量的具体值
    

6. 与 Web 全栈开发的对比总结

如果你有前端经验,可以对比记忆:

  • JavaScript:习惯用小驼峰 (camelCase),如 userId
  • Python:习惯用蛇形 (snake_case),如 user_id
  • HTML/CSS:习惯用中划线 (kebab-case),如 user-profile

核心提示:在编写 Python 后端 API 时,虽然 JSON 传输可能使用 camelCase,但在 Python 代码内部逻辑中,应坚持使用 snake_case 以保持风格地道。


1-5 Python基础之变量的声明、初始化与垃圾回收机制


1. 变量的声明与初始化 (Declaration & Initialization)

在 Python 中,声明与初始化是同时发生的。你不需要(也不能)提前声明变量的类型。

1.1 动态类型特性

Python 是动态强类型语言:

  • 动态:变量不需要指定类型,类型在运行时根据对象确定。
  • 强类型:除非进行显式转换,否则不同类型之间不会自动发生“隐式转换”(例如字符串和数字不会自动相加)。

1.2 语法实现

# 声明并初始化
user_id = 101       # Python 在堆中创建一个 int 对象,并让 user_id 指向它
user_name = "Alice" # 创建一个 str 对象

# 链式赋值
a = b = c = 1 

# 解包赋值 (Multiple Assignment)
x, y = 5, 10

1.3 底层原理

当你执行 a = 1000 时,Python 内部经历了三个步骤:

  1. 创建对象:在内存(堆)中创建一个对象,存储值 1000
  2. 创建变量:在当前作用域(栈/命名空间)中创建变量名 a
  3. 连接(绑定):将变量名 a 存储的地址指向对象的内存地址。

2. 垃圾回收机制 (Garbage Collection, GC)

Python 不需要手动释放内存(如 C 语言的 free)。它主要依靠 “引用计数” 机制,并辅助以 “标记-清除”“分代回收”

2.1 引用计数 (Reference Counting) —— 核心机制

每个对象内部都有一个 ob_refcnt 字段,记录当前有多少个变量指向它。

  • 计数增加
    • 变量赋值:b = a
    • 作为参数传递给函数:func(a)
    • 放入容器中:list1 = [a]
  • 计数减少
    • 变量被显式销毁:del a
    • 变量被重新赋值:a = 200
    • 离开作用域(如函数执行完毕,局部变量销毁)

当引用计数降为 0 时,对象占用的内存会被立即回收。

import sys

x = [1, 2, 3]
print(sys.getrefcount(x)) # 查看引用计数(结果通常比预期多1,因为函数调用本身也持有引用)

2.2 循环引用问题 (Circular References)

引用计数有一个致命缺陷:无法处理循环引用

a = []
b = []
a.append(b)
b.append(a)
del a
del b
# 此时 a 和 b 的计数仍为 1,但外部已无法访问,造成内存泄漏。

2.3 标记-清除 (Mark and Sweep)

为了解决循环引用,Python 会定期扫描内存:

  1. 标记:从根对象(全局变量等)出发,遍历所有可达对象并打上标记。
  2. 清除:遍历堆内存,如果某个对象没有标记且存在循环引用,则强制回收。

2.4 分代回收 (Generational Collection) —— 效率优化

这是基于一种经验假说:新创建的对象往往死得快,而老的对象存活时间更长。

Python 将内存中的对象分为三代:

  • 第 0 代:新创建的对象。当第 0 代对象达到一定阈值时,触发 GC。
  • 第 1 代:在一次 GC 中幸存下来的第 0 代对象。
  • 第 2 代:在多次 GC 中幸存下来的老旧对象。

规则:GC 对第 0 代扫描频率最高,第 2 代扫描频率最低。这样可以显著减少垃圾回收时的 CPU 消耗。


3. 全栈开发的避坑总结

关注点 建议
局部变量 尽量使用局部变量,函数结束后会自动触发引用计数减 1。
大数据处理 处理几 GB 的文件时,及时使用 del variable 手动解除引用。
可变默认参数 def func(lst=[]) 会导致 lst 对象常驻在第 2 代内存中,造成意外逻辑和内存占用。
监控工具 复杂应用可使用 import gc 模块手动触发 gc.collect() 或监控回收状态。

1-6 Python基础之常量

在 Web 全栈开发中,常量通常用于存储配置信息(如 API 密钥、数据库连接字符串、分页大小等)。与 JavaScript 的 const 或 Java 的 final 不同,Python 并没有语法层面上的“真常量”


1. 核心概念:约定优于配置

在 Python 中,常量是通过命名约定(Naming Convention)来实现的。

  • 语法本质:Python 的变量即使大写,在运行时依然可以被修改。
  • 文化契约:Python 社区遵循“成年人原则”(We are all consenting adults),即:“既然你把这个变量写成了全大写,我就默认为你不希望我去改动它。”

2. 命名规范 (PEP 8)

根据 Python 官方风格指南 PEP 8:

  • 格式:全部大写字母,单词之间用下划线 _ 分隔。
  • 位置:通常定义在模块(文件)的顶部,或专门的 config.py 文件中。

示例:

# 基础常量定义
API_TIMEOUT = 30
MAX_CONNECTIONS = 100
DEFAULT_THEME_COLOR = "#3498db"

# 即使你之后写了 API_TIMEOUT = 10,代码能运行,但 IDE 会发出警告,且同事会想打你。

3. 进阶:如何实现“强约束”常量?

作为全栈开发人员,如果你希望代码更健壮,防止意外修改,可以采用以下几种方式:

3.1 使用 typing.Final (Python 3.10+)

这是类型提示(Type Hinting)层面的约束。虽然它不能阻止修改,但 Mypy 等静态检查工具和主流 IDE(如 PyCharm/VS Code)会直接报错。

from typing import Final

DATABASE_URL: Final = "postgresql://localhost:5432/mydb"

# 如果你尝试修改:
DATABASE_URL = "mysql://something_else" 
# IDE 会显示错误:Cannot assign to final name "DATABASE_URL"

3.2 使用类与 @property (只读属性)

如果你想在运行时严格禁止修改,可以利用类和属性装饰器:

class _Config:
    @property
    def VERSION(self):
        return "1.0.0"

settings = _Config()

# 尝试操作:
print(settings.VERSION) # 1.0.0
settings.VERSION = "2.0.0" # 报错:AttributeError: can't set attribute

4. 全栈开发中的最佳实践

4.1 抽离配置文件

在 Web 框架(如 Django, Flask, FastAPI)中,通常将常量统一放在一个独立文件中。

# config.py
import os

DEBUG = os.getenv("DEBUG", "False") == "True"
DB_PASSWORD = os.getenv("DB_PASSWORD", "secret_pass")

4.2 使用枚举 (Enum)

对于“分类”性质的常量(如 HTTP 状态码、用户角色、订单状态),推荐使用内置的 enum 模块。

from enum import Enum

class UserRole(Enum):
    ADMIN = 1
    EDITOR = 2
    GUEST = 3

# 使用时更具语义化
current_role = UserRole.ADMIN
if current_role == UserRole.ADMIN:
    pass

5. 对比总结

特性 Python 常量 JavaScript const
强制性 弱(依靠约定,除非用特殊技巧) 强(运行时直接报错)
命名风格 SNAKE_CASE_ALL_CAPS camelCaseUPPER_CASE
修改后果 逻辑混乱,破坏维护性 程序由于语法错误无法运行

1-8 Python基础之最基本内置数据类型

在 Python 中,“万物皆对象”。即使是最基础的数据类型,在内存中也是作为 PyObject 结构体存在于堆(Heap)中的。

作为全栈开发人员,了解这些类型不仅是为了写代码,更是为了理解它们与数据库(SQL)、前端(JavaScript)之间的数据映射关系。


1 类型分类总览

Python 的内置数据类型主要可以分为以下几大类:

分类 类型名称 (type) 例子 特点
数值型 int, float, complex 42, 3.14, 1+2j 不可变
布尔型 bool True, False int 的子类
字符串 str "Hello" 不可变 Unicode 序列
列表 list [1, 2, 2] 可变,有序序列
元组 tuple (1, 2, 2) 不可变,有序序列
集合 set {1, 2, 3} 可变,无序且唯一
字典 dict {"id": 1} 可变,键值对(Key-Value)
空值 NoneType None 表示“无”或“空”

2 数值型 (Numeric Types)

2.1 整数 (int)

  • 无限精度:Python 3 的 int 并不像 C 或 Java 那样有 32 位或 64 位的限制。只要内存足够,它可以表示任意大的整数。
  • 内存特性:对于较小的整数(-5 到 256),Python 内部会进行缓存(Integer Interning),以提高性能。

2.2 浮点数 (float)

  • 双精度:类似于 C 语言中的 double,遵循 IEEE 754 标准。
  • 注意:由于二进制浮点数的特性,0.1 + 0.2 不等于 0.3。在处理金融业务(如订单金额)时,建议使用 decimal 模块。

3. 布尔型 (Boolean Type)

  • 本质boolint 的子类。
  • 对应关系True == 1, False == 0
  • 布尔测试:在 Python 中,以下值被视为 “假” (Falsy)
    • None, False
    • 数值中的 0, 0.0
    • 空容器:"", [], (), {}, set()

4. 字符串 (String Type) —— Web 开发的核心

Python 3 的 strUnicode 序列

  • 不可变性 (Immutability):一旦创建,字符串的内容就不能修改。每次拼接字符串(如 s += "!")实际上是在堆中创建了一个全新的字符串对象。
  • 驻留机制 (Inlining/Interning):为了节省内存,短小且符合规则的字符串字面量会被重用内存地址。
s = "Python"
# s[0] = "p"  # ❌ 报错:TypeError
new_s = "p" + s[1:] # ✅ 正确方案:创建一个新对象

5. 序列类型(列表与元组)

  • 列表 (list):就像 JavaScript 的 Array。它是动态数组,支持 O(1) 的随机访问。
  • 元组 (tuple)不可变的列表。通常用于存储结构化数据(如数据库的一行记录 (id, name, email)),由于其不可变性,元组的内存开销比列表小。

6. 全栈视角:类型映射表

当你作为一个全栈开发人员进行前后端交互时,类型的对应关系如下:

Python 类型 JSON 类型 JavaScript 类型 SQL 类型 (常见)
int number Number / BigInt INT, BIGINT
float number Number FLOAT, DOUBLE
str string String VARCHAR, TEXT
bool boolean Boolean BOOLEAN / TINYINT
list array Array (通常通过中间表表示)
dict object Object JSON, JSONB
None null null NULL

7. 实用工具函数

在调试阶段,这两个函数是你了解对象“本质”的神器:

x = [1, 2, 3]

print(type(x)) # <class 'list'> - 查看对象类型
print(id(x))   # 140712345678 - 查看对象在堆中的内存地址
print(isinstance(x, list)) # True - 判断是否为指定类型

1-9 Python基础之整型

作为全栈开发人员,虽然我们在业务逻辑中大多使用十进制,但在处理底层协议、颜色值、加密算法或性能优化时,二进制八进制十六进制以及你提到的三进制会经常出现。


1. 常见的进制表示法

Python 内部原生支持以下四种进制的直接书写:

进制 英文 前缀 字符集 示例 (表示十进制 10)
二进制 Binary 0b0B 0-1 0b1010
八进制 Octal 0o0O 0-7 0o12
十进制 Decimal (无) 0-9 10
十六进制 Hexadecimal 0x0X 0-9, A-F 0xa

示例代码:

a = 0b1010  # 二进制
b = 0o12    # 八进制
c = 10      # 十进制
d = 0xa     # 十六进制

print(a == b == c == d)  # 输出: True

2. 关于“三进制” (Ternary)

Python 虽然没有像 0b 那样为三进制(Base-3)提供内置的字面量前缀,但我们可以通过内置函数进行转换和处理。

2.1 将三进制字符串转为十进制

使用 int(string, base) 函数。

# 将三进制字符串 "121" 转换为十进制
# 计算过程:1*(3^2) + 2*(3^1) + 1*(3^0) = 9 + 6 + 1 = 16
val = int("121", 3)
print(val)  # 输出: 16

2.2 将十进制转为三进制

Python 没有内置 ternary() 函数,但可以通过简单的递归或循环实现:

def to_ternary(n):
    if n == 0: return "0"
    res = ""
    while n > 0:
        res = str(n % 3) + res
        n //= 3
    return res

print(to_ternary(16))  # 输出: "121"

3. 进制转换内置函数

在日常 Web 开发(如权限控制、颜色转换)中,以下函数最为常用:

函数 功能 示例
bin(n) 将十进制转为二进制字符串 bin(10) -> '0b1010'
oct(n) 将十进制转为八进制字符串 oct(10) -> '0o12'
hex(n) 将十进制转为十六进制字符串 hex(255) -> '0xff'
int(s, base) 任意进制字符串转为十进制 int('ff', 16) -> 255

4. 全栈开发中的应用场景

4.1 前端:颜色值 (Hex)

在 CSS 中我们常用 #FFFFFF。在 Python 后端(如 Pillow 库处理图片)时,常需要转换:

# 提取 RGB
color = 0xFF5733
r = (color >> 16) & 0xFF
g = (color >> 8) & 0xFF
b = color & 0xFF
print(f"R:{r}, G:{g}, B:{b}") # R:255, G:87, B:51

4.2 Linux/后端:文件权限 (Octal)

在给文件设权限时,我们常说 777644,这其实是八进制。

import os
# 设置文件为只读 (八进制 0o444)
os.chmod('test.txt', 0o444)

4.3 状态位与权限管理 (Binary)

在复杂的 Web 系统中,常用二进制位(Bitmask)来存储用户权限。

READ = 0b001
WRITE = 0b010
EXEC  = 0b100

user_permission = READ | WRITE # 用户拥有读写权限 (0b011)

总结

  • 二进制 (0b)八进制 (0o)十六进制 (0x) 是 Python 的一等公民。
  • 三进制或任意进制可以通过 int(str, base) 进行解析。
  • 对全栈开发而言,十六进制(颜色、加密)和二进制(位运算、权限)的权重最高。

1-10 Python基础之Float

作为一名全栈Web开发人员,理解浮点数及其在Python中的处理逻辑,对于无论是处理后端接口的数值计算,还是前端数据的呈现都至关重要。

以下是关于 Python 浮点数的系统性讲解:


1. 基本知识 (Basic Knowledge)

浮点数(Floating-point numbers)在Python中用于表示带有小数点的数字,或者使用科学计数法表示的数字。

  • 定义方式
    直接写出带小数点的数字即可。

    x = 3.14
    y = -0.01
    z = 10.0  # 即使是整数,加了 .0 也会变成浮点数
    
  • 科学计数法
    使用 eE 表示 10 的幂。

    a = 1.2e3  # 等于 1.2 * 10^3 = 1200.0
    b = 1.2e-3 # 等于 1.2 * 10^-3 = 0.0012
    
  • 底层实现
    Python 的 float 类型通常对应于 C 语言中的 double(双精度浮点数),遵循 IEEE 754 标准。这意味着它占用 64 位内存(8字节)。

  • 关键陷阱:精度问题
    这是全栈开发中常遇到的坑(尤其是处理电商价格或金融计算时)。

    print(0.1 + 0.2 == 0.3)  # 输出 False
    print(0.1 + 0.2)         # 输出 0.30000000000000004
    

    原因:计算机内部使用二进制表示浮点数,某些十进制小数(如0.1)无法被精确表示为二进制,从而产生微小的舍入误差。
    全栈建议:涉及财务计算时,请务必使用 Python 的 decimal 模块。


2. 自动转换、强制转换与增强赋值运算符

① 自动类型转换 (Implicit Type Conversion)

在算术运算中,Python 会自动将“窄”类型转换为“宽”类型以防止精度丢失。

  • 整数与浮点数运算
    只要运算中有一个操作数是浮点数,结果就是浮点数。

    a = 10 + 3.0   # 结果:13.0 (float)
    b = 5 * 2.0    # 结果:10.0 (float)
    
  • 除法运算
    在 Python 3 中,使用 / 运算符的结果始终是浮点数,即使能整除。

    print(10 / 2)  # 输出 5.0
    

② 强制类型转换 (Explicit Type Conversion / Casting)

使用内置函数手动转换数据类型。

  • 转为浮点数 float()

    float(10)      # 10.0
    float("3.14")  # 3.14 (字符串转浮点数,常用于解析 API 数据)
    
  • 浮点数转整数 int()
    注意int() 会直接截断小数部分(向零取整),而不是四舍五入。

    int(3.9)       # 3
    int(-3.9)      # -3
    
  • 四舍五入 round()
    如果需要精确控制小数位数。

    round(3.567, 2) # 3.57
    

③ 增强赋值运算符 (Augmented Assignment Operators)

增强赋值运算符(如 +=, -=, *=, /=)同样遵循自动转换规则。

运算符 例子 等价
+= a += 2 a = a + 2
-= a -= 2 a = a-2
*= a *= 2 a = a * 2
/= a /= 2 a = a / 2
//= a //= 2 a = a//2
**= a **= 2 a = a**2
%= a %= 2 a = a % 2
  • 语法x op= y 等价于 x = x op y
  • 示例与转换逻辑
    score = 100      # 此时是 int
    score += 5.5     # 等价于 score = 100 + 5.5
    print(score)     # 输出 105.5,score 自动转为了 float
    
    count = 10
    count /= 2       # 即使能整除,/= 也会使 count 变为 float
    print(count)     # 输出 5.0
    

⚠️注意:

  1. “+=”中间不能加空格!

  2. 结合的是右侧整个表达式:

    y *= x+2 # 相当于:y = y*(x+2)    而不是:y = y*x+2
    

1-11 Python基础之时间的表示

在 Web 开发中,时间处理是及其核心的一环。无论是数据库的 created_at 字段、前端展示的倒计时,还是 API 的缓存失效时间,都离不开对时间的精确掌控。

以下是关于 Python 时间表示的基础知识:


1. 时间的表示:Unix 时间戳与精度

在计算机科学中,时间通常不是以“年月日”存储的,而是以一个连续的数字。

① Unix 时间戳 (Unix Timestamp)

  • 定义:指从 1970年1月1日 00:00:00 UTC(协调世界时)开始所经过的秒数。这被称为“Unix 纪元(Epoch)”。
  • 特点:它是一个随时间推移而增大的实数,不受时区影响,全球统一。
  • Python 获取方式
    import time
    print(time.time())  # 输出类似于:1715836800.123456
    

② 毫秒与微秒 (Milliseconds & Microseconds)

Python 的 time.time() 返回的是一个浮点数,小数部分代表了比秒更小的单位:

  • 1 秒 (Second)
  • 1 毫秒 (Millisecond, ms) = $10^{-3}$ 秒(常用于 Web 前端 JS 中的 Date.now()
  • 1 微秒 (Microsecond, μs) = $10^{-6}$ 秒(计算机底层及高频交易常用)
  • 1 纳秒 (Nanosecond, ns) = $10^{-9}$ 秒(Python 3.7+ 通过 time.time_ns() 获取整数纳秒)

全栈开发注意

  • Python 的时间戳通常以为单位(浮点数)。
  • JavaScriptnew Date().getTime() 返回的是毫秒(整数)。
  • 建议:前后端通过 API 交互时间戳时,需统一单位。

2. time 模块的核心用法

time 模块是 Python 内置的处理底层时间的模块。

① 获取当前时间

import time

# 获取当前 Unix 时间戳 (float)
seconds = time.time()
print(f"当前时间戳: {seconds}")

# 获取人类可读的字符串 (本地时区)
print(f"本地时间串: {time.ctime()}") 
# 输出示例: Thu May 16 10:00:00 2024

② 暂停程序执行 (sleep)

在爬虫、限流或自动化测试中非常常用。

print("开始任务...")
time.sleep(2.5)  # 暂停 2.5 秒,支持浮点数
print("任务完成")

③ 性能分析 (高精度计时)

如果你想测试某段 Python 代码运行多快,不要用 time.time(),而应该用 time.perf_counter()

start = time.perf_counter()

# 执行一段耗时代码
sum(range(1000000))

end = time.perf_counter()
print(f"代码耗时: {end - start} 秒")

④ 结构化时间 (struct_time)

如果你想单独获取“年”或“月”,可以使用 localtime()

local_now = time.localtime()
print(f"年份: {local_now.tm_year}")
print(f"月份: {local_now.tm_mon}")

3. 全栈视角下的时间处理建议

在实际的 Web 项目(如 Django, Flask, FastAPI)中,你会发现单纯用 time 模块是不够的:

  1. 存储与显示分离

    • 数据库:建议统一存储为 UTC 时间(或者 Unix 时间戳)。
    • 前端:根据用户的浏览器时区,利用 JavaScript 将 UTC 转换为本地时间展示。
  2. time vs datetime

    • time 模块主要用于获取时间戳和延迟控制。
    • 对于日期的加减(如:计算 7 天后的日期),你应该使用 datetime 模块:
    from datetime import datetime, timedelta
    future_date = datetime.now() + timedelta(days=7)
    
  3. 格式化输出
    如果你需要输出特定的字符串格式(如 2024-05-16 14:00),常用 strftime:

    import time
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
    

总结

  • time.time() 是底层工具,给机器读。
  • datetime 是高级封装,给人读和做日期运算。
  • 做全栈开发,请务必建立时区意识(Timezone Aware)。

1-12 实战demo

import turtle
import math

# 1. 定义多点坐标 (List of Tuples)
coords = [(0, 0), (100, 100), (200, 0), (100, -100), (0, 0)]

# 2. 定义计算两点间距离的函数
def calculate_distance(p1, p2):
    """
    计算两点 (x1, y1) 和 (x2, y2) 之间的欧几里得距离
    """
    x1, y1 = p1
    x2, y2 = p2
    distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return distance

# 3. 设置海龟作图
# 提高速度,设置画笔颜色和粗细
turtle.speed(3)
turtle.pensize(2)
turtle.pencolor("blue")

# 4. 绘制折线并计算总路程
total_distance = 0

for i in range(len(coords)):
    x, y = coords[i]
    
    # 移动到该点(如果是起点则只移动不画线,后续点开始画线)
    if i == 0:
        turtle.penup()
        turtle.goto(x, y)
        turtle.pendown()
        turtle.dot(5, "red")  # 在起始点打一个红点
    else:
        # 计算当前点与前一个点的距离
        dist = calculate_distance(coords[i-1], coords[i])
        total_distance += dist
        
        # 绘图
        turtle.goto(x, y)
        turtle.dot(5, "red") # 在每个节点打点
        
        # 在两点中间位置写上距离(可选,增强可视化)
        mid_x = (coords[i-1][0] + x) / 2
        mid_y = (coords[i-1][1] + y) / 2
        turtle.penup()
        turtle.goto(mid_x, mid_y)
        turtle.write(f"{dist:.2f}", align="center", font=("Arial", 10, "normal"))
        turtle.goto(x, y) # 回到当前坐标继续绘制
        turtle.pendown()

# 5. 显示结果
turtle.penup()
turtle.goto(0, -150)
turtle.color("black")
turtle.write(f"绘制完成!总折线长度: {total_distance:.2f}", 
             align="center", font=("Microsoft YaHei", 12, "bold"))

# 保持窗口不关闭
turtle.done()

1-13 Python基础之运算符全解

作为一名全栈开发人员,掌握运算符是构建逻辑、处理数据和控制程序流程的基础。在 Python 中,运算符的设计非常符合人类语言直觉(如 and, or, in),这与 JavaScript 或 C 系列语言略有不同。

以下是针对 Python 基础运算符的系统性总结、

1. 算术运算符 (Arithmetic Operators)

用于执行最基本的数学运算。

运算符 名称 描述 示例 ($a=10, b=3$)
+ 相加 $a + b = 13$
- 相减 $a - b = 7$
* 相乘 $a * b = 30$
/ 结果总是浮点数 $a / b = 3.33...$
// 整除 向下取整,去掉小数部分 $10 // 3 = 3$
% 取模 返回除法的余数 $10 % 3 = 1$
** 计算次方 $2 ** 3 = 8$

加法补充

  1. 数字相加 3+2 结果是 5
  2. 字符串拼接 “3”+“2”结果是 “32”
  3. 列表、元组等合并 [10,20,30]+[5,10,100]结果是[10,20,30,5,10,100]

乘法操作补充

  1. 数字相乘 3*2 结果是 6
  2. 字符串复制 “sxt”*3 结果是 ”sxtsxtsxt”
  3. 列表、元组等复制 [10,20,30]*3 结果是 [10,20,30,10,20,30,10,20,30]

增强赋值型运算符补充

复合赋值可以让程序更加精炼,提高效率。

运算符 描述 示例 等价于
+= 加法赋值字符串拼接 sum += na += “sxt” sum = sum + na = a + “sxt”
-= 减法赋值 num1 -= n num = num - n
*= 乘法赋值 a *= b a = a * b
/= 浮点除赋值 a/=b a = a / b
//= 整数除赋值 a//=b a = a//b
%= 取余赋值 a%=b a = a % b
**= 幂运算赋值 a**=2 a = a**2
<<= 左移赋值 a<<=2 a = a<<2
>>= 右移赋值 a>>=2 a = a>>2
&= 按位与赋值 a&=b a = a&b
|= 按位或赋值 a|=b a=a|b
^= 按位异或赋值 a^=b a = a^b

⚠️与CJAVA不一样,Python不支持自增(++)和自减(--)

2. 比较运算符 (Comparison Operators)

用于比较两个值,返回布尔值 (TrueFalse)。

运算符 描述 示例
== 等于 (检查值) 5 == 5.0 -> True
!= 不等于 5 != 3 -> True
> 大于 10 > 5 -> True
< 小于 5 < 10 -> True
>= 大于等于 5 >= 5 -> True
<= 小于等于 3 <= 5 -> True

3. 逻辑运算符 (Logical Operators)

全栈开发中处理多重逻辑判断的核心。

运算符 逻辑 规则 短路特性 (Short-circuit)
and 两者皆为真才为真 若左侧为假,不再计算右侧
or 只要有一个为真即为真 若左侧为真,不再计算右侧
not 取反 not True 变为 False

4. 赋值运算符 (Assignment Operators)

用于给变量赋值及进行复合运算。

运算符 示例 等价于
= x = 5 -
+= x += 3 x = x + 3
-= x -= 2 x = x - 2
*= x *= 2 x = x * 2
/= x /= 2 x = x / 2
//= x //= 2 x = x // 2
%= x %= 2 x = x % 2

5. 成员运算符 (Membership Operators)

Python 特有的强大工具,用于检查对象是否在序列中(如列表、字符串、字典)。

运算符 描述 示例
in 在序列中找到值则返回 True 'a' in 'apple' -> True
not in 不在序列中则返回 True 1 in [2, 3] -> False

6. 身份/同一运算符 (Identity Operators)

用于比较两个对象的内存地址

运算符 描述 区别于 ==
is 判断是否为同一个对象 x is y 等同于 id(x) == id(y)
is not 判断是否不是同一个对象 x is not None 是最常用的用法

7. 位运算符 (Bitwise Operators)

在处理底层数据、图像处理或权限系统时非常有用。

运算符 描述 二进制逻辑示例
& 按位与 只有对应位都为 1 才得 1
| 按位或 只要有一个为 1 就得 1
^ 按位异或 位不同则得 1
~ 按位取反 翻转二进制位
<< 左移 相当于乘以 $2^n$
>> 右移 相当于除以 $2^n$

8. 运算符优先级速查表 (从高到低)

  1. 括号 () —— 强制最高优先级
  2. 幂运算 **
  3. 计算类 *, /, //, % 然后再 +, -
  4. 位移类 <<, >>
  5. 位逻辑 & > ^ > |
  6. 比较/身份/成员 ==, !=, >, is, in
  7. 逻辑类 not > and > or —— 逻辑或优先级最低

9.基本运算符总结

运算符 说明
and , or , not 布尔与、布尔或、布尔非
is , is not 同一性判断,判断是否为同一个对象
in , not in 判断是否在指定序列中
<,<=,>,>=,!=,== 比较值是否相当,可以连用
| ^ & 按位或,按位异或、按位与
<<, >> 移位
~ 按位翻转
+,-,*,/,//,% 加,减,乘,浮点除、整数除、取余
** 幂运算

1-14 Python基础之同一运算符和成员运算符

作为全栈开发人员,在处理复杂的后端逻辑、数据库查询结果或 API 数据验证时,同一运算符成员运算符是编写高效、安全代码的关键。

以下是关于这两个运算符的深度解析。

1. 同一运算符 (Identity Operators)

image-20211025114853853

同一运算符用于比较两个对象的内存地址(ID)是否相同。它告诉我们这两个变量是否指向内存中的同一个对象。

运算符 描述 核心原理
is 判断两个变量是否引用同一个对象 id(a) == id(b)
is not 判断两个变量是否引用不同对象 id(a) != id(b)

is== 的本质区别

这是程序员最容易混淆的地方:

  • == (等值运算符):侧重于“长得是否一样”(内容/值)。

  • is (同一运算符):侧重于“是不是同一个实体”(内存地址)。

  • is 用于判断两个变量引用对象是否为同一个,既比较对象的地址。

    == 用于判断引用变量引用对象的值是否相等,默认调用对象的 __eq__()方法。

代码示例:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1

print(list1 == list2) # True  (值相等)
print(list1 is list2) # False (内存地址不同,是两个独立的列表)
print(list1 is list3) # True  (list3 指向 list1 的内存)

② 在 Web 开发中的最佳实践

在全栈开发中,判断一个变量是否为空(None)时,必须且只能使用 is。因为 None 在 Python 中是一个单例对象。

# API 参数校验示例
user_input = request.json.get('username')

if user_input is None:
    return {"error": "用户名不能为空"}, 400

2. 成员运算符 (Membership Operators)

成员运算符用于测试一个值是否存在于某个序列(如字符串、列表、元组、字典或集合)中。

运算符 描述 示例
in 如果在序列中找到值,返回 True 'a' in 'apple'
not in 如果在序列中没找到值,返回 True 'guest' not in ['admin', 'editor']

① 针对不同数据类型的行为

  • 字符串:检查是否包含子字符串。
  • 列表/元组:检查是否包含某个元素。
  • 字典:检查键 (Key) 是否存在,而不是值 (Value)。
  • 集合 (Set):检查元素是否存在。

代码示例:

# 字典成员检测
user_data = {"id": 1, "name": "Alex"}
print("id" in user_data)      # True
print("Alex" in user_data)    # False (只查键)

# 权限控制逻辑
allowed_roles = {"admin", "editor", "manager"}
current_user_role = "guest"

if current_user_role not in allowed_roles:
    print("权限不足!")

3. 全栈视角下的性能与安全

作为开发人员,你需要关注运算符背后的性能差异

① 成员运算的性能效率 (O(n) vs O(1))

  • 列表 (list) / 元组 (tuple):使用 in线性搜索。如果列表有 100 万个元素,Python 需要从头遍历,速度慢 ($O(n)$)。
  • 集合 (set) / 字典 (dict):使用 in哈希查找。无论数据量多大,查询时间几乎恒定 ($O(1)$)。
  • 建议:在处理大规模黑名单过滤、权限列表比对时,优先将数据转换为 set 再使用 in 运算符。

② 逻辑安全:is 的陷阱

不要对整数字符串频繁使用 is 进行比较,因为 Python 内部有“驻留机制(Interning)”。

# 陷阱:小整数会被缓存,但大整数不会
a = 256
b = 256
print(a is b) # True

a = 1000
b = 1000
print(a is b) # False (在某些环境下,如交互式解释器)

结论:除了判断 is Noneis Trueis False 外,其余所有内容比较请一律使用 ==

总结

  1. 同一性 (is):查身份证 ID,用于单例检查(尤其是 None)。
  2. 成员性 (in):查容器里有没有。
  3. 性能点:在大数据集合中,in set() 远快于 in list()
  4. 业务逻辑:善用 not in 可以写出更符合人类语言逻辑的鉴权代码。

1-15 Python基础之整数缓存

在 Python(特别是官方的 CPython 实现)中,整数缓存机制(也称为 Integer InterningSmall Integer Caching)是一个为了优化性能和节省内存而设计的底层策略。

作为全栈开发人员,理解这一点能帮你避开很多在后端逻辑处理(如 Django 的 ID 比较或数据处理)中的隐形 Bug。

1. 什么是整数缓存?

在 Python 程序运行时,某些整数会被频繁使用(如循环计数器、列表索引、状态码)。
为了避免重复创建和销毁这些常用的整数对象,Python 在解释器启动时,就会在内存中预先创建好一个整数对象池。当你的代码需要用到这些数字时,Python 直接指向池里的现有对象。

2. 缓存的范围:-5256

CPython 将 -5 到 256(闭区间)之间的所有整数进行了缓存。

  • 为什么是这个范围? 因为在大多数程序中,这个范围内的整数使用频率最高。
  • 存储位置: 这些对象被存储在全局数组 small_ints 中。

3. 代码演示:is vs ==

利用我们之前学到的同一运算符 (is),可以清晰看到缓存的效果:

# 在缓存范围内
a = 256
b = 256
print(a is b)   # True (内存地址相同,指向同一个缓存对象)

# 超出缓存范围
x = 257
y = 257
print(x is y)   # False (创建了两个不同的对象,地址不同)

# 比较内容永远正确
print(x == y)   # True (值是一样的)

4. 为什么要这么做?(性能优势)

  1. 节省内存:不需要为成百上千个“1”或“100”分配独立的内存空间。
  2. 提升速度
    • 创建新对象需要申请内存(Malloc),销毁对象需要垃圾回收(GC)。
    • 通过缓存,直接返回指针引用,极大地提高了执行效率。

5. 进阶陷阱:代码块优化 (Constant Folding)

你可能会在某些 IDE(如 PyCharm)或直接运行 .py 脚本时发现以下现象:

# 运行脚本 test.py
a = 1000
b = 1000
print(a is b)  # 竟然返回了 True!

原因:
不是因为整数缓存池扩大了,而是因为 Python 编译器的“常量折叠”优化

  • 当 Python 编译一个程序块(比如一个函数或一个模块)时,如果在同一代码块里出现了两个相同的长常量,编译器会尝试让它们指向同一个常量对象。
  • 如果在 交互式解释器(REPL/Shell) 中一行一行输入,则不会有这种优化,结果依然是 False

6. 全栈开发者的实践启示

① 永远不要用 is 比较业务中的数字

在判断订单状态、用户 ID、计数统计时,必须使用 ==

# 危险写法 (如果 status 为 300 就会报错)
if status is 200: 
    pass

# 正确写法
if status == 200:
    pass

② 类似的概念:字符串驻留 (String Interning)

Python 同样会对一些短的、仅含标识符字符的字符串进行缓存(Interning),原理与整数缓存类似。

③ JS 与 Python 的对比

在 JavaScript 中,基本类型(Primitive types)的长数值比较是用值比较的(即使是 ===),并没有类似 Python 这种明显的“对象身份”陷阱。但在 Python 这种“万物皆对象”的语言里,身份(Identity)和值(Value)的区分至关重要。

总结

  • 范围-5256 是预加载的单例对象。
  • 目的:空间和时间的平衡及优化。
  • 准则is 只用于 NoneTrueFalse 这类真正的单例,业务数值比较始终用 ==

1-16 Python基础之字符串操作一

在 Python 全栈开发中,字符串(String)的处理是最核心的技能之一。无论是处理用户提交的表单、生成 HTML 模板,还是与后端数据库交互,字符串都扮演着至关重要的角色。

以下是关于 Python 字符串、Unicode 以及创建方式的深度总结:

1.字符串基本特点

  1. 字符串的本质是:字符序列。
  2. Python不支持单字符类型,单字符也是作为一个字符串使用的。

⚠️Python的字符串是不可变的,我们无法对原字符串做任何修改。但,可以将字符串的一部分复制到新创建的字符串,达到“看起来修改”的效果。

很多人初学编程时,总是担心自己数学不行,潜意识里认为数学好才能编程。实际上,大多数程序员打交道最多的是“字符串”而不是“数学”。因为,编程是用来解决现实问题的,因此逻辑思维的重要性远远超过数学能力。

2. Unicode 字符集

image-20211026162907356

在 Python 3 中,字符串的所有字符都是 Unicode

  • 什么是 Unicode? 它是一个为世界上所有文字(包括汉字、希腊字母、甚至表情符号 Emoji)分配唯一编号的标准。
  • 编码差异:Python 3 的 str 类型在内存中是以 Unicode 表示的。而当你需要将字符串保存到文件或通过网络发送时,通常会将其编码(Encode)UTF-8
  • 全栈视角:当你的前端页面(HTML)声明了 <meta charset="UTF-8">,Python 后端接收到的数据能完美兼容,不会出现乱码。

使用内置函数ord()可以把字符转换成对应的Unicode码;

使用内置函数chr()可以把十进制数字转换成对应的字符。

# Unicode 示例
s = "你好 Python 🐍"
print(s) # 正常打印,包含汉字和 Emoji

3. 三种创建字符串的方式

在 Python 中,你可以根据不同场景选择三类引号:

① 单引号 (' ')

最常用的方式,适合短字符串。

name = 'FullStack Dev'

② 双引号 (" ")

功能与单引号完全一致。其优势在于:如果字符串内部包含单引号,外层用双引号可以避免转义。

# 推荐做法
sentence = "It's a beautiful day" 

# 对应的单引号做法(需要转义符号 \)
sentence_alt = 'It\'s a beautiful day'

③ 三引号 (''' '''""" """)

也称为“多行字符串”。

  • 支持多行:会自动保留字符串中的回车换行。
  • 文档字符串 (Docstrings):常用于函数或类的说明文档。
  • 全栈应用:在 Python 代码中手写一段 HTML 模板或 SQL 语句时极其方便。
html_content = """
<div>
    <h1>Hello World</h1>
    <p>这是一个多行字符串</p>
</div>
"""

4. len() 函数

len() 用于返回字符串中字符的数量(注意:是物理字符数,而非字节数)。

  • 计算规则:无论是一个字母、一个汉字,还是一个 Emoji,在 Python 3 的 len() 中都计为 1
  • 全栈开发注意点
    • 在进行数据库字段设计时(如 MySQL 的 VARCHAR(20)),数据库存储的通常也是字符数,这与 Python 的 len() 是一致的。
    • 但如果要计算网络传输大小,则需要将其转换为字节串(bytes)后计算 len(s.encode('utf-8'))

代码示例:

s1 = "ABC"
s2 = "中国"
s3 = "🐍"

print(len(s1)) # 结果:3
print(len(s2)) # 结果:2 (在 Python 2 中可能是 6,但在 Python 3 是 2)
print(len(s3)) # 结果:1

# 字节长度 vs 字符长度
print(len(s2.encode('utf-8'))) # 结果:6 (因为一个汉字在 UTF-8 中占 3 字节)

① 空字符串

Python允许空字符串的存在,不包含任何字符且长度为0。例如:

c = ''
print(len(c))       #结果:0

5. 字符串的不可变性(Immutable)—— 补充干货

作为全栈开发,必须理解这一点:Python 的字符串是不可变的
一旦创建,你就不能修改其中的某个字符。

s = "Python"
# s[0] = "p"  # 这行会报错! TypeError

# 只能创建一个新的字符串
s = "p" + s[1:]
print(s) # "python"

性能提示:如果你在循环中频繁用 + 拼接大量字符串,性能会很差。在处理大量数据拼接(如生成长的 HTML 列表)时,推荐使用 ''.join(list_of_strings)

总结

  1. Unicode 保证了全球语言的兼容性,不用担心乱码。
  2. 单/双引号 灵活嵌套,三引号 处理多行文本和 SQL/HTML。
  3. len() 返回字符数量,符合直觉,但传输数据时需关注字节数。

1-17 Python基础之字符串操作二

在全栈开发中,字符串处理涉及前后端数据交互、日志记录以及动态 HTML/模板生成。掌握 Python 字符串的基础操作是处理这些任务的前提。

以下是关于转义字符、拼接、复制input() 输入的系统总结:


1. 转义字符 (Escape Characters)

当字符串中包含一些具有特殊含义的字符(如引号本身、换行符)时,需要使用反斜杠 \ 开启转义。

转义字符 说明 全栈应用场景
\' 单引号 字符串内嵌套单引号
\" 双引号 字符串内嵌套双引号
\n 换行符 生成多行日志或格式化文本输出
\t 制表符 (Tab) 格式化控制台输出整齐的表格数据
\\ 反斜杠本身 表示 Windows 文件路径(如 C:\\Users\\...

原始字符串 (Raw String) 技巧:
在字符串前加 r,其中的转义字符将不再生效。这在编写正则表达式 (Regex) 时非常有用。

# 路径处理
path = r"C:\nextjs\app\page.js"  # 不会被识别为 \n 或 \a 等

2. 字符串拼接 (Concatenation)

Python 提供了多种方式将多个字符串组合在一起。

① 使用 +

最直观,但由于 Python 字符串不可变的特性,频繁使用 + 拼接会消耗较多内存

first_name = "React"
last_name = "Framework"
full_name = first_name + " " + last_name

② 隐式拼接

仅限字符串常量放在一起时自动合并。

html_tag = "<div " "class='container'></div>" # 自动合并

③ f-string (推荐做法)

自 Python 3.6+ 引入。这是全栈开发中最标准、效率最高的方式。

# 将变量直接嵌入字符串
db_user = "admin"
port = 5432
connection_str = f"Connecting to {db_user} at port {port}..."

.join() 方法

当需要拼接列表中的大量字符串(如从数据库查出的多行纪录)时,性能远超 +

tags = ["Python", "JavaScript", "SQL"]
html_list = ", ".join(tags) # "Python, JavaScript, SQL"

3. 字符串复制 (Replication)

使用乘法运算符 * 可以快速重复字符串。

  • 全栈场景:常用于在控制台调试时生成分隔线。
separator = "-" * 50
print(separator)
print("  DEBUGGING API RESPONSE  ")
print(separator)

4. 获取键盘输入 input()

input() 函数允许程序暂停并等待用户从键盘输入文本。

  • 返回值类型input() 永远返回 字符串 (str)
  • 类型转换:如果输入的是数字,必须手动转换(如 int()float()),否则无法进行数学计算。

示例代码:

# 获取前端端口号并验证
user_port = input("请输入前端运行的端口号: ")

print(f"数据类型是: {type(user_port)}") # <class 'str'>

# 如果需要数学运算,必须转换
port_number = int(user_port) 
if port_number == 3000:
    print("这是 Next.js/React 的默认端口。")

5. 全栈开发避坑指南

  1. 拼接时的类型错误
    在 Python 中,你不能直接 str + int(例如 "Port: " + 3000 会报错)。而在 JavaScript 中这会自动转为字符串。

    • Pythonic 方案:使用 f-string: f"Port: {3000}"
  2. input() 的安全性
    虽然在生产 Web 环境中我们不直接使用 input() 获取用户输入(而是通过 API 请求),但在编写 CLI (命令行工具) 或脚本(例如:自动化部署脚本、数据库迁移工具)时,它是最基础的交互手段。

  3. 转义与 SQL 注入
    虽然 \ 能够转义字符,但在手动拼接 SQL 语句时,严禁通过字符串转义来防范 SQL 注入。应始终使用 Web 框架(Django/SQLAlchemy)提供的参数化查询。

总结

  • 转义:让特殊字符“保持原样”或“发挥特权”。
  • 拼接:日常用 f-string,批量处理用 .join()
  • 复制* 快速生成冗余字符。
  • 输入:记得转换返回的 字符串

1-18 Python基础之字符串操作三

作为全栈开发人员,处理字符串不仅仅是简单的显示文本,还涉及到数据清洗、API 返回结果格式化以及高效的内存管理。

以下是关于 Python 字符串转换、提取、替换及底层内存机制的深度解析:


1. str() 函数:强制类型转换

在处理后端逻辑时,经常需要将数据库读取的数字、日期或对象转换为字符串,以便进行拼接或返回给前端(JSON 格式)。

  • 功能:将其他数据类型(int, float, list, dict 等)转换为字符串。
  • 示例
    user_id = 1024
    print("User ID is: " + str(user_id)) # 必须转换,直接 + 会报错
    
    data_list = [1, 2, 3]
    print(str(data_list)) # "[1, 2, 3]" (变成了一个外观是列表的字符串)
    

2. 字符提取(索引与切片)

Python 的字符串提取功能非常强大,类似于 JavaScript 的 slice(),但语法更简洁。

① 索引 (Indexing)

  • 正向从 0 开始。
  • 反向从 -1 开始(提取末尾字符极其方便)。
s = "Next.js"
print(s[0])   # 'N'
print(s[-1])  # 's'

② 切片 (Slicing) - [start : end : step]

  • 规则:包头不包尾(包含 start,不包含 end)。
  • 全栈技巧:常用于处理文件后缀、URL 路径或隐藏敏感信息(如隐藏手机号中间位)。
url = "https://www.python.org"

# 提取协议
print(url[:5])     # "https" (省略 start 默认为 0)

# 提取域名(从索引 8 开始到最后)
print(url[8:])     # "www.python.org" (省略 end 默认为结尾)

# 步长 (step):逆序字符串(笔试高频题)
print(url[::-1])   # "gro.nohtyp.www//:sptth"

3. replace() 字符串替换

image-20211026164619887

在处理用户提交的敏感词过滤、或是根据环境动态修改路径时,replace() 是首选。

  • 语法s.replace(old, new, [count])
  • 关键点:它不会修改原字符串,而是返回一个全新的字符串(因为字符串是不可变的)。
path = "api/v1/user/profile"
new_path = path.replace("v1", "v2")

print(path)      # "api/v1/user/profile" (原词没变)
print(new_path)  # "api/v2/user/profile" (新词产生)

4. 字符串的内存分析(核心面试点)

理解内存机制是区分高级开发人员与初学者的标准。

① 字符串的不可变性 (Immutability)

在 Python 中,一旦字符串在内存中被创建,它的内容就不能被改变。
当你执行 s = s.replace("a", "b") 时,内存中发生了以下过程:

  1. 在内存中寻找一块新空间。
  2. 计算并存放替换后的新字符串内容。
  3. 将变量 s 指向这块新空间的地址。
  4. 原有的旧字符串如果没有其他引用,将被 Python 的垃圾回收 (GC) 自动处理。

② 内存驻留 (String Interning)

为了优化性能,对于一些短小的、符合标识符规则的字符串,Python 会尝试让它们共享同一块内存地址。

a = "hello"
b = "hello"
print(a is b) # True (它们指向内存中同一个地址)

③ 拼接的性能警告

虽然用 + 拼接很方便,但在循环中大量拼接性能极差:

# 差劲的做法:每次拼接都会在内存中开启新空间,复制老内容
result = ""
for i in range(1000):
    result += str(i)

# 全栈优选方案:.join()
# join 预先计算总长度,一次性申请内存,效率极高
result = "".join([str(i) for i in range(1000)])

总结(全栈视角对比)

特性 Python JavaScript
可变性 不可变 不可变 (Primitive String)
提取 s[start:end] (切片) s.substring()s.slice()
替换 replace() 返回新串 replace() 返回新串
转换 str(123) String(123)123.toString()

作为开发人员,记住一句话:在 Python 中,所有“修改”字符串的操作实质上都是在“创建”新字符串。 这种设计简化了多线程环境下的数据安全。

1-19 Python基础之字符串操作四

这一部分涵盖了 Python 字符串处理的进阶实战。作为全栈开发人员,理解这些不仅能提升代码效率,还能在处理大规模文本数据(如日志分析、爬虫、报表生成)时避免性能瓶颈。


1. 字符串切片 (Slicing) & 逆序

(简要回顾,补充底层逻辑)

  • 原理:切片操作通过调用底层 __getitem__ 并传入 slice 对象来实现。
  • 逆序应用s[::-1]
  • 应用场景:解析固定格式的文件(如旧式银行报文)、反转域名、处理文件路径。

典型操作(三个量为正数的情况)如下:

操作和说明 示例 结果
[:] 提取整个字符串 “abcdef”[:] “abcdef”
[start:]从start索引开始到结尾 “abcdef”[2:] “cdef”
[:end]从头开始知道end-1 “abcdef”[:2] “ab”
[start:end]从start到end-1 “abcdef”[2:4] “cd”
[start:end:step]从start提取到end-1,步长是step “abcdef”[1:5:2] “bd”

其他操作(三个量为负数)的情况:

示例 说明 结果
"abcdefghijklmnopqrstuvwxyz"[-3:] 倒数三个 “xyz”
"abcdefghijklmnopqrstuvwxyz"[-8:-3] 倒数第八个到倒数第三个(包头不包尾) 'stuvw'
"abcdefghijklmnopqrstuvwxyz"[::-1] 步长为负,从右到左反向提取 'zyxwvutsrqponmlkjihgfedcba'

切片操作时,起始偏移量和终止偏移量不在[0,字符串长度-1]这个范围,也不会报错。起始偏移量小于0则会当做0,终止偏移量大于“长度-1”会被当成-1。例如:

>>> 'abcdefg'[3:50]
'defg'

2. split() 分割与 join() 合并:效率之王

这是全栈开发中处理数据格式转换(如 CSV 到 JSON)最频繁的操作。

  • split(sep, maxsplit)

    • 将字符串按分隔符拆分为列表。如果不传 sep,默认按任何空白字符(空格、换行、制表符)分割,并自动丢弃空结果。
  • join(iterable)

    • 原理(非常重要):与 + 不同,join() 会先计算所有字符串的总长度,然后一次性申请内存并拷贝。
  • 代码效率测试(全栈必知)

    import time
    
    # 差评做法:频繁开辟内存空间,O(n^2)
    start = time.time()
    res = ""
    for i in range(100000):
        res += str(i)
    print("使用 + 拼接耗时:", time.time() - start)
    
    # 推荐做法:一次性计算内存,O(n)
    start = time.time()
    res = "".join([str(i) for i in range(100000)])
    print("使用 join 拼接耗时:", time.time() - start)
    
  • 结论:在循环内拼接字符串时,永远优先使用 join()

split()可以基于指定分隔符将字符串分隔成多个子字符串(存储到列表中)。如果不指定分隔符,则默认使用空白字符(换行符/空格/制表符)。示例代码如下:

拼接字符串要点: 使用字符串拼接符+,会生成新的字符串对象,因此不推荐使用+来拼接字符串。推荐使用join函数,因为join函数在拼接字符串之前会计算所有字符串的长度,然后逐一拷贝,仅新建一次对象。


3. 驻留机制 (Interning) 与 字符串比较 与 同一性 与 成员操作符判断子字符串

① 驻留机制

  • 驻留机制:为了优化寻址速度,对于符合“标识符规则”(字母、数字、下划线)的常量字符串,Python 会在程序启动时将其存入一个全局字典(Intern table),让值相同的串指向同一地址。
  • is (身份判断):比较内存地址 id()
  • == (值判断):调用 __eq__ 比较内容。
  • 应用注意
    • 绝不能用 is 比较业务中的字符串(因为动态生成的、复杂的或包含特殊符号的字符串不会被驻留)。
    • is None 是性能最高且标准的做法,因为 None 是全局单例。
字符串驻留:常量字符串只保留一份。

c = "dd#"
d = "dd#"
print(c is d)   #True

② 字符串比较与同一性

我们可以直接使用== !=对字符串进行比较,是否含有相同的字符。

我们使用is is not,判断两个对象是否同一个对象。比较的是对象的地址,即id(obj1)是否和id(obj2)相等。

③ 成员操作符判断子字符串

in not in 关键字,判断某个字符(子字符串)是否存在于字符串中。


4. 常用方法:清理与检查

方法 应用场景 (全栈视角)
find() / index() find() 找不到返回 -1,常用于判读 URL 中是否包含特定参数。
startswith() / endswith() 校验 URL 协议 (https://) 或文件上传后缀名 (.png)。
strip() / lstrip() / rstrip() 必用。处理用户表单或读取配置文件时,移除两端多余的空格或换行。
upper() / lower() 忽略大小写的用户登录验证、搜索关键字归一化。
isdigit() / isalpha() 前端输入在后端的二次基础验证(如验证码是否全数字)。
center() / ljust() 编写控制台工具 (CLI) 时,美化输出排版。

常用查找方法

我们以一段文本作为测试:

a='''我是高淇,我在北京尚学堂科技上班。我的儿子叫高洛希,他6岁了。我是一个编程教育的普及者,希望影响6000万学习编程的中国人。我儿子现在也开始学习编程,希望他18岁的时候可以超过我'''
方法和使用示例 说明 结果
len(a) 字符串长度 96
a.startswith('我是高淇') 以指定字符串开头 True
a.endswith('过我') 以指定字符串结尾 True
a.find('高') 第一次出现指定字符串的位置 2
a.rfind('高') 最后一次出现指定字符串的位置 29
a.count("编程") 指定字符串出现了几次 3
a.isalnum() 所有字符全是字母或数字 False

① 去除首尾信息

我们可以通过strip()去除字符串首尾指定信息。通过lstrip()去除字符串左边指定信息,rstrip()去除字符串右边指定信息。

【操作】去除字符串首尾信息

>>> "*s*x*t*".strip("*")
's*x*t'
>>> "*s*x*t*".lstrip("*")
's*x*t*'
>>> "*s*x*t*".rstrip("*")
'*s*x*t'
>>> "  s xt  ".strip()
's xt'

大小写转换

编程中关于字符串大小写转换的情况,经常遇到。我们将相关方法汇总到这里。为了方便学习,先设定一个测试变量:

a = "gaoqi  love  programming, love  SXT"
示例 说明 结果
a.capitalize() 产生新的字符串,首字母大写 'Gaoqi love programming, love sxt'
a.title() 产生新的字符串,每个单词都首字母大写 'Gaoqi Love Programming, Love Sxt'
a.upper() 产生新的字符串,所有字符全转成大写 'GAOQI LOVE PROGRAMMING, LOVE SXT'
a.lower() 产生新的字符串,所有字符全转成小写 'gaoqi love programming, love sxt'
a.swapcase() 产生新的,所有字母大小写转换 'GAOQI LOVE PROGRAMMING, LOVE sxt'

格式排版

center()ljust()rjust()这三个函数用于对字符串实现排版。示例如下:

>>> a="SXT"
>>> a.center(10,"*")
'***SXT****'
>>> a.center(10)
'  SXT   '
>>> a.ljust(10,"*")
'SXT*******'

特征判断方法

  1. isalnum() 是否为字母或数字
  2. isalpha() 检测字符串是否只由字母组成(含汉字)
  3. isdigit() 检测字符串是否只由数字组成
  4. isspace() 检测是否为空白符
  5. isupper() 是否为大写字母
  6. islower() 是否为小写字母
 >>> "sxt100".isalnum()
 True
 >>> "sxt尚学堂".isalpha()
 True
 >>> "234.3".isdigit()
 False
 >>> "23423".isdigit()
 True
 >>> "aB".isupper()
 False
 >>> "A".isupper()
 True
 >>> "\t\n".isspace()
 True

5. format 格式化:动态拼接的利器

除了最新的 f-string,format() 在处理模板数据或复杂数字格式时依然重要。

  • 填充与对齐{:*>10} (右对齐,总宽10,星号填充)。
  • 数字格式化
    • 精度控制{:.2f} (保留两位小数)。
    • 千分位{:,} (打印金融金额:1,234,567.89)。
    • 进制转换{:b} (二), {:x} (十六)。
  • 示例
    # 财务报表格式化
    balance = 12345.678
    print(f"账户余额:{balance:,.2k}") # 报错,应为 {balance:,.2f}
    print(f"账户余额:{balance:*>15,.2f}") # ***12,345.68
    

format()基本用法

基本语法是通过 {}:来代替以前的 %

format() 函数可以接受不限个数的参数,位置可以不按顺序。

我们通过示例进行格式化的学习。

>>> a = "名字是:{0},年龄是:{1}"
>>> a.format("高淇",18)
'名字是:高淇,年龄是:18'
>>> a.format("高希希",6)
'名字是:高希希,年龄是:6'
>>> b = "名字是:{0},年龄是{1}。{0}是个好小伙"
>>> b.format("高淇",18)
'名字是:高淇,年龄是18。高淇是个好小伙'
>>> c = "名字是{name},年龄是{age}"
>>> c.format(age=19,name='高淇')
'名字是高淇,年龄是19'

我们可以通过{索引}/{参数名},直接映射参数值,实现对字符串的格式化,非常方便。

② 填充与对齐

  1. 填充常跟对齐一起使用
  2. ^<>分别是居中、左对齐、右对齐,后面带宽度
  3. :号后面带填充的字符,只能是一个字符,不指定的话默认是用空格填充
>>> "{:*>8}".format("245")
'*****245'
>>> "我是{0},我喜欢数字{1:*^8}".format("高淇","666")
'我是高淇,我喜欢数字**666***'

数字格式化

浮点数通过f,整数通过d进行需要的格式化。案例如下:

>>> a = "我是{0},我的存款有{1:.2f}"
>>> a.format("高淇",3888.234342)
'我是高淇,我的存款有3888.23'

其他格式,供大家参考:

数字 格式 输出 描述
3.1415926 3.14 保留小数点后两位
3.1415926 3.14 带符号保留小数点后两位
2.71828 3 不带小数
5 05 数字补零 (填充左边, 宽度为2)
5 5xxx 数字补x (填充右边, 宽度为4)
10 10xx 数字补x (填充右边, 宽度为4)
1000000 1,000,000 以逗号分隔的数字格式
0.25 25.00% 百分比格式
1000000000 1.00E+09 指数记法
13 13 右对齐 (默认, 宽度为10)
13 13 左对齐 (宽度为10)
13 13 中间对齐 (宽度为10)

6. 可变字符串:io.StringIO

Python 的 str 是不可变的。有时你需要一个“类似文件的对象”来动态构建超长文本,而不想频繁生成新的字符串对象。

  1. Python中,字符串属于不可变对象,不支持原地修改,如果需要修改其中的值,只能创建新的字符串对象。
  2. 确实需要原地修改字符串,可以使用io.StringIO对象或array模块
  • 原理StringIO 在内存中开辟一块缓冲区,像操作文件一样操作字符串。
  • 应用场景
    1. 大规模生成 CSV 导出文件内容。
    2. 单元测试:模拟一个文件对象传给需要处理文件的函数。
  • 示例
    from io import StringIO
    
    f = StringIO()
    f.write("Line 1\n")
    f.write("Line 2\n")
    
    # 获取全部内容
    content = f.getvalue()
    print(content)
    f.close()
    

7. 类型转换总结

全栈开发中,Python 与前端 (JSON/Strings) 交互后的转换至关重要:

  1. str(x):通用的“转字符串”方法。
  2. int(str, base):将字符串转为整数。注意 int("10", 16) 是十六进制转十进制。
  3. float(str):转浮点数。
  4. list(str):将字符串打散成字符列表。
  5. ord(char)chr(int)
    • ord('a') -> 97 (Unicode 码点)。
    • chr(97) -> 'a'。
    • 场景:简单加密算法、生成随机验证码、判断字符范围。
  6. eval() (警告!)
    • 能将字符串当成 Python 表达式执行。
    • 全栈陷阱绝对不要对用户输入使用 eval(),这会导致严重的远程代码执行 (RCE) 安全漏洞。如果需要解析 JSON 格式的字符串,请使用 json.loads()
类型转换
int(x [,base]) 将x转换为一个整数
long(x [,base] ) 将x转换为一个长整数
float(x) 将x转换到一个浮点数
complex(real[,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
Complex(A) 将参数转换为复数型
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
unichr(x) 将一个整数转换为Unicode字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

给全栈开发者的核心建议:

  1. 性能优先:在大文本拼接前,养成把零件丢进 list 最后再 "".join(list) 的习惯。
  2. 安全优先:始终对用户传入的内容进行 strip() 处理,并警惕 eval() 的使用。
  3. 对齐一致:如果后端涉及生成日志或 CLI 工具,利用 ljust()format() 的对齐功能,会让你的后端的输出像前端页面一样优雅。
posted @ 2026-01-31 18:53  edward-y  阅读(5)  评论(0)    收藏  举报