Python基础 (字符串 列表 元组 字典 序列遍历 文件操作 函数)
Python基础入门
1.Python 介绍
注:这里的Python一律指cpython
Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。
Python是跨平台的。
Python 官网:https://www.python.org/
Python 安装:https://www.cnblogs.com/0bug/p/11942492.html
2.变量
01.声明变量
使用等号 "=" 声明变量,将等号右边的值赋给左边。
1 | age = 18 |
02.变量定义规则
1.变量名可以由字母、数字、下画线(_)组成,其中数字不能打头。(此处的字母并不局限于 26 个英文字母,可以包含中文字符、日文字符等 )
2.变量名不能是 Python 关键字,但可以包含关键字。
3.变量名不能包含空格。

>>> import keyword >>> >>> keyword.kwlist ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', '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']
03.变量的命名规范
1.小驼峰法 :第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母。
例如:
1 | myFirstName |
2.下划线分割:用下划线链接多个小写字母。
例如:
1 | my_first_name |
3.常量
常量通俗讲就是值不变的量,通常使用大写字母定义
例如:
1 | SECRET_KEY = "234567WERTYSDFGxscv@#$" |
4.注释
单号注释使用井号,多行注释使用三引号
1 2 3 4 5 6 | # 我是单行注释 "" " 我是 多行注释 "" " '' '我也是多行注释' '' |
5.基础数据类型
程序运行时,要将程序数据写入内存中,那么我们需要为一个程序开辟多大的内存空间呢?先来看一个生活中的例子,例如,我们要运送一台电脑,大卡车和小轿车都可以完成,但是,如果使用大卡车运送一台电脑,显然有点小题大做,浪费空间。
同理,存储数据时,为了更充分利用内存空间,就需要针对不同类型数据,开辟不同大小的内存空间,这个事情Python内部已经为我们实现了,Python可以识别变量的数据类型。
Python中常见的数据类型:
1.数字型
Python中的数字类型包含整型、浮点型和复数类型。示例代码如下:
1 2 3 | 整 型:0101 83 -239 0x80 299384938832 浮点型:3.14154 2E-10 -2.34E-19 复数类型:3.12+1.23j -1.23-98j |
2.布尔类型
布尔类型是特殊的整型,它的值只有两个,分别是True和Fase。如果将布尔值进行数值运算,True会被当作整型1,Fase会被当作整型0。
3.字符串类型
Python中的字符串被定义为一个字符集合,它被引号所包含,引号可以是单引号、双引号或者三引号(三个连续的单引号或者双引号)。
1 2 3 | string_one = 'Python' string_two = '' Python '' string_three = '' 'Python' '' |
4.其他类型
列表、元组、字典、集合...
6.格式化符号 %
Python 支持格式化字符串的输出 。最基本的用法是将一个值插入到一个有字符串格式符 %s 的字符串中。
1 | print( "My name is %s and weight is %d kg!" ) % ( 'li' , 21) |
python 字符串格式化符号:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | "" " %c 格式化字符及其ASCII码 %s 格式化字符串 %d 格式化整数 %u 格式化无符号整型 %o 格式化无符号八进制数 %x 格式化无符号十六进制数 %X 格式化无符号十六进制数(大写) %f 格式化浮点数字,可指定小数点后的精度 %e 用科学计数法格式化浮点数 %E 作用同%e,用科学计数法格式化浮点数 %g %f和%e的简写 %G %F 和 %E 的简写 %p 用十六进制数格式化变量的地址 "" " |
格式化操作符辅助指令:
1 2 3 4 5 6 7 8 9 10 | "" " * 定义宽度或者小数点精度 - 用做左对齐 + 在正数前面显示加号( + ) <sp> 在正数前面显示空格 # 在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于用的是'x'还是'X') 0 显示的数字前面填充 '0' 而不是默认的空格 % '%%' 输出一个单一的 '%' ( var ) 映射变量(字典参数) m.n. m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话) "" " |
7.基本运算符
1.算术运算符
下面以a=10 ,b=20为例进行计算
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 两个对象相加 a + b 输出结果 30 |
- | 减 | 得到负数或是一个数减去另一个数 a - b 输出结果 -10 |
* | 乘 | 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200 |
/ | 除 | x除以y b / a 输出结果 2 |
// | 取整除 | 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 |
% | 取余 | 返回除法的余数 b % a 输出结果 0 |
** | 幂 | 返回x的y次幂 a**b 为10的20次方, 输出结果 100000000000000000000 |
1 2 3 4 | >>> 9 / 2.0 4.5 >>> 9 / / 2.0 4.0 |
2.赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 赋值运算符 | 把=号右边的结果给左边的变量 num=1+2*3 结果num的值为7 |
1 2 3 4 5 | >>> a, b = 1 , 2 >>> a 1 >>> b 2 |
3.复合赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
4.逻辑运算符
Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20:
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 | (a and b) 返回 20。 |
or | x or y | 布尔"或" - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。 | (a or b) 返回 10。 |
not | not x | 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 | not(a and b) 返回 False |
5.位运算符
按位运算符是把数字看作二进制来进行计算的。Python中的按位运算法则如下:
下表中变量 a 为 60,b 为 13,二进制格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | a = 0011 1100 b = 0000 1101 - - - - - - - - - - - - - - - - - a&b = 0000 1100 a|b = 0011 1101 a^b = 0011 0001 ~a = 1100 0011 |
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 | (a & b) 输出结果 12 ,二进制解释: 0000 1100 |
| | 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 | (a | b) 输出结果 61 ,二进制解释: 0011 1101 |
^ | 按位异或运算符:当两对应的二进位相异时,结果为1 | (a ^ b) 输出结果 49 ,二进制解释: 0011 0001 |
~ | 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x 类似于 -x-1 | (~a ) 输出结果 -61 ,二进制解释: 1100 0011,在一个有符号二进制数的补码形式。 |
<< | 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。 | a << 2 输出结果 240 ,二进制解释: 1111 0000 |
>> | 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数 | a >> 2 输出结果 15 ,二进制解释: 0000 1111 |
进制转换与位运算:http://www.cnblogs.com/0bug/p/8696126.html
6.成员运算符
除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回 True,否则返回 False。 | x 在 y 序列中 , 如果 x 在 y 序列中返回 True。 |
not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 | x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。 |
7.比较运算符
以下假设变量a为10,变量b为20:
运算符 | 描述 | 实例 |
---|---|---|
== | 等于 - 比较对象是否相等 | (a == b) 返回 False。 |
!= | 不等于 - 比较两个对象是否不相等 | (a != b) 返回 true. |
<> | 不等于 - 比较两个对象是否不相等 | (a <> b) 返回 true。这个运算符类似 != 。 |
> | 大于 - 返回x是否大于y | (a > b) 返回 False。 |
< | 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。 | (a < b) 返回 true。 |
>= | 大于等于 - 返回x是否大于等于y。 | (a >= b) 返回 False。 |
<= | 小于等于 - 返回x是否小于等于y。 | (a <= b) 返回 true。 |
8.赋值运算符
以下假设变量a为10,变量b为20:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
9.逻辑运算符
Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 | (a and b) 返回 20。 |
or | x or y | 布尔"或" - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。 | (a or b) 返回 10。 |
not | not x | 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 | not(a and b) 返回 False |
10.身份运算符
身份运算符用于比较两个对象的存储单元
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用自一个对象 | x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False |
is not | is not 是判断两个标识符是不是引用自不同对象 | x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。 |
注: id() 函数用于获取对象内存地址。
11.运算符优先级
以下表格列出了从最高到最低优先级的所有运算符:
运算符 | 描述 |
---|---|
** | 指数 (最高优先级) |
~ + - | 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@) |
* / % // | 乘,除,取模和取整除 |
+ - | 加法减法 |
>> << | 右移,左移运算符 |
& | 位 'AND' |
^ | | 位运算符 |
<= < > >= | 比较运算符 |
<> == != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
is is not | 身份运算符 |
in not in | 成员运算符 |
not or and | 逻辑运算符 |
8.输入输出函数 input 和 print
1.输入 input
input 接收的值会被转换为字符串类型
1 2 3 | age = input( "请输入你的年龄:" ) print( "你的年龄是:%s 岁 " % age) print(type(age)) |
这会产生如下的对应着输入的结果:
1 2 3 | 请输入你的年龄:18 你的年龄是:18 岁 < class 'str' > |
2.输出 print
1 2 3 4 5 6 7 8 9 10 11 12 | def print(self, *args, sep= ' ' , end= '\n' , file=None): # known special case of print "" " print(value, ..., sep= ' ' , end= '\n' , file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default . Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. "" " pass |
print 用法示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | a = 'a' b = 'b' c = 'c' print(a, b, c) print(a, b, c, sep= '-' ) print(a, file=open( 'data.txt' , 'w' ), end= "" ) print(b, file=open( 'data.txt' , 'a' )) print(c, file=open( 'data.txt' , 'a' )) "" " 终端打印结果: a b c a-b-c data.txt: ab c "" " |
9.条件判断
Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。
1 2 3 4 5 6 7 8 | if 判断条件1: 执行语句1…… elif 判断条件2: 执行语句2…… elif 判断条件3: 执行语句3…… else : 执行语句4…… |
10.while循环
在给定的判断条件为 true 时执行循环体,否则退出循环体。
循环控制语句可以更改语句执行的顺序。Python支持以下循环控制语句:
1 2 3 4 | "" " break 语句 在语句块执行过程中终止循环,并且跳出整个循环 continue 语句 在语句块执行过程中终止当前循环,跳出该次循环,执行下一次循环。 pass 语句 pass是空语句,表示什么都不做,是为了保持程序结构的完整性。 "" " while 后面的 else 作用是指,当 while 循环正常执行完,中间没有被 break 中止的话,就会执行 else 后面的语句 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | v = 7 while v > 5: print(v) v -= 1 else : print( '此时v不大于5' ) print(v) "" "结果: 7 6 此时v不大于5 5 "" " |
字符编码
1.字符编码
字符编码(英语:Character encoding)也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以1个字节的方式存储。
ASCII的局限在于只能显示26个基本拉丁字母、阿拉伯数字和英式标点符号,因此只能用于显示现代美国英语(且处理naïve、café、élite等外来语时,必须去除附加符号)。虽然EASCII解决了部分西欧语言的显示问题,但对更多其他语言依然无能为力。因此,现在的软件系统大多采用Unicode。
2.编码
在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。那么字母”A”在硬盘上是如何存储的呢?可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。比如小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。小张用的编码表是ASCII,ASCII编码表把26个字母都一一的对应到2进制1和0上;小王用的编码表可能是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不同。一般地说,开放的操作系统(LINUX 、WINDOWS等)采用ASCII 编码,而大型主机系统(MVS 、OS/390等)采用EBCDIC 编码。在发送数据给对方前,需要事先告知对方自己所使用的编码,或者通过转码,使不同编码方案的两个系统可沟通自如。
3.常见编码规则
01.ASCII
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。
ASCII 是这套编码系统的传统命名,IANA 现在更倾向于使用它的新名字 US-ASCII。
ASCII是 IEEE里程碑 之一。
ASCII 由电报码发展而来。第一版标准发布于1963年[3][4],1967年经历了一次主要修订,最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。
ASCII的局限在于只能显示26个基本拉丁字母、阿拉伯数字和英式标点符号,因此只能用于显示现代美国英语(且处理naïve、café、élite等外来语时,必须去除附加符号)。虽然EASCII解决了部分西欧语言的显示问题,但对更多其他语言依然无能为力。因此,现在的软件系统大多采用Unicode。
02.MBCS
为了扩充ASCII编码,以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码,又称为"MBCS(Muilti-Bytes Charecter Set,多字节字符集)"。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,所以在中文 windows下要转码成gb2312,gbk只需要把文本保存为ANSI 编码即可。 不同 ANSI 编
码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。一个很大的缺点是,同一个编码值,在不同的编码体系里代表着不同的字。这样就容易造成混乱。导致了unicode码的诞生。
其中每个语言下的ANSI编码,都有一套一对一的编码转换器,Unicode变成所有编码转换的中间介质。所有的编码都有一个转换器可以转换到Unicode,而Unicode也可以转换到其他所有的编码。
03.GB2312
GB2312 也是ANSI编码里的一种,对ANSI编码最初始的ASCII编码进行扩充,为了满足国内在计算机中使用汉字的需要,中国国家标准总局发布了一系列的汉字字符集国家标准编码,统称为GB码,或国标码。其中最有影响的是于1980年发布的《信息交换用汉字编码字符集 基本集》,标准号为GB 2312-1980,因其使用非常普遍,也常被通称为国标码。GB2312编码通行于我国内地;新加坡等地也采用此编码。几乎所有的中文系统和国际化的软件都支持GB 2312。
04.GBK
GBK即汉字内码扩展规范,K为扩展的汉语拼音中“扩”字的声母。英文全称Chinese Internal Code Specification。GBK编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。GB 2312的出现,基本满足了汉字的计算机处理需要,但对于人名、古汉语等方面出现的罕用字GB 2312不能处理,GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样)。
05.Big5
在台湾、香港与澳门地区,使用的是繁体中文字符集。而1980年发布的GB2312面向简体中文字符集,并不支持繁体汉字。在这些使用繁体中文字符集的地区,一度出现过很多不同厂商提出的字符集编码,这些编码彼此互不兼容,造成了信息交流的困难。为统一繁体字符集编码,1984年,台湾五大厂商宏碁、神通、佳佳、零壹以及大众一同制定了一种繁体中文编码方案,因其来源被称为五大码,英文写作Big5,后来按英文翻译回汉字后,普遍被称为大五码
06.Unicode
如上ANSI编码条例中所述,世界上存在着多种编码方式,在ANSi编码下,同一个编码值,在不同的编码体系里代表着不同的字。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码,可能最终显示的是中文,也可能显示的是日文。在ANSI编码体系下,要想打开一个文本文件,不但要知道它的编码方式,还要安装有对应编码表,否则就可能无法读取或出现乱码。为什么电子邮件和网页都经常会出现乱码,就是因为信息
的提供者可能是日文的ANSI编码体系和信息的读取者可能是中文的编码体系,他们对同一个二进制编码值进行显示,采用了不同的编码,导致乱码。这个问题促使了unicode码的诞生。
如果有一种编码,将世界上所有的符号都纳入其中,无论是英文、日文、还是中文等,大家都使用这个编码表,就不会出现编码不匹配现象。每个符号对应一个唯一的编码,乱码问题就不存在了。这就是Unicode编码。
Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6C49。
Unicode固然统一了编码方式,但是它的效率不高,比如UCS-4(Unicode的标准之一)规定用4个字节存储一个符号,那么每个英文字母前都必然有三个字节是0,这对存储和传输来说都很耗资源。
07.UTF-8
为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。
UTF-8的编码是这样得出来的,以”汉”这个字为例:
“汉”字的Unicode编码是U+00006C49,然后把U+00006C49通过UTF-8编码器进行编码,最后输出的UTF-8编码是E6B189。
08.Base64
Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于{\displaystyle 2^{6}=64}{\displaystyle 2^{6}=64},所以每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使
用不同的64字符集来代表6个二进制数字,但是不被称为Base64。
Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。
Python示例
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 | # 导入 base64模块 import base64 # 给定需要转换的字符串 str1 = "你好哇,李银河" # 需要转成2进制格式才可以转换,所以我们这里再手动转换一下 result1 = base64.b64encode(str1.encode( 'gb2312' )) result2 = base64.b64encode(str1.encode( 'utf8' )) # 打印转换后的结果 print ( '转换后的结果 --> ' , result1) print ( '转换后的结果 --> ' , result2) # 再把加密后的结果解码 temp1 = base64.b64decode(result1) temp2 = base64.b64decode(result2) # 同样的,解码后的结0果是二进制,我们再转换一下 print ( '解密后的结果 --> ' , temp1.decode( 'gb2312' )) print ( '解密后的结果 --> ' , temp2.decode( 'utf8' )) """ 输出结果: 转换后的结果 --> b'xOO6w83bo6zA7tL4utM=' 转换后的结果 --> b'5L2g5aW95ZOH77yM5p2O6ZO25rKz' 解密后的结果 --> 你好哇,李银河 解密后的结果 --> 你好哇,李银河 """ |
Base64在URL中的应用
Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的/和+字符变为形如%XX的形式,而这些%号在存入数据库时还需要再进行转换,因为ANSI SQL中已将%号用作通配符。
为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充=号,并将标准Base64中的+和/分别改成了-和_,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。
另有一种用于正则表达式的改进Base64变种,它将+和/改成了!和-,因为+,*以及前面在IRCu中用到的[和]在正则表达式中都可能具有特殊含义。
此外还有一些变种,它们将+/改为_-或._(用作编程语言中的标识符名称)或.-(用于XML中的Nmtoken)甚至_:(用于XML中的Name)。
为了克服Base64由于输出内容中包括两个以上“符号类”字符(+, /, =等)而带来的互不兼容多变种问题,一种输出内容无符号的Base62x编码方案被引入软件工程领域,Base62x被视为无符号化的Base64改进版本。
数据类型--字符串(String)
Python中的字符串被定义为一个字符集合,它被引号所包含,引号可以是单引号、双引号或者三引号。
1.索引和切片
索引
索引也叫下标(从0开始,最后一个为-1):
1 2 3 4 5 6 7 8 9 | name = 'abcdef' print (name[ 0 ]) # a print (name[ 1 ]) # b print (name[ 2 ]) # c print (name[ - 1 ]) # f print (name[ - 2 ]) # e print (name[ - 3 ]) # d |
切片
切片是指对操作的对象截取其中一部分的操作。字符串、列表、元组都支持切片操作。
切片的语法:[起始:结束:步长]
注意:选取的区间属于左闭右开型,即从"起始"位开始,到"结束"位的前一位结束(不包含结束位本身)。
我们以字符串为例讲解。
如果取出一部分,则可以在中括号[]中,使用:
1 2 3 4 5 | name = 'abcdef' print (name[ 0 : 3 ]) # 取 下标0~2 的字符 abc print (name[ 2 :]) # 取 下标为2开始到最后的字符 cdef print (name[ 1 : - 1 ]) # 取 下标为1开始到最后第2个之间的字符bcde |
其他
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> a = "abcdef" >>> a[: 3 ] 'abc' >>> a[:: 2 ] 'ace' >>> a[ 5 : 1 : 2 ] '' >>> a[ 1 : 5 : 2 ] 'bd' >>> a[:: - 2 ] 'fdb' >>> a[ 5 : 1 : - 2 ] 'fd' |
2.字符串常见操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | name = 'I\'am LiChengGuang' print (name) # 输出字符串,打印:I'am LiChengGuang print ( len (name)) # 输出字符串长度 print (name[ 0 ]) # 输出第 1 个字符 print (name[ 0 : - 1 ]) # 输出下标第 1 个位置到倒数第 2 位置的所有字符,打印:I'am LiChengGuan print (name[ 5 : 15 ]) # 输出下标从第 5 个到第 14 个位置的字符,打印:LiChengGua print (name[ 5 :]) # 输出下标从第 5 个起后面所有的字符,打印: LiChengGuan print (name * 2 ) # 输出 2 次字符串 print ( 'Hello,' + name) # 字符串拼接,打印:Hello,I'am LiChengGuan print ( 'Li' in name) # True print (name.find( 'Li' )) # 查找,打印 5,即返回开始的索引值,否则返回-1 print (name.index( 'Li' )) # 查找,打印 5,即返回开始的索引值,没有则抛异常 print ( 'Li' not in name) # False print (name.upper()) # 全部转大写 print (name.lower()) # 全部转小写 print (name.capitalize()) # 把字符串的第一个字符大写 print (name.isspace()) # 是否包含空格 print (name.replace( 'Li' , '')) # 替换操作 print (name.split( 'm' )) # 分割操作,打印: ["I'a", ' LiChengGuan'] print (name.strip()) # 去掉字符串的左右空格 print (name.lstrip()) # 去掉字符串的左空格 print (name.rstrip()) # 去掉字符串的右空格 |
如有字符串mystr = 'hello world lcg and 0bug'
,以下是常见的操作
1.find
1 | mystr.find( str , start = 0 , end = len (mystr)) |
检测 str 是否包含在 mystr中,如果是返回第一个的索引值,否则返回-1
1 2 3 4 5 6 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.find( 'o' , 1 , 3 ) - 1 >>> mystr.find( 'o' ) 4 >>> |
2.index
1 | mystr.index( str , start = 0 , end = len (mystr)) |
跟find()方法一样,只不过如果str不在 mystr中会报一个异常.
1 2 3 4 5 6 7 8 9 10 11 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.index( 'o' ) 4 >>> mystr.index( 'x' ) Traceback (most recent call last): File "<stdin>" , line 1 , in <module> ValueError: substring not found >>> mystr.index( '0' , 1 , 3 ) Traceback (most recent call last): File "<stdin>" , line 1 , in <module> ValueError: substring not found |
3.count
1 | mystr.count( str , start = 0 , end = len (mystr)) |
返回 str在start和end之间 在 mystr里面出现的次数
1 2 3 4 5 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.count( 'o' ) 2 >>> mystr.count( 'hello' ) 1 |
4.replace
1 | mystr.replace(str1, str2, mystr.count(str1)) |
把 mystr 中的 str1 替换成 str2,如果 count 指定,则替换不超过 count 次.
1 2 3 4 5 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.replace( 'o' , 'x' ) 'hellx wxrld lcg and 0bug' >>> mystr.replace( 'o' , 'x' , 1 ) 'hellx world lcg and 0bug' |
5.split
1 | mystr.split( str = " " , 2 ) |
以 str 为分隔符切片 mystr返回一个列表,如果 maxsplit有指定值,则仅分隔 maxsplit 个子字符串
1 2 3 4 5 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.split( ' ' , 2 ) [ 'hello' , 'world' , 'lcg and 0bug' ] >>> mystr.split( ' ' ) [ 'hello' , 'world' , 'lcg' , 'and' , '0bug' ] |
6.capitalize
把字符串的第一个字符大写。mystr.capitalize()
1 2 3 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.capitalize() 'Hello world lcg and 0bug' |
7.title
把字符串的每个单词首字母大写
1 2 3 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.title() 'Hello World Lcg And 0Bug' |
8.startswith
检查字符串是否是以 obj 开头, 是则返回 True,否则返回 False。mystr.startswith(obj)
1 2 3 4 5 6 7 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.startswith( 'hello' ) True >>> mystr.startswith( 'h' ) True >>> mystr.startswith( 'HELLO' ) False |
9.endswith
检查字符串是否以obj结束,如果是返回True,否则返回 False. mystr.endswith(obj)
1 2 3 4 5 6 7 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.endswith( '0bug' ) True >>> mystr.endswith( '0BUG' ) False >>> mystr.endswith( 'g' ) True |
10.lower
转换 mystr 中所有大写字符为小写 mystr.lower()
1 2 3 | >>> mystr = 'HELLO LCG' >>> mystr.lower() 'hello lcg' |
11.upper
转换 mystr 中的小写字母为大写。mystr.upper()
1 2 3 | >>> mystr = 'hello 0bug' >>> mystr.upper() 'HELLO 0BUG' |
12.ljust
1 | mystr.ljust(width) |
返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
1 2 3 | >>> mystr = 'hello' >>> mystr.ljust( 10 ) 'hello ' |
13.rjust
返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串
1 2 3 | >>> mystr = 'hello' >>> mystr.rjust( 10 ) ' hello' |
14.center
1 | mystr.center(width) |
返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
1 2 3 4 5 | >>> mystr = 'hello 0bug' >>> mystr.center( 10 ) 'hello 0bug' >>> mystr.center( 50 ) ' hello 0bug ' |
15.lstrip
删除 mystr 左边的空白字符
1 | mystr.lstrip() |
16.rstrip
删除 mystr 字符串末尾的空白字符
1 | mystr.rstrip() |
17.strip
删除mystr字符串两端的空白字符
1 2 3 4 5 6 | >>> mystr = '\n\thello 0bug\n\t' >>> mystr.strip() 'hello 0bug' >>> mystr = ' hello 0bug ' >>> mystr.strip() 'hello 0bug' |
18.rfind
1 | mystr.rfind( str , start = 0 ,end = len (mystr) ) |
类似于 find()函数,不过是从右边开始查找.
1 2 3 4 5 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.rfind( 'o' ) 7 >>> mystr.rfind( 'o' , 1 , 5 ) 4 |
19.rindex
1 | mystr.rindex( str , start = 0 ,end = len (mystr)) |
类似于 index(),不过是从右边开始.
1 2 3 4 5 6 7 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.index( 'o' ) 4 >>> mystr.index( 'x' ) Traceback (most recent call last): File "<stdin>" , line 1 , in <module> ValueError: substring not found |
20.partition
1 | mystr.partition( str ) |
把mystr以str分割成三部分,str前,str和str后
1 2 3 4 5 | >>> mystr = 'hello world lcg and 0bug' >>> mystr.partition( 'lcg' ) ( 'hello world ' , 'lcg' , ' and 0bug' ) >>> mystr.partition( ' ' ) ( 'hello' , ' ' , 'world lcg and 0bug' ) |
21.rpartition
类似于 partition()函数,不过是从右边开始.
22.splitlines
1 | mystr.splitlines() |
按照行分隔,返回一个包含各行作为元素的列表
1 2 3 | >>> mystr = 'hello world \nlcg and 0bug' >>> mystr.splitlines() [ 'hello world ' , 'lcg and 0bug' ] |
23.isalpha
如果 mystr 所有字符都是字母 则返回 True,否则返回 False
24.isdigit
如果 mystr 只包含数字则返回 True 否则返回 False.
25.isalnum
如果 mystr 所有字符都是字母或数字则返回 True,否则返回 False
26.isspace
如果 mystr 中只包含空格,则返回 True,否则返回 False.
27.join
1 | str .join(mystr) |
mystr 中每个字符后面插入str,构造出一个新的字符串
1 2 3 4 | >>> mystr = [ 'a' , 'b' , 'c' , 'd' ] >>> str = " " >>> str .join(mystr) 'a b c d' |
转义:
使用反斜杠 \ 转义特殊字符或者用r转义字符串。
1 2 | print ( "my email is \"lcgsmile@qq.com\"" ) # my email is "lcgsmile@qq.com" print (r 'D:\django_study\nice' ) # D:\django_study\nice |
数据类型--列表(List)
1.列表的格式
1 | namesList = [ 'a' , 'b' , 'c' ] |
比C语言的数组强大的地方在于列表中的元素可以是不同类型的
1 | testList = [ 1 , 'a' ] |
2.列表的循环遍历
使用for循环
1 2 3 | namesList = [ 'xiaoWang' , 'xiaoZhang' , 'xiaoHua' ] for name in namesList: print (name) |
使用while循环
1 2 3 4 5 6 7 8 9 | namesList = [ 'xiaoWang' , 'xiaoZhang' , 'xiaoHua' ] length = len (namesList) i = 0 while i<length: print (namesList[i]) i + = 1 |
3.列表"增"、"删"、"改""
"增"append, extend, insert
append
通过append可以向列表末尾追加元素
extend
通过extend可以将另一个序列中的元素逐一添加到列表中,也可理解为扩展,其原理就是for循环遍历与append结合。

