廖雪峰python教程整理

廖雪峰python教程整理python 基础数据类型与变量用 r 表示内部字符不转义 eg printr t 用 的格式表示多行内容 eg print line1 换行 line2 换行 line3 用大写的变量名表示常量字符编码源码包含中文时 前面加两句 usr bin envpython coding utf 8 格式化输出 Hi s you

python基础

  • 数据类型与变量
    • 用r’ ‘表示内部字符不转义,eg:print r’\\t\’
    • 用”’ ”’的格式表示多行内容,eg:print ”’line1换行line2换行line3”’
    • 用大写的变量名表示常量
  • 字符编码
    • 源码包含中文时,前面加两句:#!/usr/bin/env python # -*- coding: utf-8 -*-
    • 格式化输出: ‘Hi, %s, you have $%d.’ % (‘Michael’, )
    • 如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串
  • list和tuple
    • list,可变,用 []
      • append追加元素到末尾:classmates.append(‘Adam’)
      • insert插入元素到指定位置:classmates.insert(1, ‘Jack’)
      • 要删除list末尾的元素,用pop(),要删除指定位置的元素,用pop(i)
    • tuple,不可变,用()
      • 只有1个元素的tuple定义时必须加一个逗号,,来消除歧义,eg t = (1,)
      • tuple的每个元素,指向永远不变,但是你要把元素设为可变的list也没办法
  • 循环的范围
    • Python提供一个range()函数,可以生成一个整数序列,比如range(5)生成的序列是从0开始小于5的整数,即0,1,2,3,4
  • dict和set
    • dict
      • dict使用键-值(key-value)存储,用大括号,d = {‘Michael’: 95, ‘Bob’: 75, ‘Tracy’: 85}
      • 把数据放入dict,还可以通过key放入,eg:d[‘Adam’] = 67
      • 避免key不存在的错误
        • 通过in判断key是否存在:’Thomas’ in d
        • 通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:d.get(‘Thomas’, -1)
      • 要删除一个key,用pop(key)
      • dict的key必须是不可变对象
    • set ([])
      • set是一组不重复key的集合,不存储value,重复元素会被自动过滤
      • 通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果
      • 通过remove(key)方法可以删除元素
      • set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作
      • set和dict一样,key必须是不可变对象,可以是tuple

函数

  • 如果想定义一个什么事也不做的空函数,可以用pass语句,可以占个位
  • 数据类型检查可以用内置函数isinstance
  • 函数可以同时返回多个值,但其实就是一个tuple
  • 函数的参数
    • 默认参数
      • 必选参数在前,默认参数在后
      • 当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数
      • 默认参数必须指向不变对象
    • 可变参数,一个星号
      • 传入的参数个数是可变的,在参数前面加了一个*号,eg:def calc(*numbers):
      • 如果已经有一个list或者tuple,要调用一个可变参数,在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去,eg:calc(*nums)
    • 关键字参数,两个星号
      • 允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict,eg:def person(name, age, kw),该函数除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数
      • 也可以传入任意个数的关键字参数
    • 参数组合
      • 参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数
      • 使用*args和kw是Python的习惯写法
  • 递归函数
    • 递归调用栈溢出的解决办法:尾递归优化,和循环效果一样

高级特性

  • 切片(Slice)操作符取指定索引范围,对list和tuple和字符串都可以进行切片
  • 迭代(Iteration):通过循环遍历list或tuple或其他可迭代对象(字符串等)上
    • 默认情况下,dict迭代的是key,而且迭代出的结果顺序很可能不一样
      • 如果要迭代value,可以用for value in d.itervalues()
      • 如果要同时迭代key和value,可以用for k, v in d.iteritems()
    • 判断是否可迭代:通过collections模块的Iterable类型判断
    • 实现list的下标循环:enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身
  • 列表生成式(List Comprehensions):python内置的可以用来创建list的生成式
    • 写列表生成式时,把要生成的元素放到前面,后面跟for循环,就可以把list创建出来
    • for循环后面还可以加上if判断
    • 还可以使用两层循环,可以生成全排列
  • 生成器(Generator):一边循环一边计算的机制,它保存的是算法
    • 创建方法:
      • 法一:只要把一个列表生成式的[]改成()
      • 法二:创建generator函数
    • 打印其中元素的方法:
      • 法一:用next(),基本不用。每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误
      • 法二:for循环迭代
      • 法三:for没法解决的,用函数实现
        • 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
        • generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

