python 语法篇(一)

目录

  • [1 正则匹配](#1 正则匹配)
    • 注意点1
    • [1.1 正则匹配字符串写法](#1.1 正则匹配字符串写法)
    • [1.2 创建re函数](#1.2 创建re函数)
      • (1)re.search()--搜索第一个匹配项
      • [(2)re.match() - 从字符串开头匹配](#(2)re.match() - 从字符串开头匹配)
      • [(3)re.findall() - 返回所有匹配项的列表](#(3)re.findall() - 返回所有匹配项的列表)
      • [(4)re.finditer() - 返回匹配项的迭代器(适合大文本)](#(4)re.finditer() - 返回匹配项的迭代器(适合大文本))
      • [(5)re.sub() - 替换匹配内容](#(5)re.sub() - 替换匹配内容)
      • [(6)re.split() - 按正则表达式分割字符串](#(6)re.split() - 按正则表达式分割字符串)
  • [2 参数数量/类型/默认值指定](#2 参数数量/类型/默认值指定)
  • [3 引用传递和值传递说明](#3 引用传递和值传递说明)
  • [4 排列组合 itertools](#4 排列组合 itertools)
  • [5 内置变量/特殊变量](#5 内置变量/特殊变量)
    • [5.1 内置变量](#5.1 内置变量)
    • [5.2 类相关的特殊属性](#5.2 类相关的特殊属性)
  • [6 try-except-else-finally机制](#6 try-except-else-finally机制)
    • [6.1 基础用法](#6.1 基础用法)
    • [6.2 else-finally](#6.2 else-finally)
    • [6.3 向上一级抛出错误](#6.3 向上一级抛出错误)
  • [7 Threading - 线程(不是进程,创建进程我用的少)](#7 Threading - 线程(不是进程,创建进程我用的少))
    • [7.1 讲到线程,就不得不谈线程通信](#7.1 讲到线程,就不得不谈线程通信)
  • [8 路径操作及路径索引 glob](#8 路径操作及路径索引 glob)

以下资料参考官网及AI

1 正则匹配

re官网

python 的 re 库能够实现正则匹配功能。

注意点1

注意:在Python中使用正则表达式时要优先使用原始字符串。

(也就是说,字符串不会被python语言解析。而只会被re库里的函数解析)

原因如下:

正则表达式本身用 \ 转义特殊字符(如 \d 表示数字),但Python字符串中的 \ 也是转义符。因此,在普通字符串中写正则表达式时,需用 ‌两个反斜杠‌ 表示一个实际的反斜杠(如 \d)。

原始字符串(前缀 r)会忽略Python字符串的转义规则,直接保留所有字符的字面值。例如,r"\d" 会直接传递给正则引擎 \d,而无需额外转义。

以下为错误案例1:

python 复制代码
import re

pattern = "\\"  # 普通字符串:实际传递的是单个 \,但正则引擎会报错(转义不完整)
re.findall(pattern, "a\\b")  # 报错:因为正则收到的是单个 \

正确写法:

python 复制代码
pattern = "\\\\"  # 普通字符串中,四个反斜杠 → Python转义为两个 \,正则引擎收到两个 \
result = re.findall(pattern, "a\\b")  # 成功匹配到 ["\\"]

使用原始字符串的写法:

python 复制代码
pattern = r"\\"  # 原始字符串直接保留两个 \,正则引擎收到两个 \
result = re.findall(pattern, "a\\b")  # 成功匹配到 ["\\"]

以下为错误案例2:

python 复制代码
pattern = "\b"   # 普通字符串中,\b 是退格符,正则引擎无法识别为单词边界
re.findall(pattern, "hello world")  # 匹配失败

正确写法:

python 复制代码
pattern = r"\b"  # 原始字符串直接传递 \b,正则引擎识别为单词边界
result = re.findall(pattern, "hello world")  # 匹配到单词边界的空字符

1.1 正则匹配字符串写法

pattern = r'xxx'

匹配字符 含义 案例
[ ] 一个字符的集合,这写字符可以单独列出,也可以用范围表示(范围用-分隔) [abc],[a-c]
$ [akm\] 将会匹配以下任一字符 'a', 'k', 'm' 或 ''
^ ^放在字符类的最开头,集合取反来匹配字符类中未列出的字符。(如果放在字符类其他位置,则无意义) [^5] 将匹配除 '5' 之外的任何字符;[5^] 将匹配 '5' 或 '^'
\w 匹配任何字母数字字符 相当于字符类 [a-zA-Z0-9_]
\d 匹配任何十进制数字 等价于字符类 [0-9]
\S 匹配任何非空白字符 等价于字符类 [^ \t\n\r\f\v]
\W 匹配任何非字母与数字字符 等价于字符类 [^a-zA-Z0-9_]
\s 匹配任何空白字符 [ \t\n\r\f\v]
\D 匹配任何非数字字符 等价于字符类 [^0-9]
. 匹配除换行符之外的任何字符
* 定前一个字符可以匹配零次或更多次,而不是只匹配一次 ca*t 将匹配 'ct' ( 0 个 'a' )、'cat' ( 1 个 'a' )、 'caaat' ( 3 个 'a' )
+ 匹配一次或更多次 ca+t 可以匹配 'cat' ( 1 个 'a' )或 'caaat' ( 3 个 'a'),但不能匹配 'ct'
{m,n} 其中 m 和 n 是十进制整数,该限定符意味着必须至少重复 m 次,最多重复 n 次。 a/{1,3}b 可以匹配 'a/b'、'a//b' 或者 'a///b' ,但不能匹配中间没有斜杆的 'ab',或者四个斜杆的 'ab'
() 它们将包含在其中的表达式组合在一起,你可以使用重复限定符重复组的内容 (ab)*,匹配ab 0到多次

1.2 创建re函数

(1)re.search()--搜索第一个匹配项

python 复制代码
import re

text = "Python is fun, Python is powerful"
pattern = r"Python"
match = re.search(pattern, text)
if match:
    print("Found:", match.group())  # 输出: Found: Python

(2)re.match() - 从字符串开头匹配

python 复制代码
import re
text = "Python is awesome"
pattern = r"Python"
match = re.match(pattern, text)
if match:
    print("Match found:", match.group())  # 输出: Match found: Python

# 若 text = "I love Python",则 match 为 None

(3)re.findall() - 返回所有匹配项的列表

python 复制代码
import re
text = "apple 12, banana 3, cherry 45"
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出: ['12', '3', '45']

(4)re.finditer() - 返回匹配项的迭代器(适合大文本)

python 复制代码
import re
text = "a=1, b=2, c=3"
matches = re.finditer(r'\w+=\d+', text)
for match in matches:
    print(match.group())  # 输出: a=1, b=2, c=3

(5)re.sub() - 替换匹配内容

python 复制代码
import re
text = "2023-10-05"
new_text = re.sub(r'-', '/', text)
print(new_text)  # 输出: 2023/10/05

# 使用函数处理替换内容
def double_number(match):
    return str(int(match.group()) * 2)

text = "Score: 5, Count: 3"
result = re.sub(r'\d+', double_number, text)
print(result)  # 输出: Score: 10, Count: 6

(6)re.split() - 按正则表达式分割字符串

python 复制代码
import re
text = "one,two;three four"
parts = re.split(r'[,; ]+', text)
print(parts)  # 输出: ['one', 'two', 'three', 'four']

2 参数数量/类型/默认值指定

直接通过一个综合案例说明:

python 复制代码
from typing import Union, Optional, Any

def generate_user_card(
    username: str,  # 必选参数(无默认值)
    age: int = 18,  # 必选但有默认值(可省略)
    *hobbies: str,  # 不定数量的位置参数(爱好)
    country: Optional[str] = "未知",  # 可选关键字参数(允许None)
    **extra_info: Union[str, int, float]  # 不定数量的关键字参数(扩展信息)
) -> dict[str, Any]:
    """
    生成用户信息卡,支持灵活参数输入
    """
    user_data = {
        "username": username,
        "age": age,
        "hobbies": hobbies if hobbies else ("无",),
        "country": country,
        "extra": extra_info
    }
    return user_data

(1)基础调用:

python 复制代码
result1 = generate_user_card("Alice")
print(result1)
# {'username': 'Alice', 'age': 18, 'hobbies': ('无',), 'country': '未知', 'extra': {}}

(2)额外信息传入:

python 复制代码
result3 = generate_user_card(
    "Charlie",
    age=30,
    country=None,  # 明确设置为None
    email="[email protected]",
    score=95.5
)
print(result3["extra"])
# {'email': '[email protected]', 'score': 95.5}

3 引用传递和值传递说明

在 Python 中,变量传递的本质是 对象引用的传递‌,所有操作都是基于对象的引用(可以理解为"指针")。

  • 不可变对象‌(int, float, str, tuple 等)

    传递的是对象的引用,但修改时会创建新对象,原始对象不受影响(类似"值传递"的效果)。

  • ‌可变对象‌(list, dict, set, 自定义类实例等)

    传递的是对象的引用,修改内容时会影响原始对象(类似"引用传递"的效果)。

案例说明1

python 复制代码
def modify_data(num: int, lst: list, obj: object):
    num += 10      # 不可变对象:创建新对象
    lst.append(4)  # 可变对象:修改原对象
    obj.value = 5  # 可变对象:修改原对象

# 初始化数据
original_num = 5
original_list = [1, 2, 3]
class MyClass:
    def __init__(self):
        self.value = 0
original_obj = MyClass()

# 调用函数
modify_data(original_num, original_list, original_obj)

print(original_num)    # 输出 5(未改变)
print(original_list)   # 输出 [1, 2, 3, 4](已改变)
print(original_obj.value)  # 输出 5(已改变)

案例2

python 复制代码
class DataHolder:
    def __init__(self, data):
        self.data = data  # data 是可变/不可变对象的引用

# 不可变对象操作
holder1 = DataHolder(10)
temp = holder1.data
temp += 5  # 创建新对象,不影响原数据
print(holder1.data)  # 输出 10

# 可变对象操作
holder2 = DataHolder([1, 2])
holder2.data.append(3)  # 直接修改原对象
print(holder2.data)     # 输出 [1, 2, 3]

案例3:修改和赋值的本质区别

python 复制代码
a = [1, 2]
b = a       # 引用传递(指向同一对象)
b.append(3) # 修改原对象
print(a)    # 输出 [1, 2, 3]

c = [4, 5]
d = c
d = [6, 7]  # 创建新对象(重新绑定引用)
d.append(10)
print(c)    # 输出 [4, 5](原对象未变)

注意,这里:

lst = lst + (创建新列表,不影响原对象)

lst.append(4)(原地修改,影响原对象)

案例4:默认参数陷阱

python 复制代码
# 错误示例:默认参数为可变对象
def buggy_func(data=[]):  # 默认列表会持续保留
    data.append(1)
    return data

# 正确做法
def safe_func(data=None):
    data = data if data is not None else []
    data.append(1)
    return data

错误案例的进一步测试:

python 复制代码
def func(data=[]):
    data.append(1)
    return data

func()
data = func()
data.append(10)
func()
print(data) # 输出:[1, 1, 10, 1]

4 排列组合 itertools

tee 生成迭代器副本(副本的修改不影响原始数据)

islice 切片
zip_longest 合并多个迭代器

python 复制代码
import itertools

l = [1,2,3,4]
iter1, iter2 = itertools.tee(l, 2)
for x in iter1:
# 
itertools.zip_longest()

5 内置变量/特殊变量

5.1 内置变量

python所有的内置变量:

python 复制代码
dir(__builtins__)

__name__

如果当前运行的python文件为主文件,则该文件:
__name__ == __main__

如果当前文件被其他文件调用,则该文件:
__name__ == [文件名](不带.py后缀)
参考文章

5.2 类相关的特殊属性

__slots__

限制class可绑定的类的属性。

python 复制代码
__slots__ = ['属性名1','属性名2','属性名3']

定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
__init__

类默认构造函数 ,第一个参入参数为self
__lt__

@property装饰器

将方法变成属性调用。
__str__

6 try-except-else-finally机制

6.1 基础用法

python 复制代码
try:
    with open('example.txt', 'r') as file:
        content = file.read()
        print(content)
except FileNotFoundError:
    print("文件未找到,请检查文件路径是否正确。")
except PermissionError:
    print("没有权限读取该文件。")
except Exception as e:
    # 捕获所有其他类型的异常
    print(f"发生了一个错误:{e}")

try: 放置可能引发异常的代码。'

except:如果try中的代码引发异常,会跳转到指定的except 块儿中

as: as e是可选的,允许你将异常实例赋值给变量e,这样就可以在except块中访问到异常信息。

Exception :代表不指定异常类型(反之捕获所有异常)

Python会按照except块的顺序检查,一旦找到匹配的异常类型,就会执行该块中的代码,并且跳过后续的except块。

6.2 else-finally

python 复制代码
try:
    # 尝试执行的代码
    pass
except SomeException:
    # 处理异常的代码
    pass
else:
    # 如果没有异常发生,执行这里的代码
    pass
finally:
    # 无论是否发生异常,都执行这里的代码
    pass

else:如果你想要在没有异常发生时执行一些代码,可以使用else块。它紧跟在所有的except块之后,只有在try块没有引发任何异常时才会执行。

finally:无论是否发生异常,finally块中的代码都会被执行。这通常用于执行一些清理工作,比如关闭文件或释放资源。

6.3 向上一级抛出错误

raise [error]

注意:如果不抛出错误,程序在执行换except后就会退出吗?

当except块内部的操作执行完成后,程序并不会自动退出,除非你在except块中显式地调用了sys.exit()、exit()、os._exit()等函数来终止程序,或者异常没有被捕获并且传播到了程序的顶层(即没有被任何try块捕获)。

7 Threading - 线程(不是进程,创建进程我用的少)

感谢大佬的总结:

https://liaoxuefeng.com/books/python/process-thread/thread/index.html

说实话,之前只用过C thread,没用过python。

这里对大佬的 文章列出一些关键点:

(1)启动一个线程就是把一个函数传入并创建Thread实例,然后==调用start()==开始执行。

(2)在Python中,可以使用多线程,但不要指望能有效利用多核

python 复制代码

有一些久远的记忆似乎在逐渐复苏

7.1 讲到线程,就不得不谈线程通信

线程的特点就是,共享资源,任务间需要频繁通信。

线程的关键点就是:通信和同步。

要避免的问题:死锁

(1)互斥锁

(2)信号量

(3)条件变量

(4)事件

(5)消息队列

(6)管道

8 路径操作及路径索引 glob

主要利用glob2库

python 复制代码
from glob2 import glob
    paths = glob(file_path) # 搜索文件file_path下所有文件,返回list变量
	# 返回该路径下所有文件
相关推荐
niuniu_66627 分钟前
selenium应用测试场景
python·selenium·测试工具·单元测试·测试
光军oi27 分钟前
Mysql从入门到精通day5————子查询精讲
android·数据库·mysql
满怀10151 小时前
Python扩展知识详解:lambda函数
开发语言·python
qr9j422332 小时前
Django自带的Admin后台中如何获取当前登录用户
数据库·django·sqlite
cherry52302 小时前
【PostgreSQL】【第4章】PostgreSQL的事务
数据库·postgresql
蓝博AI3 小时前
基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)
pytorch·python·cnn
牧歌悠悠5 小时前
【Python 算法】动态规划
python·算法·动态规划
IT成长日记6 小时前
【MySQL基础】聚合函数从基础使用到高级分组过滤
数据库·mysql·聚合函数
Doris Liu.7 小时前
如何检测代码注入(Part 2)
windows·python·安全·网络安全·网络攻击模型