+=本质会调用MutableSequence类下的魔法函数__iadd__方法,该方法有调用了extend方法。 rom collections import abc # ctrl+鼠标左键点abc ...... from _collections_abc import * from _collections_abc import __all__ # ctrl+鼠标左键点__all__ ...... __all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", "AsyncGenerator", "Hashable", "Iterable", "Iterator", "Generator", "Reversible", "Sized", "Container", "Callable", "Collection", "Set", "MutableSet", "Mapping", "MutableMapping", "MappingView", "KeysView", "ItemsView", "ValuesView", "Sequence", "MutableSequence", "ByteString", ] # ctrl+鼠标左键点MutableSequence ...... def __iadd__(self, values): #实际上+=就会调用这个魔法函数 self.extend(values) return self ...... def extend(self, values): 'S.extend(iterable) -- extend sequence by appending elements from the iterable' for v in values: self.append(v)
例子:
1 2 3 4 5 6 7 8 | >>> a = [ 1 , 2 ] >>> b = [ 3 , 4 ] >>> a.append(b) >>> a [ 1 , 2 , [ 3 , 4 ]] >>> a.extend(b) >>> a [ 1 , 2 , [ 3 , 4 ], 3 , 4 ] |
insert
insert(index, object) 在指定位置index前插入元素object
1 2 3 4 | >>> a = [ 0 , 1 , 2 ] >>> a.insert( 1 , 3 ) >>> a [ 0 , 3 , 1 , 2 ] |
修改
修改元素的时候,要通过下标来确定要修改的是哪个元素,然后才能进行修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # 定义变量A,默认有3个元素 L = [ 'A' , 'B' , 'C' ] print ( "-----修改之前,列表L的数据-----" ) for i in L: print (i) # 修改元素 L[ 1 ] = 'X' print ( "-----修改之后,列表L的数据-----" ) for i in L: print (i) """结果: -----修改之前,列表L的数据----- A B C -----修改之后,列表L的数据----- A X C """ |
"查"in, not in, index, count
所谓的查找,就是看看指定的元素是否存在
in, not in
python中查找的常用方法为:
- in(存在),如果存在那么结果为true,否则为false
- not in(不存在),如果不存在那么结果为true,否则false
index, count
index和count与字符串中的用法相同
1 2 3 4 5 6 7 8 9 10 11 | >>> a = [ 'a' , 'b' , 'c' , 'a' , 'b' ] >>> a.index( 'a' , 1 , 3 ) # 注意是左闭右开区间 Traceback (most recent call last): File "<stdin>" , line 1 , in <module> ValueError: 'a' is not in list >>> a.index( 'a' , 1 , 4 ) 3 >>> a.count( 'b' ) 2 >>> a.count( 'd' ) 0 |
"删"del, pop, remove
列表元素的常用删除方法有:
- del:根据下标进行删除
- pop:删除最后一个元素
- remove:根据元素的值进行删除
排序sort, reverse
sort方法是将list按特定顺序重新排列,默认为由小到大,参数reverse=True可改为倒序,由大到小。
reverse方法是将list逆置。
1 2 3 4 5 6 7 8 9 10 11 12 | >>> a = [ 1 , 4 , 2 , 3 ] >>> a [ 1 , 4 , 2 , 3 ] >>> a.reverse() >>> a [ 3 , 2 , 4 , 1 ] >>> a.sort() >>> a [ 1 , 2 , 3 , 4 ] >>> a.sort(reverse = True ) >>> a [ 4 , 3 , 2 , 1 ] |
实例:http://www.cnblogs.com/0bug/p/8671934.html
列表嵌套
一个列表中的元素又是一个列表,那么这就是列表的嵌套
1 2 3 | >>> alist = [ 1 ,[ 2 , 3 ], 4 ] >>> alist[ 1 ][ 1 ] 3 |
数据类型--元组(Tuple)
1.列表与元组的区别
Python的元组与列表类似,不同之处在于元组的元素不能修改。元组使用小括号,列表使用方括号。
2.可通过索引访问元组,元组不可修改
1 2 3 4 5 6 7 8 9 10 11 12 | >>> t = ( '0bug' , 100 , '你好' ) >>> t[ 0 ] '0bug' >>> t[ 1 ] 100 >>> t[ - 1 ] '你好' >>> t[ 0 ] = 'hello' Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: 'tuple' object does not support item assignment >>> |
3.元组方法,index、count
index和count与字符串和列表中的用法相同
1 2 3 4 5 6 7 8 9 10 11 | >>> a = ( 'a' , 'b' , 'c' , 'a' , 'b' ) >>> a.index( 'a' , 1 , 3 ) # 注意是左闭右开区间 Traceback (most recent call last): File "<stdin>" , line 1 , in <module> ValueError: tuple .index(x): x not in tuple >>> a.index( 'a' , 1 , 4 ) 3 >>> a.count( 'b' ) 2 >>> a.count( 'd' ) 0 |
数据类型--字典(Dict)
1.字典是什么
生活中的字典
python中的字典
变量info为字典类型:
1 | info = { 'name' : 'lcg' , 'id' : 100 , 'sex' : 'f' , 'address' : '地球亚洲中国长春' } |
说明:
- 字典和列表一样,也能够存储多个数据
- 列表中找某个元素时,是根据下标进行的
- 字典中找某个元素时,是根据'名字'(就是冒号:前面的那个值,例如上面代码中的'name'、'id'、'sex')
- 字典的每个元素由2部分组成,键:值。例如 'name':'lcg' ,'name'为键,'lcg'为值。要求键是不可变类型。
2.通过键访问值
1 2 3 4 5 6 7 8 | info = { 'name' : 'lcg' , 'id' : 100 , 'sex' : 'f' , 'address' : '地球亚洲中国长春' } print (info[ 'name' ]) print (info[ 'address' ]) # 结果: lcg 地球亚洲中国长春 |
访问不存在的键,则会报错:
1 2 3 4 | >>> info[ 'age' ] Traceback (most recent call last): File "<stdin>" , line 1 , in <module> KeyError: 'age' |
在我们不确定字典中是否存在某个键而又想获取其值时,可以使用get方法,还可以设置默认值:
1 2 3 4 5 6 7 | >>> age = info.get( 'age' ) >>> age #'age'键不存在,所以age为None >>> type (age) < type 'NoneType' > >>> age = info.get( 'age' , 18 ) # 若info中不存在'age'这个键,就返回默认值18 >>> age 18 |
3.修改元素
字典的每个键对应的value值是可以修改的,只要通过key找到,即可修改,存在则修改,不存在则新增:
1 | info[ 'id' ] = 666 |
4.添加元素
变量名['键'] = 数据 时,这个“键”在字典中,不存在,那么就会新增这个元素
1 | info[ 'hobby' ] = 'music' |
5.删除元素 del 、clear
del删除指定的元素
1 | del info[ 'name' ] |
del删除整个字典
1 | del info |
clear清空整个字典
1 2 3 | info.clear() 清空后info变为空字典{} |
6.len
测量字典中,键值对的个数
1 2 3 | >>> d = { 'a' : 1 , 'b' : 2 , 'c' : 3 } >>> len (d) 3 |
7.keys
返回一个包含字典所有KEY的列表
1 2 3 | >>> d = { 'a' : 1 , 'b' : 2 , 'c' : 3 } >>> d.keys() dict_keys([ 'c' , 'b' , 'a' ]) |
8.values
返回一个包含字典所有value的列表
1 2 3 | >>> d = { 'a' : 1 , 'b' : 2 , 'c' : 3 } >>> d.values() dict_values([ 3 , 2 , 1 ]) |
9.items
返回一个包含所有(键,值)元祖的列表
1 2 3 | >>> d = { 'a' : 1 , 'b' : 2 , 'c' : 3 } >>> d.items() dict_items([( 'c' , 3 ), ( 'b' , 2 ), ( 'a' , 1 )]) |
序列遍历
通过for ... in ...:的语法结构,我们可以遍历字符串、列表、元组、字典等数据结构。
字符串遍历
1 2 3 4 5 | a_str = "hello lcg" for char in a_str: print (char,end = ' ' ) # h e l l o l c g |
列表遍历
1 2 3 4 5 | >>> a_list = [ 1 , 2 , 3 , 4 , 5 ] >>> for num in a_list: ... print (num,end = ' ' ) ... 1 2 3 4 5 |
元组遍历
1 2 3 4 | >>> a_turple = ( 1 , 2 , 3 , 4 , 5 ) >>> for num in a_turple: ... print (num,end = " " ) 1 2 3 4 5 |
字典遍历
遍历字典的key(键)
1 2 3 4 5 6 | >>> d = { "name" : "lcg" , "age" : 25 } >>> for key in d.keys(): ... print (key) ... name age |
遍历字典的value(值)
1 2 3 4 5 6 | >>> d = { "name" : "lcg" , "age" : 25 } >>> for v in d.values(): ... print (v) ... lcg 25 |
遍历字典的项(元素)
1 2 3 4 5 6 | >>> d = { "name" : "lcg" , "age" : 25 } >>> for item in d.items(): ... print (item) ... ( 'name' , 'lcg' ) ( 'age' , 25 ) |
遍历字典的key-value(键值对)
1 2 3 4 5 6 | >>> d = { "name" : "lcg" , "age" : 25 } >>> for k,v in d.items(): ... print ( "key=%s,value=%s" % (k,v)) ... key = name,value = lcg key = age,value = 25 |
enumerate()实现带下标索引的遍历
1 2 3 4 5 6 7 8 | >>> chars = [ 'a' , 'b' , 'c' , 'd' ] >>> for i, chr in enumerate (chars): ... print i, chr ... 0 a 1 b 2 c 3 d |
文件操作
1.什么是文件以及为何要有文件
计算机系统分为:计算机硬件,操作系统,普通应用程序三部分。
我们用Python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于磁盘中,这就涉及到操作硬件,众所周知,现代操作系统不允许普通的程序直接操作硬件,操作系统把复杂的硬件操作封装成简单的接口给应用程序使用。在磁盘上读写文件的功能都是由操作系统提供的,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。
一般来说,计算机文件可以分为两类:文本文件和二进制文件
有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:
1 2 3 4 5 | 1. 打开文件,得到文件句柄并赋值给一个变量 2. 通过句柄对文件进行操作 3. 关闭文件 |
2.如何操作文件
读写文件是最常见的IO操作
文件操作的流程:
1 2 3 4 5 6 7 8 | 1. 打开文件,得到文件句柄并赋值给一个变量 f = open ( 'a.txt' , 'r' ,encoding = 'utf-8' ) # 默认打开模式就为r 2. 通过句柄对文件进行操作 data = f.read() 3. 关闭文件 f.close() |
f = open('a.txt', 'r')的过程分析
1 2 3 4 5 | 1 、由应用程序向操作系统发起系统调用 open (...) 2 、操作系统打开该文件,并返回一个文件句柄给应用程序 3 、应用程序将文件句柄赋值给变量 f |
打开一个文件包含两部分资源:操作系统级别打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为:
1 2 | 1.f .close() # 回收操作系统级打开的文件 2.del f # 回收应用程序级的变量 |
其中 del f 一定要发生在 f.close() 之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源,
而python自动的垃圾回收机制决定了我们无需考虑 del f,这就要求我们,在操作完毕文件后,一定要记住 f.close()
Python给我们提供了一种傻瓜式操作方式:使用with关键字来帮我们管理上下文:
1 2 3 4 5 6 7 | # 使用whith打开可以不用close with open ( 'E:\Work\\f1.txt' , 'r' ) as f: pass # 在Python 2.7 后,with又支持同时对多个文件的上下文进行管理 with open ( 'E:\Work\\f1.txt' , 'r' ) as f1, open ( 'E:\Work\\f2.txt' , 'w' ) as f2: pass |
注意:f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。
若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
1 | f = open ( 'a.txt' , 'r' , encoding = 'utf-8' ) |
Python2 中的 file 与 open:
首先在 python3 中操作文件只有一种选择,那就是open()
而在 python2 中则有两种方式:file() 与 open()
两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用 file() 来打开文件,相当于这是在构造文件类,而用 open() 打开文件,是用 python 的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如 type(f) is file
3.打开文件的模式
1 | 文件句柄 = open ( '文件路径' , '模式' ) |
Character | Meaning |
---|---|
‘r' | open for reading (default) |
‘w' | open for writing, truncating the file first |
‘a' | open for writing, appending to the end of the file if it exists |
‘b' | binary mode |
‘t' | text mode (default) |
‘+' | open a disk file for updating (reading and writing) |
‘U' | universal newline mode (for backwards compatibility; should not be used in new code) |
1 2 3 4 5 | r 只读模式(默认)。 w 只写模式。【不可读;不存在则创建;存在则删除内容;】 a 追加模式。【可读; 不存在则创建;存在则只追加内容;】 |
"+" 表示可以同时读写某个文件
1 2 3 4 5 | r + 可读写文件。【可读;可写;可追加】 w + 先写再读。【这个方法打开文件会清空原本文件中的所有内容,将新的内容写进去,之后也可读取已经写入的内容】 a + 同a |
"U"表示在读取时,可以将 \r \n \r\n自动转换成 \n (注意:只能与 r 或 r+ 模式同使用)
1 2 3 4 5 6 7 | rU r + U rbU rb + U |
"b"表示以字节的方式操作,对于非文本文件,我们只能使用b模式,所有文件也都是以字节(二进制)的形式存储的,使用这种模式无需考虑文本文件的字符编码
1 2 3 4 5 | rb wb ab |
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
1 2 3 4 5 | x 只写模式【不可读;不存在则创建,存在则报错】 x + 写读【可读,可写】 xb |
4.操作文件的方法