函数式编程(Functional Programming)

  • 一种抽象程度很高的编程范式,特点:允许把函数本身作为参数传入另一个函数,还允许返回一个函数
  • 高阶函数(Higher-order function)
    • 变量可以指向函数
    • 函数名其实就是指向函数的变量
    • 高阶函数:接收另一个函数作为参数的函数
    • map/reduce
      • map():接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回
      • reduce():reduce把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
    • filter()函数用于过滤序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
    • sorted()函数可以对list进行排序,它还可以接收一个比较函数来实现自定义的排序
  • 返回函数:把函数作为结果值返回
    • 返回的函数并没有立刻执行,而是直到调用了f()才执行
    • 闭包(Closure):返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用
    • 返回函数不要引用任何循环变量,或者后续会发生变化的变量
    • 要是非要引用循环变量,应该再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变
  • 匿名函数:没名字的函数
    • 用关键字lambda表示,冒号前面的x表示函数参数
    • 限制:只能有一个表达式,不用写return,返回值就是该表达式的结果
    • 好处:不用担心函数名冲突
    • 可以把匿名函数赋值给一个变量,再利用变量来调用该函数
    • 也可以把匿名函数作为返回值返回
  • 装饰器(Decorator):在代码运行期间动态增加功能的方式,借助@语法,把decorator置于要扩充函数的定义处
    • 函数对象有一个__name__属性,可以拿到函数的名字
    • 在定义wrapper()的前面加上@functools.wraps(func)
  • 偏函数(Partial function):
    • functools.partial() 把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
    • 创建偏函数时,实际上可以接收函数对象、*args和kw这3个参数
    • 当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单

模块:

一个.py文件就称之为一个模块(Module)

  • 好处:
    • 大大提高了代码的可维护性
    • 编写代码不必从零开始
    • 还可以避免函数名和变量名冲突
  • 注意:尽量不要与内置函数名字冲突
  • 避免模块名字冲突的方法:包(Package)
    • 每一个包目录下面都必须有一个__init__.py的文件,否则,Python就把这个目录当成普通目录,而不是一个包
    • 可以有多级目录,组成多级层次的包结构
  • 使用模块:
    • import
    • 使用别名import … as …
    • 作用域
      • 正常的函数和变量名是公开的(不带_)可以被直接引用
      • 类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途
      • 类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用
      • 外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public
  • 安装第三方模块:第三方库都会在Python官方的pypi.python.org网站注册,要安装一个第三方库,必须先知道该库的名称,可以在官网或者pypi上搜索
    • 模块搜索路径:默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中
      • 法一:直接修改sys.path,添加要搜索的目录,sys.path.append(‘ ‘),这种方法是在运行时修改,运行结束后失效
      • 法二:设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中
  • 使用__future__模块,把下一个新版本的特性导入到当前版本,于是我们就可以在当前版本中测试一些新版本的特性

