Python快速上手

Wanjiongming 于 2020-09-06 发布

准备

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]))

参考

类型标注支持

Python 教程 - 廖雪峰的官方网站