class file(object): def close(self): # real signature unknown; restored from __doc__ 关闭文件 """close() -> None or (perhaps) an integer. Close the file. Sets data attribute .closed to True. A closed file cannot be used for further I/O operations. close() may be called more than once without error. Some kinds of file objects (for example, opened by popen()) may return an exit status upon closing. """ def fileno(self): # real signature unknown; restored from __doc__ 文件描述符 """fileno() -> integer "file descriptor". This is needed for lower-level file interfaces, such os.read(). """ return 0 def flush(self): # real signature unknown; restored from __doc__ 刷新文件内部缓冲区 """ flush() -> None. Flush the internal I/O buffer. """ pass def isatty(self): # real signature unknown; restored from __doc__ 判断文件是否是同意tty设备 """ isatty() -> true or false. True if the file is connected to a tty device. """ return False def next(self): # real signature unknown; restored from __doc__ 获取下一行数据,不存在,则报错 """ x.next() -> the next value, or raise StopIteration """ pass def read(self, size=None): # real signature unknown; restored from __doc__ 读取指定字节数据 """read([size]) -> read at most size bytes, returned as a string. If the size argument is negative or omitted, read until EOF is reached. Notice that when in non-blocking mode, less data than what was requested may be returned, even if no size parameter was given.""" pass def readinto(self): # real signature unknown; restored from __doc__ 读取到缓冲区,不要用,将被遗弃 """ readinto() -> Undocumented. Don't use this; it may go away. """ pass def readline(self, size=None): # real signature unknown; restored from __doc__ 仅读取一行数据 """readline([size]) -> next line from the file, as a string. Retain newline. A non-negative size argument limits the maximum number of bytes to return (an incomplete line may be returned then). Return an empty string at EOF. """ pass def readlines(self, size=None): # real signature unknown; restored from __doc__ 读取所有数据,并根据换行保存值列表 """readlines([size]) -> list of strings, each a line from the file. Call readline() repeatedly and return a list of the lines so read. The optional size argument, if given, is an approximate bound on the total number of bytes in the lines returned. """ return [] def seek(self, offset, whence=None): # real signature unknown; restored from __doc__ 指定文件中指针位置 """seek(offset[, whence]) -> None. Move to new file position. Argument offset is a byte count. Optional argument whence defaults to (offset from start of file, offset should be >= 0); other values are 1 (move relative to current position, positive or negative), and 2 (move relative to end of file, usually negative, although many platforms allow seeking beyond the end of a file). If the file is opened in text mode, only offsets returned by tell() are legal. Use of other offsets causes undefined behavior. Note that not all file objects are seekable. """ pass def tell(self): # real signature unknown; restored from __doc__ 获取当前指针位置 """ tell() -> current file position, an integer (may be a long integer). """ pass def truncate(self, size=None): # real signature unknown; restored from __doc__ 截断数据,仅保留指定之前数据 """ truncate([size]) -> None. Truncate the file to at most size bytes. Size defaults to the current file position, as returned by tell().“"" pass def write(self, p_str): # real signature unknown; restored from __doc__ 写内容 """write(str) -> None. Write string str to file. Note that due to buffering, flush() or close() may be needed before the file on disk reflects the data written.""" pass def writelines(self, sequence_of_strings): # real signature unknown; restored from __doc__ 将一个字符串列表写入文件 """writelines(sequence_of_strings) -> None. Write the strings to the file. Note that newlines are not added. The sequence can be any iterable object producing strings. This is equivalent to calling write() for each string. """ pass def xreadlines(self): # real signature unknown; restored from __doc__ 可用于逐行读取文件,非全部 """xreadlines() -> returns self. For backward compatibility. File objects now include the performance optimizations previously implemented in the xreadlines module. """ pass
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | f.read() #读取所有内容,光标移动到文件末尾 f.readline() #读取一行内容,光标移动到第二行首部 f.readlines() #读取每一行内容,存放于列表中 f.readable() #文件是否可读 f.writable() #文件是否可读 f.closed #文件是否关闭 f.encoding #如果文件打开模式为b,则没有该属性 f.flush() #立刻将文件内容从内存刷到硬盘 f.name |
5.修改文件
文件的数据是存放于硬盘上的,因而只存在替换、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:
方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存替换源文件到硬盘(word,vim,nodpad++等编辑器)。
方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆替换文件。
有文件user.txt
1 2 3 | 卢本伟 - 斗鱼TV主播 刘谋 - 熊猫TV主播 骚男 - 虎牙TV主播 |
在每位主播名字后面添加_NB:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #! /usr/bin/env python # -*- coding: utf-8 -*- # __author__ = "lcg" import os f1 = open ( 'user.txt' , encoding = 'utf-8' ) f2 = open ( 'user_bak.txt' , 'w' , encoding = 'utf-8' ) for line in f1: userList = line.split( '-' ) userList[ 0 ] = userList[ 0 ] + '_NB' user_str = '-' .join(userList) f2.write(user_str) f1.close() f2.close() os.remove( 'user.txt' ) # 删除一个文件 os.rename( 'user_bak.txt' , 'user.txt' ) # 重命名一个文件 |
结果user.txt
1 2 3 | 卢本伟_NB - 斗鱼TV主播 刘谋_NB - 熊猫TV主播 骚男_NB - 虎牙TV主播 |
函数编程
1.什么是函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段
2.为什么要用函数
函数能提高应用的模块性,和代码的重复利用率。
3.函数的分类
1、内置函数
为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max() ps:我们将会在最后详细介绍常用的内置函数。
2、自定义函数
很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可
4.创建函数
1.语法
1 2 3 4 5 6 7 | # 语法 def 函数名(参数 1 ,参数 2 ,参数 3 ,...): '''注释''' 函数体 return 返回的值 # 函数名要能反映其意义 |
2.函数使用的原则:先定义,再调用
函数即“变量”,“变量”必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名
3.函数在定义阶段都干了哪些事
1 2 | # 只检测语法,不执行代码 也就说,语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道 |
4.定义函数的三种形式
1 2 3 4 5 6 | 无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印 有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值 空函数:设计代码结构 定义时无参,意味着调用时也无需传入参数 定义时有参,意味着调用时则必须传入参数 |