面对对象编程(Object Oriented Programming),OOP

  • OP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数
    • 对象包含属性(Property)
    • 对象的方法(Method):方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据
    • 三大特点:数据封装、继承和多态
    • 思想:面向对象的设计思想是抽象出Class,根据Class创建Instance
    • 类和实例:
      • 类(Class):自定义的对象数据类型,类名通常是大写开头的单词
      • (object),表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类
      • 通过定义一个特殊的__init__方法,在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去
        • 注意到__init__方法的第一个参数永远是self,表示创建的实例本身
        • 有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传
      • 在类中定义的函数,第一个参数永远是实例变量self
      • Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同
    • 访问限制:
      • 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
      • 以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量
      • 以一个下划线开头的实例变量名,意思是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”
    • 继承和多态:
      • 继承的好处:
        • 子类获得了父类的全部功能,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重
        • 多态:
          • 多态的好处:调用方只管调用,不管细节,即开闭原则:对扩展开放,对修改封闭
    • 获取对象信息:
      • type()
        • 可以获得对象类型,返回的是type类型
        • Python把每种type类型都定义好了常量,放在types模块
        • 所有类型本身的类型就是TypeType
      • isinstance()
        • isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上
        • 还可以判断一个变量是否是某些类型中的一种
      • dir()
        • 列出一个对象的所有属性和方法
        • 配合getattr()、setattr()以及hasattr(),可以直接操作一个对象的状态
          • getattr():获取对象的属性,如果试图获取不存在的属性,会抛出AttributeError的错误,可以传入一个default参数,如果属性不存在,就返回默认值
          • setattr():给对象设置一个属性
          • hasattr():判断是否有某个属性

面向对象高级编程

  • 使用__slots__限制该class能添加的属性
    • __slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的
    • 除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__
  • 使用@property,保证对属性的必要检查
    • 该装饰器就是负责把一个方法变成属性来调用
    • 把一个getter方法变成属性,只需要加上@property就可以
    • @property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
    • 只读属性:只定义getter方法,不定义setter方法就是一个只读属性
  • 多重继承
    • 通过多重继承,一个子类就可以同时获得多个父类的所有功能
    • Mixin:用多重继承的一种常见设计
      • 目的:给一个类增加多个功能
      • 好处:不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类
  • 定制类:让自己定义的类表现得和Python自带的list、tuple、dict没什么区别
    • __len__()方法用于让class作用于len()函数
    • __str__()返回用户看到的字符串,可以打印出好看的字符串
    • __repr__()返回程序开发者看到的字符串,为调试而服务的
    • __iter__(),一个类要是想被用于for循环中,就要实现这个方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环
    • __getitem__(),实现这个方法可以让该类像list一样按照下标取出元素,把对象视作list或dict来对集合赋值,它传入的参数可能是一个int,也可能是一个切片对象slice
    • __delitem__()方法,用于删除某个元素
    • __getattr__(),只有在没有找到属性的情况下,才调用该方法,默认返回None,如果要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误
    • __call__(),用于直接对实例进行调用
      • 函数和对象的界限是很模糊的
      • 通过callable()函数,就可以判断一个对象是否是“可调用”对象,比如函数和带有__call()__的类实例
  • 使用元类
    • type():
      • 既可以返回一个对象的类型,也可以创建新的类型,创建要传入的参数:
        • \1. class的名称;
        • \2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
        • \3. class的方法名称与函数绑定
        • 大多数情况还是用class定义类,type函数允许动态创建类
    • metaclass(元类):
      • 先定义metaclass,就可以创建类,最后创建实例
      • metaclass允许你创建类或者修改类
      • 要通过元类的__new__()的指示来创建新类,新类具有元类的方法
      • 需要通过metaclass修改类定义的场合:ORM(Object Relational Mapping,对象-关系映射),就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表
      • 千万不要把实例属性和类属性使用相同的名字

