准备
pip 下载慢
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
vcode 配置
{
"code-runner.executorMap": {
"python": "set PYTHONIOENCODING=utf8 && python -u"
},
"python.pythonPath": "E:\\Program Files\\Python\\Python38\\python.exe",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"[python]": {
"editor.tabSize": 4
}
}
规范
4 个空格缩进
没有常量, 一般约定纯大写的就是常量
数据类型
动态类型
a = 123
a = '123'
print(a)
print(a-1) # 报错
数字
由于是动态类型 整数,浮点数区分起来只能靠一些函数 对大数字的支持比较好,不用担心溢出
a = 123
print(isinstance(a, int), isinstance(a, float))
a = 123.0
print(isinstance(a, int), isinstance(a, float))
字符串
单双引号没区别,有个优点如下
print("I\'m ok")
print("I'm ok")
保留换行的字符串
print('''line1
line2''')
布尔值
注意是大写,运算符为 and、or 和 not
a = True
a = False
空值
None
运算符注意
10/3 # 3.33333
集合类
元组,tuple,不可变长,使用 len(arr)获取长度,越界取值报错,无法删除使用 del 释放
z 支持切片操作,元组
a = ()
b = (2,) # 为防止歧义,只有一个元素必须要加逗号,当然,只有一个元素的数组也没啥意义
# 使用tuple函数构建
tuple(list)
tuple(tuple)
tuple(dict) # 所有的key
列表,list,可变长,,使用 len(arr)获取长度,可用 append,pop,pop(i),等方法
越界取值报错,空 list 调用 pop 报错
a = [2]
[1, 2, 3] + [4, 5, 6] # 组合
['Hi!'] * 4 # 重复
3 in [1,2,3]
字典,dict,其他语言都叫做 map,删除使用 pop(key)
m = {'k1': 1, 'k2': 2}
m['k3'] = 3
print('k4' in m)
print(m.get('k4')) # None
print(m['k4']) # KeyError
# 通过dict方法构建
m1 = dict(k1=1,k2=2) # 传入关键字
print(m1)
m2 = dict(zip(['k1','k2'],[1,2])) # 映射函数方式来构造字典
print(m2)
m3 = dict([('k1', 1),('k2', 2)]) # 可迭代对象方式来构造字典
print(m3)
集合,set
s = {1, 2, 3}
# 也可以使用set方法构建
s2 = set([1,2,3,4])
s3 = set((1,2,3,4))
循环
只有一种for ... in ...
的写法,想要获取下标可以换一种思路
arr = (2, 4, 6, 8, 10)
for item in arr:
print(item)
for idx in range(len(arr)):
print(arr[idx])
for i, v in enumerate(arr):
print(i, v)
列表生成
print(list(range(0, 10))) # 等价 range(10)
print(list(range(0, 10, 2))) # 0 2 4 6 8
# 列表生成式
print([x * x for x in range(10)])
print([x * x for x in range(10) if x > 5])
print([m + n for m in 'ABC' for n in 'XYZ'])
# 生成器,返回一个函数,每次调用next计算出下个值,最后抛出 StopIteration 异常
g = (x*x for x in range(2, 10))
print(next(g)) # 4
print(next(g)) # 9
函数式编程
map,reduce,filter,sorted 和 es6 里面的意思差不多
from functools import reduce
sum = reduce(lambda x, y: x+y, list(range(1, 11)))
print(sum)
函数
支持的特性:必选参数,参数默认值,可变参数,关键字参数,命名关键字参数
注意: 默认参数值必须指向不变对象,假如是 list 的话,这个引用会被一直保持着
注意:不能多传,不能少传,传值顺序不能有歧义
def f1():
pass
f1(123) # takes 0 positional arguments but 1 was given
def f2(a, b=99, *c):
print(a, b, c)
f2(1) # 1 99 ()
f2(1, 2) # 1 2 ()
# f2(1, a=2) # got multiple values for argument 'a'
f2(b=2, a=1) # 1 2 ()
f2(2, 3, 4, 5, 6) # 2 3 (4, 5, 6)
强制使用关键词参数,*
后面的参数必须通过带参数名的方式传值,不能多传,不能少传
def f2(name, *, p1, p2):
print(name, p1, p2)
# f2('zs', 5, 6)
f2('zs', p1=5, p2=6)
接收多余的关键词参数(命名关键字参数)
def f2(name, **other):
print(other)
# {'age': 18, 'sex': 0}
f2(name='zs', age=18, sex=0)
总结:一般其他语言为了避免可变参数的歧义,定义可变参数必须为最后一个参数,但是在 python 中有了命名关键字参数后,可变参数后面还可以定义其他关键词参数
在 Python 中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这 5 种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f2(name, *p1, p2, p3):
print(name, p1, p2, p3)
f2('zs', 5, 6, 7, p2=6, p3=6)
当定义一个空函数时,可以使用 pass
def f1():
return
def f2():
pass
面向对象
__xx
表示私有变量,其实也不是私有,解释器会把它重命名,变成_ClassName__VarName
class User(object):
attr = 'haha' # 类变量
def __init__(self, name):
self.__name = name # 定义成员变量
def print(self):
print('{"name": "%s"}' %(self.__name))
class SpecialUser(User):
def __init__(self, name, weight):
User.__init__(self, name) # 调用父类构造方法
# super(SpecialUser, self).__init__(name)
self.weight = weight
u = User('zs')
u.print()
print(u._User__name)
# 动态添加属性
u.extName = 'xxx'
两个函数type()
,isinstance()
获取类信息dir()
,hasattr()
,setattr()
,getattr()
模块管理
在导入模块的时候,模块会从头到尾执行一遍,然后的变量均可被导出
方便开发运行模块,类似于 main 方法吧,又不希望导入的时候被执行可以可以使用下面的魔法写法
# 在直接运行时候成立
if __name__ == "__main__":
pass
导入其他 py 文件的几种方式
在 python 2.7 及之前版本中默认是先“相对”后“绝对”的顺序搜索模块,之后是先搜索绝对路径如果有就停止,所以在你的文件名,包名尽量起的不要和常用库的名字一样
import tool
# 相对导入只能在模块中使用,且无法直接执行运行,需要以模块的方式去跑
# python -m dirname.filename
import .tool
from . import tool
# 子目录
import dir.tool
dir.tool.say()
# 重命名
import dir.tool as t
t.say()
# 导出单个方法
from dir.tool import say,move
say()
move()
实际项目中,一般都是以目录作为模块的划分,直接导入目录,然后在在目录下的__init__.py
文件去导入本目录中的文件,然后再暴露出去。系统识别到 init 文件后会把该目录视作一个模块
在如下层级关系中
|-- main.py
|-- m
| |-- a.py
| |-- b.py
没使用__init__.py
时候一般是这样用的
import m.a as ma
import m.b as mb
print(ma.name)
print(mb.name)
添加__init__.py
后
import m
print(m.aName)
print(m.bName)
import a
import b
aName = a.name
bName = b.name
这时会报错,因为python main.py
的搜索路径是当前路径+系统模块路径,在解析__init__.py
时,在上述路径中搜索不到 a 和 b
可以通过改变搜索路径来解决这问题,但是对 IDE 可能不太好
import sys
sys.path.append('m')
import a
import b
aName = a.name
bName = b.name
规范的做法是在模块内使用相对路径导入,执行main.py
正常。但是由于使用了相对导入__init__.py
就无法作为脚本直接执行了,需要到外层python -m m.__init__
进行执行
from . import a
from . import b
aName = a.name
bName = b.name
第三方库使用 pip 管理,官方源,下载慢建议替换成清华的源
pip install –upgrade pip pip install requests
使用 python3 的 typing 模块提高代码健壮性
Python 在 3.5 版本中引入了 typing 模块,实现了类型提示功能
这里需要注意的一点是,Python typing 本质是一种注释,可以用来帮助 IDE 进行类型检查和自动补全等操作,但是他并不会真的让执行失败。
from typing import List, Tuple, Dict
int,long,float: 整型,长整形,浮点型;
bool,str: 布尔型,字符串类型;
List, Tuple, Dict, Set:列表,元组,字典, 集合;
Iterable,Iterator:可迭代类型,迭代器类型;
Generator:生成器类型;
from typing import List
# 声明新的类型
NewType = List[str]
# 定义参数类型,定义返回值类型
def conv(list: List[int]) -> NewType:
temp: NewType = []
for item in list:
temp.append(hex(item))
return temp
print(conv([3, 5, 8]))