def auth(user,password): ''' auth function :param user: 用户名 :param password: 密码 :return: 认证结果 ''' pass
5.调用函数
函数的调用:函数名加括号
6.函数的返回值
1 2 3 | 无 return - > None return 1 个值 - >返回 1 个值 return 逗号分隔多个值 - >元组 |
注意:return语句结束整个函数
7.函数调用的三种形式
1 2 3 | 语句形式:foo() 表达式形式: 3 * len ( 'hello' ) 当中另外一个函数的参数: range ( len ( 'hello' )) |
5.函数的参数
形参即变量名,实参即变量值,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定。
1.位置参数
按照从左到右的顺序定义的参数
1 2 | 位置形参:必选参数 位置实参:按照位置给形参传值 |
2.关键字参数
按照key=value的形式定义的实参
1 2 3 4 | 无需按照位置为形参传值 注意的问题: 1. 关键字实参必须在位置实参右面 2. 对同一个形参不能重复传值 |
3.默认参数
形参在定义时就已经为其赋值
1 2 3 4 5 | 可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参) 注意的问题: 1. 只在定义时赋值一次 2. 默认参数的定义应该在位置形参右面 3. 默认参数通常应该定义成不可变类型 |
4.可变长参数
可变长指的是实参值的个数不固定
而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
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 | # == == == == == =*args == == == == == = def foo(x, y, * args): print (x, y) print (args) foo( 1 , 2 , 3 , 4 , 5 ) def foo(x, y, * args): print (x, y) print (args) foo( 1 , 2 , * [ 3 , 4 , 5 ]) def foo(x, y, z): print (x, y, z) foo( * [ 1 , 2 , 3 ]) # == == == == == = ** kwargs == == == == == = def foo(x, y, * * kwargs): print (x, y) print (kwargs) foo( 1 , y = 2 , a = 1 , b = 2 , c = 3 ) def foo(x, y, * * kwargs): print (x, y) print (kwargs) foo( 1 , y = 2 , * * { 'a' : 1 , 'b' : 2 , 'c' : 3 }) def foo(x, y, z): print (x, y, z) foo( * * { 'z' : 1 , 'x' : 2 , 'y' : 3 }) # == == == == == =*args + ** kwargs == == == == == = def foo(x, y): print (x, y) def wrapper( * args, * * kwargs): print ( '====>' ) foo( * args, * * kwargs) |
5.命名关键字参数
*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
可以保证,传入的参数中一定包含某些关键字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def foo(x, y, * args, a = 1 , b, * * kwargs): print (x, y) print (args) print (a) print (b) print (kwargs) foo( 1 , 2 , 3 , 4 , 5 , b = 3 , c = 4 , d = 5 ) """ 结果: 1 2 (3, 4, 5) 1 3 {'c': 4, 'd': 5} """ |
函数编程进阶
1.函数是对象
函数也是对象,即函数可以当作数据传递
1 2 3 4 | 1 可以被引用 2 可以当作参数传递 3 返回值可以是函数 4 可以当作容器类型的元素 |
利用该特性,优雅的取代多分支的if
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def foo(): print ( 'foo' ) def bar(): print ( 'bar' ) dic = { 'foo' :foo, 'bar' :bar, } while True : choice = input ( '>>: ' ).strip() if choice in dic: dic[choice]() |
2、函数嵌套
嵌套函数,就是指在某些情况下,您可能需要将某函数作为另一函数的参数使用,这一函数就是嵌套函数