错误、调试和测试

  • 错误处理:
    • try机制:
      • 当我们认为某些代码可能会出错时,就可以用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,执行完except后,如果有finally语句块,则执行finally语句块
      • 可以有多个except来捕获不同类型的错误
      • 如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句
      • Python的错误其实也是class,所有的错误类型都继承自BaseException,一旦在except中先使用这个类型,别的错误都捕捉不到了,比如ValueError是StandardError的子类
      • 好处:跨越多层调用,于是可以只在合适的层捕获错误即可,不用每个都写
    • 调用堆栈:如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出;可以通过打印出的错误信息来追踪错误源头
    • 抛出错误:
      • 自己定义错误class,用raise抛出
      • 只有在必要的时候才定义自己的错误类型,尽量使用python内置的错误类型
    • 错误类型转换:
      • 在except中raise一个error,可以把一个类型的错误转化成另一种类型,只要是合理的转换逻辑即可;
      • 但是,决不应该把一个IOError转换成毫不相干的ValueError
      • raise语句如果不带参数,就会把当前错误原样抛出
  • 调试:调试程序的手段
    • \1. 用print打印可能有问题的变量
      • 坏处:将来还要删掉
    • \2. 断言:
      • 用print来辅助查看的地方,都可以用assert代替
      • assert A, ‘B’,表达式A应该是True,否则会抛出AssertionError并打印B
      • 启动Python解释器时可以用-O参数来关闭assert
    • \3. logging:不会抛出错误,而且可以输出到文件
      • 好处:可以指定记录信息的级别,比如debug、info、warning、error等,于是可以统一控制输出哪个级别的信息
    • \4. pdb:启动调试器pdb,单步运行程序
      • 以参数-m pdb启动后,输入命令l来查看代码
      • 输入命令n可以单步执行代码
      • 任何时候都可以输入命令p 变量名来查看变量
      • q结束调试
      • 坏处:代码一长就麻烦了
    • \5. pdb.set_trace():需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点
      • 程序会自动在pdb.set_trace()暂停并进入pdb调试环境,可以用命令p查看变量,或者用命令c继续运行
    • \6. 使用支持调试功能的IDE比如Pycharm
  • 单元测试:
    • 单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作
    • 需要引入Python自带的unittest模块,对每一类测试都需要编写一个test_xxx()方法
    • 运行方法:两种
  • 文档测试:doctest非常有用,不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest

IO编程

  • 文件读写
    • 读文件:默认都是读取文本文件,并且是ASCII编码的文本文件
      • 用Python内置的open()函数,传入文件名和标示符,标示符’r’表示读
      • 如果文件不存在,open()函数就会抛出一个IOError的错误
      • 如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示
      • 最后一步是调用close()方法关闭文件
      • 为了保证无论是否出错都能正确地关闭文件,可以使用try … finally来实现,但是很繁琐,所以一般都用with语句
      • 保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容
      • 调用readline()可以每次读取一行内容
      • 调用readlines()一次读取所有内容并按行返回list
    • file-like Object
    • 二进制文件:比如图片、视频等等,用’rb’模式打开文件即可
    • 字符编码:
      • 要读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码,麻烦
      • Python还提供了一个codecs模块帮我们在读文件时自动转换编码,直接读出unicode
    • 写文件:
      • 调用open()函数时,传入标识符’w’或者’wb’表示写文本文件或写二进制文件
      • 一定要用f.close()来关闭文件
      • 用with语句来得保险
  • 操作文件和目录:import os模块
    • 环境变量:
      • 全部保存在os.environ这个dict中
      • 要获取某个环境变量的值,可以调用os.getenv()函数
    • 操作文件和目录:操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中
      • 查看当前目录的绝对路径:os.path.abspath(‘.’)
      • 在某个目录下创建一个新目录
        • 首先把新目录的完整路径表示出来:os.path.join(‘/Users/michael’, ‘testdir’)
        • 然后创建一个目录:os.mkdir(‘/Users/michael/testdir’)
        • 删除目录:rmdir
      • 合并拆分路径:并不要求目录和文件要真实存在,它们只对字符串进行操作
        • os.path.join():可以正确处理不同操作系统的路径分隔符
        • os.path.split():可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名
        • os.path.splitext()可以直接让你得到文件扩展名
      • 文件操作:
        • 对文件重命名:os.rename()
        • 删除文件:os.remove()
        • 复制文件:用shutil模块提供的copyfile()的函数
        • 过滤文件:
          • 列出当前目录下的所有目录:[x for x in os.listdir(‘.’) if os.path.isdir(x)]
          • 要列出所有的.py文件:[x for x in os.listdir(‘.’) if os.path.isfile(x) and os.path.splitext(x)[1]==’.py’]
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201842.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午8:29
下一篇 2026年3月20日 上午8:29


