一、变量
1.1. 变量类型
- Numbers(数字类型)
- int:有符号整数
- long
- float
- complex:复数
- 布尔类型:True = 1、False = 0
- String
- List
- Tuple
- Dictionary:字典
person = {
"name": "yhf",
"age": 24,
}
print(person)
# 查看变量的数据类型
print(type(person))
1.2. 类型转换
函数 | 说明 |
---|---|
int(x) | 将 x 转为 int 类型,x 只能是整数的字符串 |
float(x) | 将 x 转为 float 类型,x 只能是数字的字符串 |
str(x) | 将 x 转为 string 类型,bool 类型直接是 ‘True’ 和 ‘False’ 而不是1和0 |
bool(x) | 将 x 转为 bool 类型,x 只能是数字的字符串,只有 0、0.0、“”、[]、()、{} 是 False,其他内容都是 True |
ord(x) | 将单字符 x 转为 acsii 码的 int 值 |
1.3. 进制的表示
python 中:
- 结尾为 b:2进制
- 结尾 o:8进制
- 结尾 x:16进制
格式化进制:
a = 1
# 用0补齐到8位,多了不管,不足补齐
print(format(a, "08b")) # 00000001
1.4. python 中的编码格式
a = '中' # py 内存中Unicode编码
print(ord(a)) # 码位:20013
print(chr(20013)) # 码位还原成符号:'中'
二、运算符
2.1. 算数运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | |
- | 减 | |
* | 乘 | |
/ | 除 | |
// | 整除(向下取整) | -1//2 = -1,1//2 = 0 |
% | 取模 | |
** | 指数 | 2 ** 3 = 8 |
() | 优先运算符 |
优先级: ****** > ***、/、%、// ** > +、-
字符串之间的 + 操作是拼接,注意与 java 不同的是,必须两边都是 str 类型,否则编译报错
字符串的 * n 操作是将字符串重复 n 次,n 只能为 int 类型
2.2. 赋值运算符
运算符 | 描述 |
---|---|
= | 将等号右边的值赋给等号左边的变量 |
可以同时给多个变量赋值:
b = c = 20
a, b, c = 1, 2, 3
2.3. 复合赋值运算符
运算符 | 描述 |
---|---|
+= | 同 java |
-= | 同 java |
/= | 同 java |
*= | 同 java |
//= | b = b // n ,整除之后重新赋值 |
%= | 同 java |
**= | b = b ** n,n 次幂后重新赋值 |
2.4. 比较运算符
运算符 | 描述 |
---|---|
== | 同 java |
!= | 同 java,python3 不支持 <> 了 |
> | 同 java |
>= | 同 java |
< | 同 java |
<= | 同 java |
同样,比较运算符左右两边也需要数据类型保持一致!!
2.5. 逻辑运算符
运算符 | 描述 |
---|---|
and | 不能用 java 的 && |
or | 不能用 java 的 || |
not | 不能用 java 的 ! |
与以上运算符不同的是,逻辑运算符两边可以是任意的数据类型,因为万物可以转为 bool 类型
与 java 一样,具有断路的特性
None 与任何值逻辑运算都是 None,但 not None 的结果为 True
2.6. 位运算符
运算符 | 描述 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或(相同0,不同1) |
~ | 按位取反 |
<< | 左移,相当于乘 2 的整数倍,高位丢弃 |
>> | 右移,低位丢弃,相当于整除 2 的整数倍 |
只有整数能进行位运算
2.7. 成员运算符
运算符 | 描述 |
---|---|
in | print( “a” in “abcd” ) 结果为:True print( 114514 in [1, 2, 114514] ) 结果为:True print(114514 in (1, 2, 114514)) 结果为:True print(114514 in {0: [1, 2, 114514]}) 结果为:False。对于 dict 类型判断 key 是否存在 |
not in |
两边类型无限制
2.8. 身份运算符
运算符 | 描述 |
---|---|
is | 比较两个变量的引用地址 |
is not |
a = "1"
c = "1"
b = str(1)
print(a is c) # True
print(a is b) # False
a = ("1")
c = ("1")
b = tuple("1")
print(a is c) # True
print(a is b) # False
2.9. 优先级
运算符 | 描述 |
---|---|
(expressions...) ,[expressions...] , {key: value...} , {expressions...} | 圆括号的表达式 |
x[index] , x[index:index] , x(arguments...) , x.attribute | 读取,切片,调用,属性引用 |
await x | await 表达式 |
** | 乘方(指数) |
+x , -x , ~x | 正,负,按位非 NOT |
* , @ , / , // , % | 乘,矩阵乘,除,整除,取余 |
+ , - | 加和减 |
<< , >> | 移位 |
& | 按位与 AND |
^ | 按位异或 XOR |
` | ` |
in,not in, is,is not, <, <=, >, >=, !=, == | 比较运算,包括成员检测和标识号检测 |
not x | 逻辑非 NOT |
and | 逻辑与 AND |
or | 逻辑或 OR |
if -- else | 条件表达式 |
lambda | lambda 表达式 |
:= | 赋值表达式 |
三、输入和输出
3.1. 输出
普通输出:
# 使用 end 指定结尾
print('yhf', end="\n")
# 默认省略是 \n
print('yhf')
格式化输出(excel 文件、mysql、redis):
name = 'yhf'
age = 24
print('名字%s,年龄%d' % (name, age))
# %.2f 保留2位小数
3.2. 输入
name = input("请输入您的名字:")
print(name)
四、流程控制
4.1. if
格式:
#1.单if
if 条件:
动作
#2.if和else
if 条件:
动作
else:
动作
#3.多分支
if 条件1:
动作
elif 条件2:
动作
elif 条件n:
动作
else: #可省略
动作
案例:
age = input("请输入您的年龄:")
try:
age = int(age)
if age >= 65:
print("老年人")
elif age >= 18:
print("成年人")
elif age >= 0:
print("年轻人")
else:
print("年龄只能为正整数")
except ValueError:
print("年龄只能为数字类型")
4.2. for
案例:
str = 'China'
for char in str:
print(char)
几个重要函数:
函数名 | 说明 |
---|---|
range(n) | [0, n):左闭右开的整数集合 |
range(start, end) | [start, end):左闭右开的整数集合 |
range(start, end, step) | [start, end):左闭右开的步长为 step 整数集合,例如 range(1, 10, 3) = [1,4,7] |
4.3. while
while 条件:
动作
4.4. break、continue
使用 break 可以退出循环
使用 continue 可以忽略本轮的剩余语句提前进入循环的下一轮
4.5. pass
pass 是为了保持 python 缩进结构的完整性的空语句
例如下面的 pass 代表捕获异常后不执行任何操作:
try:
动作
except ValueError:
pass
五、各数据类型的常用函数
5.1. 字符串
函数名 | 说明 |
---|---|
len( str ) | 返回字符串 str 的长度 |
find(self, sub, start=None, end=None) | 返回 str 中第一个 sub 的下标(0开始),没找到返回 -1 |
startswith(self, prefix, start=None, end=None) | 返回 str 是否以 prefix 开头(True or False) |
count(self, sub, start=None, end=None) | 返回 str 中 sub 的个数 |
replace(self, old: str, new: str, count: int) | 从左至右替换 str 中的 old 为 new,此行为只会发生 count 次 count 省略即 str 中的 old 全部替换为 new |
split(self, sep: Optional[str], maxsplit: int) | 返回一个 str 被 sep 切分后的数组。从左至右最多切 maxsplit 次 |
str.upper()、str.lower() | 返回 str 转大小写后的字符串 |
str.isupper()、str.islower() | 返回 str 是否全为大写或小写 |
str.strip()、str.lstrip()、str.rstrip() | 去前后空格、只去左空格,只去右空格 |
join(self, iterable: Iterable[str]) | 将 iterable 以 str 为分隔符重新拼接成字符串 例如:“yhf”.join([“1”, “2”, “3”]) == “1yhf2yhf3” |
以上的 start 和 end 都是包前不包后,end 不写默认是 str 末尾、start 和 end 应是自然数、否则返回 -1:
str = "yhfy"
print(str.startswith("y", 3, 3)) # False
print(str.startswith("y", 3, 4)) # True
5.2. 列表
-
添加元素
函数名 说明 list.append( element ) list 末尾追加元素 element list.insert( index, element ) list 下标未 index 的位置插入 element,其他元素后移一位 list.extend( list2 ) 将可迭代的集合 list2(str 也算),按顺序追加到 list 末尾 -
修改
直接通过下标赋值:
list[index] = newVal
-
查找元素
函数名 说明 list.__ contains__( element ) 返回 list 中是否包含元素 element 使用成员运算符:in、not in
-
删除元素
函数名 说明 del list[index] 删除 list 中下标 index 的元素 list.pop(index) 弹出 index 位置的元素,index 省略为删除最后一个元素并返回 list.remove( element ) 删除 list 中的所有 element,element 必须存在于 list 中,否则报错
5.3. 元组
元组跟数组一样用中括号+下标访问元素,但是与数组不同的是,元组里的元素是 final 的:
tp = (['yhf'], 24, 'programmer')
tp[0].append('b') # 可以添加
tp[1] = 25 # 报错
扩展:java 中的元组是可以修改的:
Tuple2<String, Integer> yhf = Tuple2.of("yhf", 24);
yhf.f0 = "yhf2";
System.out.println(yhf); // ("yhf2", 24)
特殊:定义只有一个元素的元组时,该元素后要冗余一个逗号:
tp1 = ( 114514 )
print(type(tp1)) # <class 'int'>
tp1 = ( 114514, )
print(type(tp1)) # <class 'tuple'>
5.4. 字典
-
查找 key 对应的 value
person = { 'name': 'yhf', 'age': 24 } # 跟数组和元组一样, key 不存在会报错!! print(person['name']) # yhf # get(key) print(person.get('age')) # 24 # get(key, default) print(person.get('profession', 'programmer')) # programmer
-
修改 value
person['name'] = 'yhf1'
-
新增 kv
修改的 key 如果不存在就是新增!
person['sex'] = 'male'
-
删除 kv
方法 说明 del 关键字 删除指定 kv,删除整个字典对象 person.pop( key ) 删除指定 kv,返回被删除的 value person.clear() 清空字典,保留对象 注意!! 以上被删除的 key 不存在都会报错!
例如:
del person['sex'] person.pop('age') person.clear() del person
-
获取全部 keys 或 values
# 返回的不是 list,但是也是可迭代对象 print(person.keys()) # dict_keys(['name', 'age', 'sex']) print(type(person.keys())) # <class 'dict_keys'> # 返回的不是 list,但是也是可迭代对象 print(person.values()) # dict_values(['yhf1', 24, 'male']) print(type(person.values())) #<class 'dict_values'>
-
循环输出
# 输出 key for key in person.keys(): print(key) # 输出 value for value in person.values(): print(value) # 输出 (kv),是 tuple 类型,所以是 item 里的元素无法重新赋值的 for item in person.items(): print(item) print(type(item)) # <class 'tuple'> # 结构输出 key,value for key, value in person.items(): print(key) print(value)
六、几个重要函数
6.1. 切片
字符串、列表、元组 都支持切片操作,切片指截取并返回对象的一部分,类似 splice()。这里用 str 举例:
"""
格式:
start: 开始下标
end: 结束下标(跟)
step: 步长
"""
list[start: end: step]
yhf = "12345"
-
从下标为1取到末尾
print(yhf[1:]) # 2345
-
从下标1开始,取到下标4
print(yhf[1:4]) # 234
-
从开头取到下标3
print(yhf[:3]) # 123
-
从下标1开始,取到下标4,步长为2
print(yhf[1:4:2]) # 24
-
特殊:
从倒数第1个元素切到倒数第4个
""" step 为负表示反着切 start 应大于 end 的值(-1 > -4) 同样时包前(-1即倒数第一个元素: 5)不包后(-4): """ print(yhf[-1:-4:-1]) # 543
6.2. hash
hash() 返回的一定是一个数字
s = 'del'
print(hash(s)) # 45726931929387004
6.3. id
返回的是对象的内存地址
s = 'del'
print(id(s)) # 2016542226032
6.4. help
获取关键字的 statement 和说明
print(help('del'))
6.5. dir
dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法 _ _ dir_ (),该方法将被调用。如果参数不包含 _ _ dir_ _(),该方法将最大限度地收集参数信息。
dir([object])
# object -- 对象、变量、类型。
>>> dir() # 获得当前模块的属性列表
['__builtins__', '__doc__', '__name__', '__package__', 'arr', 'myslice']
>>> dir([ ]) # 查看列表的方法
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>>
七、函数
7.1. 定义
def myFunc():
print('yhf')
7.2. 调用
myFunc()
7.3. 参数传递
def sum(a: int, b: int):
print(a + b)
# 顺序传参
sum(1, 2)
# 关键字传参
sum(a=1, b=2)
高级参数用法:
# 混合参数 :顺序位置在前面,关键字在后面
# 默认值 scala gender:String = "男",默认参数要放最后
def func2(name, gender="男"):
pass
# 不定长参数,*号接受的值放在元组中,scala args: String*
def func3(*food):
pass
# 关键字不定长参数,**号接受的值放在dict中
def func4(**food):
pass
# 顺序: 位置 > *args > 默认值 > 关键字.这四个参数可以随意搭配
def func5(a, b, c, *args, d="默认值", **kwargs):
pass
将 list 传入不定长参数中:
# list 传入 不定长参数,**传dict. scala arr:_*
arr = []
func3(*arr)
参数也可以某个函数:
# 代理模式
def out(inner):
inner()
def target():
print("执行了")
out(target) # 将 target 传入 out 中当作 inner 执行
7.4. 返回值
# python的本质还是动态语言,这里会继续正常执行,所以限定返回值类型,更多的是一种约定俗成的规矩,使代码更便于阅读
def sum(a: int, b: int) -> int:
return a + b
print(sum(1, 2)) # 3
print(sum(a=1, b=2)) # 3
返回值也可以是函数本身:
def func():
def inner():
pass
return inner # 返回的是一个函数
func() # 相当于执行 inner()
7.5. 变量的作用域
-
全局变量:
全局能访问,顶格写的变量包括函数都是全局的作用域
a = 10 def func1(): a = 20 # 这里相当于是重新创建了一个局部变量,并不是全局变量 a 了 func1() print(a) # a 还是 10,没变
如何在局部修改全局变量的值?需要用到 global 关键字:
a = 10 def func1(): global a # 引入全局变量,修改会影响原变量 a = 20 func1() print(a) # 输出 20
如果是函数的嵌套呢?内层函数如何修改外层函数的局部变量?
def func1(): global a a = 20 b = 20 def inner(): nonlocal b # 在局部,引入外层(由内向外)的局部变量,外层不存在这个变量会报错 b = 30 inner() print('b', b) func1() print('a', a) """ 输出: b 30 a 20 """
-
局部变量:
只能函数内部使用
7.6. 闭包
概念:嵌套的返回函数,被返回的函数访问到作用域外部的变量。连同这些变量一起会被常驻内存,这就形成了闭包
一个简单的闭包示例:
def func():
a = 10
def inner():
nonlocal a
a += 1
return a
return inner
ret = func() # ret 相当于是 inner 的引用
print(ret()) # 执行 ret(),输出 11
print(ret()) # 执行 ret(),输出 12
利用闭包的好处:
- 让一个变量常驻内存
- 该变量是局部的,外部难以修改其值,安全性高
- 只能通过暴露给外部的方法修改,能保证自己定义的合法性
7.7. 装饰器 @wrapper
装饰器本质上是一个闭包,作用相当于在函数前后添加新功能,但是不改变原来的代码,例如下面的例子:
-
我有一个玩游戏的方法:
def playGenshin(): print('我是原批') playGenshin() # 玩原神
-
有一天来了个大神,给原神开启作弊模式:
def kami(playGenshin): print('玩游戏前自动获得8080原石') playGenshin() print('玩游戏后销毁作弊记录') kami(playGenshin) # 但是这样是不对的,这样就是大神玩原神而不是自己玩了!
-
所以我们想到把封装好的作弊版原神返回出来:
def kami(playGenshin): def superGenshin(): print('玩游戏前自动获得8080原石') playGenshin() print('玩游戏后销毁作弊记录') return superGenshin playGenshin = kami(playGenshin) # 我们直接从大神那里得到我们的作弊版原神 playGenshin() # 开玩!
-
但是对于 playGenshin = kami(playGenshin),总感觉像是递归调用。所以只需在我们需要装饰的函数定义语句上方添加 @装饰器名 就可以实现以上功能
def kami(playGenshin): def superGenshin(): print('玩游戏前自动获得8080原石') playGenshin() print('玩游戏后销毁作弊记录') return superGenshin @kami # 这就相当于在每次执行 playGenshin() 方法前执行:playGenshin = kami(playGenshin) def playGenshin(): print('我是原批') playGenshin() # 开玩! """ 输出: 玩游戏前自动获得8080原石 我是原批 玩游戏后销毁作弊记录 """
理解以上例子后、我们可以写出一般装饰器的通用代码:
def wrapper(fn):
def inner(*args, **kwargs): # *,**表示接收所有参数,打包成元组和字典
# 前置操作
rs = fn(*args, **kwargs) # *,**表示参数从args和kwargs里传过来
# 后置操作
return rs # 返回目标函数的返回值
return inner
***** 装饰器的嵌套执行顺序
def wrapper1(fn):
def inner(*args, **kwargs):
print("wrapper1 进入") # 1
rs = fn() # 2 inner2()
print("wrapper1 出去") # 7
return rs # 8
return inner
def wrapper2(fn): # fn = target
def inner2(*args, **kwargs):
print("wrapper2 进入") # 3
rs = fn() # 4 target()
print("wrapper2 出去") # 5
return rs # 6
return inner2
@wrapper1 # 传入inner2
@wrapper2 # 先是这个装饰器,执行wrapper2,得到inner2
def target():
print("目标函数执行")
target()
"""
输出:
wrapper1 进入
wrapper2 进入
目标函数执行
wrapper2 出去
wrapper1 出去
"""
以上例子中可以理解为由近及远层层装饰,wrapper2 离 target 近所以先装饰:
target = wrapper2(target)
然后再是 wrapper1:
target = wrapper1(target)
合起来就是:
target = wrapper1(wrapper2(target))
所以执行顺序显而易见:
=> wrapper1 前置
=> wrapper2 前置
=> target 执行
=> wrapper2 后置
=> wrapper1 后置
八、文件操作
8.1. 打开文件
创建和打开文件都是 open() 函数:
file = open('filePath' , mode = 'r' , encoding = 'utf-8')
file.close()
filePath:可以写绝对路径和相对路径,如果文件夹不存在会报错。
mode:
mode 说明 r 默认 mode。以只读方式打开文件,文件指针在文件开头。文件不存在会报错! w 打开一个文件只写,如果文件存在会覆盖,文件不存在创建新文件 a 打开一个文件用于追加,如果存在,新内容追加进文件结尾。不存在则创建文件并写入 r+ 打开一个文件用于读写,文件指针在文件开头。文件不存在会报错! w+ 打开一个文件用于读写,存在覆盖,不存在创建 a+ 打开一个文件用于读写,文件存在追加,不存在创建 rb 以二进制格式打开一个文件用于只读。文件指针在头部。文件不存在会报错! wb 以二进制格式打开一个文件用于写入,存在覆盖,不存在创建 ab 以二进制格式打开一个文件用于追加,文件存在追加,不存在创建 rb+ 以二进制格式打开一个文件用于读写。文件指针在头部。文件不存在会报错! wb+ 以二进制格式打开一个文件用于读写。存在覆盖,不存在创建 ab+ 以二进制格式打开一个文件用于读写。文件存在追加,不存在创建
8.2. 文件读写
-
写:
file.write('yhf')
-
读:
按字节读:
byte = file.read()
读一行:
line = file.readline()
去前后空格
line = file.readline().strip()
读全部行:
```python
# 返回的是 list
lines = file.readlines()
8.3. 序列化和反序列化
默认清空 python 对象无法写入文件
序列化的两种方式
-
使用 dumps 实现序列化
import json person = { 'name': '余鸿福' } file = open('./yhf.txt', mode='w', encoding='utf-8') personStr = json.dumps(person) # json 字符串 file.write(personStr) file.close()
-
dump 将对象写入目标文件
import json person = { 'name': '余鸿福' } file = open('./yhf.txt', mode='w', encoding='utf-8') json.dump(person, file) file.close()
反序列化
-
loads
import json person = { 'name': '余鸿福' } file = open('./yhf.txt', mode='r', encoding='utf-8') personStr = file.readline() personFile = json.loads(personStr) print(personFile) # { 'name': '余鸿福' } print(type(personFile)) # <class 'dict'> file.close()
-
load
import json person = { 'name': '余鸿福' } file = open('./yhf.txt', mode='r+', encoding='utf-8') print(json.load(file)) file.close()
九、异常
try:
1 / 0
except ZeroDivisionError:
print('被除数不能为0')
except FileNotFoundError:
print('文件不存在')
finally:
print('结束')
可以多重 except,可以 finally 执行最终操作。