def max(x,y): return x if x > y else y def max4(a,b,c,d): res1=max(a,b) res2=max(res1,c) res3=max(res2,d) return res3 print(max4(1,2,3,4))
3、名称空间与作用域
1、什么是名称空间
名称空间:存放名字的地方,三种名称空间,(x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)
2、名称空间的加载顺序
1 2 3 4 | python test.py 1 、python解释器先启动,因而首先加载的是:内置名称空间 2 、执行test.py文件,然后以文件为基础,加载全局名称空间 3 、在执行文件的过程中如果调用函数,则临时产生局部名称空间 |
3、名字的查找顺序
局部名称空间--->全局名称空间--->内置名称空间
4、函数的作用域
1.作用域即范围
- 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
- 局部范围(局部名称空间属于该范围):临时存活,局部有效
2.作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
1 2 3 4 5 6 7 8 9 10 11 | x = 1 def f1(): def f2(): print (x) return f2 x = 100 def f3(func): x = 2 func() x = 10000 f3(f1()) # 10000 |
3.查看作用域:globals(),locals()
1 2 3 4 5 | LEGB 代表名字查找顺序: locals - > enclosing function - > globals - > __builtins__ locals 是函数内的名字空间,包括局部变量和形参 enclosing 外部嵌套函数的名字空间(闭包中常见) globals 全局变量,函数定义所在模块的名字空间 builtins 内置模块的名字空间 |
4.函数的闭包
1.什么是闭包
以下是一段简单的闭包代码示例:
1 2 3 4 5 6 7 8 9 10 11 | def foo(): m = 3 n = 5 def bar(): a = 4 return m + n + a return bar >>>bar = foo() >>>bar() 12 |
说明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。
简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。
2.闭包的意义与应用
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算(原来我们是传参,现在我们是包起来)
1 2 3 4 5 6 7 8 9 10 11 12 | from urllib.request import urlopen def index(url): def get(): return urlopen(url).read() return get baidu = index( 'http://www.baidu.com' ) print (baidu().decode( 'utf-8' )) |
5.装饰器
装饰器就是闭包函数的一种应用场景
1、为何要用装饰器
开放封闭原则:对修改封闭,对扩展开放
2、什么是装饰器
就是装饰其他函数。
强调装饰器的原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
3.装饰器语法
1 2 3 4 5 6 7 8 | 被装饰函数的正上方,单独一行 @deco1 @deco2 @deco3 def foo(): pass foo = deco1(deco2(deco3(foo))) |
4、装饰器的使用