相关推荐

  • 欧拉图&哈密顿图详解

    欧拉图&哈密顿图详解欧拉图 小声 bb 又是一些无聊的概念性知识 存在欧拉回路的无向图被称为欧拉图 有欧拉通路 但无欧拉回路的图被称为半欧拉图 欧拉回路 若存在一条从起点 S 出发的路径 每条边恰好只走一次 最终回到起点 S 欧拉路径 若存在一条从起点 S 出发的路径 经过每条边一次 但是不要求回到起点 S 类似一笔画 欧拉回路和欧拉路径的判断根据顶点的度数来判断 关于顶点的度数讲拓扑排序的时候已经说了

    2026年3月19日
    2
  • Android Studio(AS)–>导入项目

    Android Studio(AS)–>导入项目博文更新2015-10-22:AndroidStudio1.4版本开始,可以直接打开Eclipse项目;1:首先,你必须要有一个工程(Project),才可以打开项目(Module);(注意:Eclipse中的Workspace对应AndroidStudio中的Project,Eclipse中的Project对应AndroidStudio中的Module,);

    2022年5月10日
    47
  • C语言 按位异或运算

    C语言 按位异或运算按位异或运算:规律:无论0或1,异或1取反,异或0不变变量交换:题一:给定两个数a和b,用异或运算交换它们的值。思路:1)中间量t=a^b2)b=tb,相当于abb,根据异或性质知道ab^b=a,所以b=t^b就是b=a(异或性质:异或两次不变)3)a=t^a,道理同上出现奇数次的数:题二:输入n个数,其中只有一个数出现了奇数次,其它所有数都出现了偶数次。求这个出现了奇数次的数。思路:根据异或的性质,两个一样的数异或结果为零。也就是所有出现偶数

    2022年5月25日
    46
  • 900万!!!!!!!!这也太强了吧!!!我的老天!!!!!!!!!!

    900万!!!!!!!!这也太强了吧!!!我的老天!!!!!!!!!!大家好,我是二哥呀!之前在送书的时候做了一个小调查,问题是:“你是怎么认识二哥的?”我以为从知乎上了解的多一些,没想到,CSDN上的最多,看来二哥还是在CSDN上更有影响力一些,这个结果多少让我感到有些意外,因为我最近在知乎上更新得更勤快一些。写这篇文章的时候,我去CSDN上看了一眼我的主页。访问量突破了900万!按照目前的增长速度来看,年底突破1000万访问量应该没啥大问题。另外还有一些数据我觉得也挺牛逼的:原创文章数量957篇;作者总榜第12名;作者周榜第

    2022年6月7日
    30
  • Photobucket不能用了怎么办?推荐10个在线图片储存服务!

    Photobucket不能用了怎么办?推荐10个在线图片储存服务!近日 图片共享服务网站 Photobucket 更新了政策 要求用户缴纳 399 美元的年费 才能使用第三方网站图片储存服务 由于 Photobucket 出台这一政策 亚马逊及其他电商平台上相关的产品图片已被删除 取而代之的是要求账号更新的图片 除了许多论坛和博客外 eBay 和 Etsy 也受到了影响 那么 除了 Photobucket 这一图片储存服务之外 电商卖家们还有哪些其他的选择呢 本文列出了 10 个目

    2026年3月19日
    3
  • 【MyBatis学习13】MyBatis中的二级缓存[通俗易懂]

    【MyBatis学习13】MyBatis中的二级缓存[通俗易懂]1.二级缓存的原理  前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的。为了更加清楚的描述二级缓存,先来看一个示意图:  从图中可以看出:sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到该UserMapper的二级缓存中。

    2025年11月24日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号