Python基础语法详解(第一篇)

目录

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

    1 正则匹配

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

    注意点1

    注意:在Python中使用正则表达式时要优先使用原始字符串。
    (也就是说,字符串不会被python语言解析。而只会被re库里的函数解析)

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

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

    以下为错误案例1:

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

    正确写法:

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

    使用原始字符串的写法:

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

    以下为错误案例2:

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

    正确写法:

    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()–搜索第一个匹配项

    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() – 从字符串开头匹配

    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() – 返回所有匹配项的列表

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

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

    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() – 替换匹配内容

    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() – 按正则表达式分割字符串

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

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

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

    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)基础调用:

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

    (2)额外信息传入:

    result3 = generate_user_card(
        "Charlie",
        age=30,
        country=None,  # 明确设置为None
        email="charlie@example.com",
        score=95.5
    )
    print(result3["extra"])
    # {'email': 'charlie@example.com', 'score': 95.5}
    
    

    3 引用传递和值传递说明

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

  • 不可变对象‌(int, float, str, tuple 等)
    传递的是对象的引用,但修改时会创建新对象,原始对象不受影响(类似“值传递”的效果)

  • ‌可变对象‌(list, dict, set, 自定义类实例等)
    传递的是对象的引用,修改内容时会影响原始对象(类似“引用传递”的效果)

  • 案例说明1

    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

    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:修改和赋值的本质区别

    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:默认参数陷阱

    # 错误示例:默认参数为可变对象
    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
    

    错误案例的进一步测试:

    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 合并多个迭代器

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

    5 内置变量/特殊变量

    5.1 内置变量

    python所有的内置变量:

    dir(__builtins__)
    

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

    5.2 类相关的特殊属性

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

    __slots__ = ['属性名1','属性名2','属性名3']
    

    定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
    除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
    __init__
    类默认构造函数 ,第一个参入参数为self
    __lt__
    @property装饰器
    将方法变成属性调用。
    __str__

    6 try-except-else-finally机制

    6.1 基础用法

    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

    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中,可以使用多线程,但不要指望能有效利用多核

    
    

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

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

    线程的特点就是,共享资源,任务间需要频繁通信。
    线程的关键点就是:通信和同步。
    要避免的问题:死锁
    (1)互斥锁
    (2)信号量
    (3)条件变量
    (4)事件
    (5)消息队列
    (6)管道

    8 路径操作及路径索引 glob

    主要利用glob2库

    from glob2 import glob
        paths = glob(file_path) # 搜索文件file_path下所有文件,返回list变量
    	# 返回该路径下所有文件
    
    

    作者:弈风千秋万古愁

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python基础语法详解(第一篇)

    发表回复