import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer def foo(): time.sleep(3) print('from foo') foo()

def auth(driver='file'): def auth2(func): def wrapper(*args,**kwargs): name=input("user: ") pwd=input("pwd: ") if driver == 'file': if name == 'guang' and pwd == '123': print('guang successful') res=func(*args,**kwargs) return res elif driver == 'ldap': print('ldap') return wrapper return auth2 @auth(driver='file') def foo(name): print(name,'welcome!') foo('guang')
5、装饰器补充 wraps
官网解释:https://docs.python.org/2/library/functools.html#functools.wraps

from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' x=10 print('from index') print(index.__name__) print(index.__doc__) # 加wraps # index # 哈哈哈哈 # 不加waps # wrapper # None
详情,请参考这里:http://www.cnblogs.com/0bug/p/7978595.html
6.迭代器
1.迭代的概念
1 2 3 4 5 6 7 8 9 | #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True : #只是单纯地重复,因而不是迭代 print ( '===>' ) l = [ 1 , 2 , 3 ] count = 0 while count < len (l): #迭代 print (l[count]) count + = 1 |
2、为何要有迭代器?什么是可迭代对象?什么是迭代器对象?

#1、为何要有迭代器? 对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器 #2、什么是可迭代对象? 可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下 'hello'.__iter__ (1,2,3).__iter__ [1,2,3].__iter__ {'a':1}.__iter__ {'a','b'}.__iter__ open('a.txt').__iter__ #3、什么是迭代器对象? 可迭代对象执行obj.__iter__()得到的结果就是迭代器对象 而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象 文件类型是迭代器对象 open('a.txt').__iter__() open('a.txt').__next__() #4、注意: 迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
3、迭代器对象的使用

dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身 iter_dic.__iter__() is iter_dic #True print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) # print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志 #有了迭代器,我们就可以不依赖索引迭代取值了 iter_dic=dic.__iter__() while 1: try: k=next(iter_dic) print(dic[k]) except StopIteration: break #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环
4.for循环
1 2 3 4 5 6 7 8 9 | #基于for循环,我们可以完全不再依赖索引去取值了 dic = { 'a' : 1 , 'b' : 2 , 'c' : 3 } for k in dic: print (dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环 |
5、迭代器特点
1 2 3 4 | - 提供一种统一的、不依赖于索引的迭代方式 - 惰性计算,节省内存 - 无法获取长度(只有在 next 完毕才知道到底有几个值) - 一次性的,只能往后走,不能往前退 |
7.生成器
1.什么是生成器
1 2 3 4 5 6 7 8 9 10 11 12 13 | #只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码 def func(): print ( '====>first' ) yield 1 print ( '====>second' ) yield 2 print ( '====>third' ) yield 3 print ( '====>end' ) g = func() print (g) # <generator object func at 0x0000000002184360> |
2、生成器也是迭代器
1 2 3 4 5 | g.__iter__ g.__next__ #生成器也是迭代器,因此可以这么取值 res = next (g) print (res) |
8.列表推导式
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 | #1、示例 egg_list = [] for i in range ( 10 ): egg_list.append( '鸡蛋%s' % i) egg_list = [ '鸡蛋%s' % i for i in range ( 10 )] #2、语法 [expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ... for itemN in iterableN if conditionN ] 类似于 res = [] for item1 in iterable1: if condition1: for item2 in iterable2: if condition2 ... for itemN in iterableN: if conditionN: res.append(expression) #3、优点:方便,改变了编程习惯,可称之为声明式编程 |
9.生成器表达式
1 2 3 4 5 6 7 8 9 10 11 12 | #1、把列表推导式的[]换成()就是生成器表达式 #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性 >>> chicken = ( '鸡蛋%s' % i for i in range ( 5 )) >>> chicken <generator object <genexpr> at 0x10143f200 > >>> next (chicken) '鸡蛋0' >>> list (chicken) #因chicken可迭代,因而可以转成列表 [ '鸡蛋1' , '鸡蛋2' , '鸡蛋3' , '鸡蛋4' ,] #3、优点:省内存,一次只产生一个值在内存中. |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了