Python
数据类型
- 整数型
- 浮点型
- 字符串
- 布尔型
- None
数据结构
列表
# 列表中的元素可以是任意类型的list = [1,'2',3.0]# 通过下标来获取/修改元素list[0]='a'print(list[0])# 通过len函数来获取列表长度print(len(list))# 通过list的append函数来添加元素list.append('xx')# 查看元素在列表中的下标print(list.index(3.0))# 查看元素是否在列表中print('2' in list)# 统计列表中某元素的数量print(list.count(1))# 向某位置插入元素,如果提供的下标超出列表的大小,会插在最后list.insert(0,'x')# 添加一个列表list.extend([5,5,5])# 根据下标删除元素并返回x = list.pop(0)# 直接删除指定下标位置的元素del list[0]# 删除并返回最后一个元素x = list.pop()# 直接删除元素list.remove('2')# 反转列表list.reverse()# 排序list.sort()# 清空列表list.clear()
元组
元组创建完成后,便不能向其中添加元素,也不能修改和删除其中的任何一个元素
# 空元祖items = ()# 一个元素的元组,需要在最后加一个(,),如果括号中只有一个元素,那么 Python 会将这个括号当作优先级符号进行处理items=(1,)# 多个元素的元组items=(1,2,3)# 获取元素print(items[2])# 获取下标print(items.index(2))# 是否存在print(2 in items)# 统计元素个数print(items.count(1))
字符串
字符串是字符的有序序列,所以也具有索引。也可以根据索引取出其中某一个字符
print('cxk'[2])# 字符串是不可变的,所以不能通过下标修改# 'cxk'[2]='b'# 同样可以用len获取长度print(len('cxk'))str = 'java language'# 查找子串print(str.find('ang'))# 判断子串print('ava' in str)# 统计子串数print(str.count('a'))# 是否以某子串开头print(str.startswith('ja'))# 是否以某子串结尾print(str.endswith('ge'))# 字符串替换print(str.replace('java','python'))# 去除字符串前后空白字符print(str.strip())# 分割字符串,返回listprint(str.split(' '))# 拼接字符串print(str.join(['so','good']))# 转成大写形式print(str.upper())# 转成小写形式print(str.lower())
- 字符转义
常用的转义字符 | 含义 |
---|---|
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
\n | 换行符 |
\t | 制表符(Tab) |
\r | 回车 |
- 原始字符串
# 原始字符串,有啥就是啥print(r'java \t no.1')
- 多行字符串
# 多行字符串,输出的字符串不换行print('java no.1\ yes!\ ')# 输出的字符串换行print("""javano.1""")
列表、元组、字符串的通用操作
# 长度print(len(str))# 获取子序列print(str[1:10])# 拼接子序列print(str + '?')# 重复序列中的元素print(str*3)
字典
也就是map,显著优势是可以通过键快速地查询数据
# 创建空字典map = {}# 创建有内容的字典map = {'key1': 1, 'key2': 2}# 增加键值对/修改键所对应的值map['key3'] = 3# 通过键获取值,若键不存在则将抛出 KeyError 异常print(map['key2'])# 通过方法来获取,不存在返回Noneprint(map.get('key1'))# 不存在返回默认值0print(map.get('keyx', 0))# 是否包含某个键print('x' in map)# 获取所有键,返回迭代器print(map.keys())# 获取所有值,返回迭代器print(map.values())# 获取键值对迭代器,每一对都是元组print(map.items())# 根据键删除,返回值,如果键不存在,则会抛出 KeyError 异常map.pop('key1')# 键不存在返回默认值,不会抛异常map.pop('key1', 'x')# 键不存在会抛异常del map['key2']# 随机弹出一个键值对print(map.popitem())# 用字典更新字典map = {'key1': 'x'}map.update({'key1': 1})
集合
其中的元素没有顺序关系。集合中的元素没有重复,重复的元素将被自动剔除最终只留下一个,集合也是用花括号({})来表示,不同于字典的是,花括号中放的是一个个数据,而不是键值对
# 创建空集合s = set()# 创建集合s = {1, 2, 3, 4, 5}# 添加元素s.add(0)# 并集s.update({7, 8, 9})# 查看元素是否在集合中print(0 in s)# 弹出一个元素print(s.pop())# 删除指定元素,如果要删除的元素不存在,则抛出 KeyError 异常s.remove(1)# 删除,但不抛出异常s.discard(1)# 求交集print({1, 2, 3}.intersection({3, 4, 5}))print({1, 2, 3} & {3, 4, 5})# 求并集print({1, 2, 3}.union({3, 4, 5}))print({1, 2, 3} | {3, 4, 5})# 求差集print({1, 2, 3}.difference({3, 4, 5}))print({1, 2, 3} - {3, 4, 5})# 是否为子集print({1, 2}.issubset({1, 2, 3}))# 是否为超集print({1, 2, 3}.issuperset({1, 2}))# 清空集合s.clear()
数值运算
# 加法print(33+725)# 减法print(33-11)# 乘法print(33*25)# 除法print(33/22)# 取余print(33 % 11)# 次方print(33**2)# 整除print(33//22)
比较运算
print(2>3)print(2==3)print(2<=3)print(2!=3)
is 与 ==
is 判断的时内存地址
== 会去调用类的 __eq__
函数来进行比较
变量与赋值
a=5
值传递与引用传递
python 的引用机制同 java,本质上都是值传递,无法实现类似于 c++ 的引用传递效果
函数
- 抽象
- 代码复用
函数定义
def sum(a,b): return a+b
副作用
函数包含一些会引起程序或系统状态变化的操作,如修改全局变量、命令行输入输出、读写文件等,这样的变化叫做函数的副作用
几个内置函数
# 获取终端的一个输入str = input('input str')# 将str转为int类型a = int(str)# 输出print(a)
python内置函数
- 数据类型相关
内置函数 | 功能 | 示例 | 示例结果 |
---|---|---|---|
dict() | 将参数转换为字典类型 | dict(a=1, b=2, c=3) | {'a': 1, 'b': 2, 'c': 3} |
float() | 将字符串或数字转换为浮点型 | float('0.22') | 0.22 |
int() | 将字符串或数字转换为整数型 | int(1.23) | 1 |
list() | 将元组、字符串等可迭代对象转换为列表 | list('abc') | ['a', 'b', 'c'] |
tuple() | 将列表、字符串等可迭代对象转换为元组 | tuple([1, 2, 3]) | (1, 2, 3) |
set() | 1.创建空集合;2.将可迭代对象转换为列表集合 | set('abc') | {'b', 'a', 'c'} |
str() | 将参数转换为字符串 | str(3.14) | '3.14' |
bytes() | 将参数转换为字节序列 | bytes(4) | b'\x00\x00\x00\x00 |
- 数值计算相关
内置函数 | 功能 | 示例 | 示例结果 |
---|---|---|---|
max() | 求最大值 | max([13, 2, 0.6, -51, 7]) | 13 |
min() | 求最小值 | min([13, 2, 0.6, -51, 7]) | -51 |
sum() | 求和 | sum([13, 2, 0.6, -51, 7]) | -28.4 |
abs() | 求绝对值 | abs(-51) | 51 |
pow() | 求次方 | pow(2, 10) | 1024 |
bin() | 转换为二进制 | bin(77) | '0b1001101' (注意结果为字符串) |
hex() | 转换为十六进制 | hex(77) | '0x4d' (注意结果为字符串) |
round() | 浮点数四舍五入 | round(4.5678, 2) | (第二个参数为小数精度) 4.57 |
- bool 值判断相关
内置函数 | 功能 |
---|---|
bool() | 判断参数是否为真,为真则返回 True,否则返回 False。「为真」指的是,表达式的结果为布尔值 True,或非零数字,或非空字符串,或非空列表 |
all() | 如果可迭代对象中的所有值,在逐一应用 bool(值) 后结果都为 True,则返回 True,否则返回 False |
any() | 如果可迭代对象中的任意一个或多个值,在应用 bool(值) 后结果为 True,则返回 True,否则返回 False |
- IO 相关
内置函数 | 功能 |
---|---|
input() | 从标准输入中读取字符串 |
print() | 将内容写入标准输出中 |
open() | 打开一个文件。之后便可以对文件做读写操作 |
- 元数据相关
内置函数 | 功能 |
---|---|
type() | 获取对象的类型 |
isinstance() | 判断对象是否是某个类(或其子类)的对象 |
dir() | 获取类或对象中的所有方法和属性;无参数时获取当前作用域下的所有名字 |
id() | 返回一个对象的唯一标识。在我们所使用的 CPython 中这个唯一标识实际为该对象在内存中的地址 |
- help
# 得到有关int函数的相关信息help(int)
- sorted
# 排序print(sorted([3,5,7,1]))
- range
# 获取一个整数序列print(range(100))
函数进阶
- 参数默认值
# 如果省略a,则a的默认值为10def f(a=10): print(a)
- 关键字参数
def f(x,y): print(x) print(y)# 这里通过指定参数名,可以颠倒参数的顺序f(y=1,x=2)
# 使用这种方式,kw能把接收到参数组合成一个mapdef f(**kw): print(kw) f(x=1,y=2,z=3)
- 任意参数列表
# 类似于java的可变参数def f(*kw): print(kw) f(1,2,3)
- 多返回值
def f(): x=1 y=2 return x,y a,b=f()
逻辑关键字
- and
- or
- not
分支语句
需要注意的是,python使用的缩进来代表c/java中的花括号
if a<18: print('未成年')elif a>=18 and a<=20: print('还年轻')else: print('成年')
循环语句
- while循环
while a>=0: print(a) a = a-1
- for循环
list = [1,2,3]for i in list: print(i)
错误处理与异常机制
异常捕获
# 捕获所有异常try: b=a/0except: print('catch exception')# 捕获某个异常try: b=a/0except ZeroDivisionError as e: print('catch exception:',e)# 捕获多个异常try: b=a/0except (ZeroDivisionError,IndexError) as e: print('catch exception:',e)# 增加finally语句,finally语句无论是否发生异常都会执行try: b=a/0except: print('catch exception')finally: print("finally")
python常见的内置异常
异常名 | 含义 |
---|---|
Exception | 大多数异常的基类 |
SyntaxError | 无效语法 |
NameError | 名字(变量、函数、类等)不存在 |
ValueError | 不合适的值 |
IndexError | 索引超过范围 |
ImportError | 模块不存在 |
IOError | I/O 相关错误 |
TypeError | 不合适的类型 |
AttributeError | 属性不存在 |
KeyError | 字典的键值不存在 |
ZeroDivisionError | 除法中被除数为 0 |
抛出异常
try: raise ValueError("参数错误")except ValueError as e: print('catch exception:',e)
面向对象
查看数据类型
print(type(''))
类的定义
class Person: pass # pass是占位符
实例化
p = Person()
属性
class Person: # 增加构造器参数,self,定义时必须有这个参数,但是调用时不必传递,等同于this def __init__(self,firstName,lastName): self.firstName = firstName self.lastName = lastName# 创建对象时传入参数p = Person('c','xk')# 访问属性print(p.firstName)
方法
class Person: # 省略... def say(self): print(self.firstName+self.lastName)# 调用方法p.say()
进阶
- 类属性与类方法
class Person: # 定义一个类变量 people = '70亿' # 定义一个类方法 @classmethod def go(klass): print(str(klass)+'go')# 使用print(Person.people)Person.go()
- 静态方法
class Person: ... # 定义一个静态方法,区别在于不用传入klass @staticmethod def go0(): print('static go')
- 私有属性
class Person: # 定义一个类私有属性 __people = '70' @classmethod def f(klass): print(Person.__people) def f1(self): # 私有成员变量 self.__age=15 return self.__agePerson.f()p = Person()print(p.f1())# 会抛异常p.__age# 会抛出异常print(Person._people)
- 特殊方法
头尾有双下划线的方法都是特殊方法
__init__()
用于对象的初始化。在实例化类的过程中,被自动调用,就是构造器
__next__()
对迭代器调用 next() 函数,便能生成下一个值。这个过程的背后,next() 调用了迭代器的 __next__()
方法
__len__()
实现了 __len__()
方法,调用 len() 函数时将自动调用容器的__len__()
方法
__str__()
在使用 print() 函数时将自动调用类的 __str__()
方法,toString()
__getitem__()
'abc'[2] 即等同于 'abc'.__getitem__(2)
- 类继承
class Animal: def run(self): print('animal run')class Dog(Animal): def __init__(self): # 调用父类的构造器 super().__init__() # 覆写父类的方法 def run(self): print('dog run') def bark(self): print('wolf wolf')dog = Dog()dog.run()dog.bark()
- 多继承
class MachineDog: def kill(self): print('machine dog kill you')class Dog(Animal): ...class KillingMachineDog(Dog,MachineDog): passsuperDog = KillingMachineDog()superDog.bark()superDog.kill()
模块和包
模块的导入
# 导入模块import random# 使用模块print(random.randint(1,9))
包
/├── main.py├── 模块1.py├── 模块2.py├── 子包1/ ├── __init__.py ├── 模块3.py └── 模块4.py└── 子包2/ ├── __init__.py ├── 模块5.py └── 孙子包1/ ├── __init__.py └── 模块6.py
包的导入
import 子包1.模块3.pyfrom 子包1.模块3 import *
__init__.py
在 python3 中不是必须的
迭代器
迭代指的是通过重复执行某个操作,不断获取被迭代对象中的数据。这样的每一次操作就是就是一次 迭代
迭代器可以提供迭代功能,当我们需要逐一获取数据集合中的数据时,使用迭代器可以达成这个目的
迭代器可以不保存数据,它的数据可以在需要时被计算出来(这一特性也叫做惰性计算)
# 将容器包装成一个迭代器iterator = iter([1,2,3,4])# 不断迭代,直至迭代完抛出异常while True: print(next(iterator))
python的for循环迭代就是通过使用迭代器完成的
- 对一个容器调用 iter() 函数,获取到该容器的迭代器
- 每次循环时对迭代器调用 next() 函数,以获取一个值
- 若捕获到 StopIteration 异常则结束循环
可迭代
定义了 __iter__()
方法的类对象就是可迭代的。当这个类对象被 iter() 函数使用时,将返回一个迭代器对象
自定义迭代器
class MyIterator: # 定义了这个方法就代表是可迭代的 def __iter__(self): self.count=0 return self # 实现可迭代对象的接口 def __next__(self): self.count = self.count+1 return self.count# 使用i = MyIterator()for i in i: print(i)
生成器
yield 语句的作用和 return 语句有几分相似,都可以将结果返回。不同在于,生成器函数执行至 yield 语句,返回结果的同时记录下函数内的状态,下次执行这个生成器函数,将从上次退出的位置(yield 的下一句代码)继续执行
# 另外一种定义迭代器的方式def f(): for i in range(10): yield i# 使用i = f()for j in i: print(j)
生成器表达式
生成器 = (针对项的操作 for 项 in 可迭代对象)
# 输出0-9每个数的平方for i in (j**2 for j in range(10)): print(i)
也可以加上if语句
# 输出0-100中偶数的平方for i in (j**2 for j in range(100) if j%2==0): print(i)
字典生成式
{键: 值 for 项 in 可迭代对象}
# 生成0-10的键为i,值为i的平方的mapmap = {i:i**2 for i in range(10)}
集合生成式
# 生成0-10的集合set = {i for i in range(10)}
协程
import asyncioasync def web(): return requests.get('http://baidu.com').textasync def main(): print(await web())asyncio.run(main())
asyncio 的原理是维护一个 eventloop,每次遍历协程任务,当协程任务让出控制权,eventloop会继续遍历其他协程任务
future
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: fut = executor.submit(web) while not fut.done(): continue print(fut.result())
函数式编程
def say(): print('say')# 函数可赋值给变量并调用f = sayf()
函数作为参数
def f(callback): callback('date')def f1(x): print(x)f(f1)
lambda表达式
# 上面的函数调用也可以缩写成f(lambda x: print(x))
函数作为返回值
def f(): return lambda x,y: x+yprint(f()(1,2))
map与filter
# filter函数可对一个可迭代对象做过滤,符合过滤lambda的元素会被返回l = filter(lambda x: x%2==0,[1,2,3,4,5])print(list(l))
l = [1,2,3,4,5]# map函数则是对可迭代对象中的每个元素做处理,然后返回ret = map(lambda x: x**2,l)print(list(ret))
装饰器
自定义装饰器
def aop(fun): # 对fun进行包装,在其外层拦截参数 def wrapper(*args,**kw): print("aop拦截参数:",args[1],kw) fun(*args,**kw) return wrapperclass A: # 加上这一行等于 m = aop(m) @aop def m(self, name): print('method invoke ' + name)a = A()a.m('a')# 输出# aop拦截参数: a {}# method invokea
一些语言特性
切片
l = [1,2,3,4,5]# 负数代表倒数第几个print(l[-2])# 起始索引跟结束索引默认不写就代表是第一个/最后一个print(l[:])# 代表从0到最后一个,步长为2取一个元素print(l[0:-1:2])
赋值
# 连续赋值a = b = c = 1# 拆包x, y = 1, 2# 拆包一次接收多个元素x, *y = 1, 2, 3, 4# 交换两个元素x, y = y, x# or的使用print('' or '1') # 结果为'1' 类似于js
控制语句
# 三元表达式# 如果1=1,ret=1 否则ret=2ret = 1 if 1==1 else 2# for...else# 如果可迭代对象全部都被迭代了,就会执行else语句,否则不执行else语句,while...else同理for i in range(5): print(i)else: print('all used')# try except else,没有发生异常时,else语句会被调用try: passexcept: print('发生异常')else: print('没有发生异常')
类
# 自定义异常class BussinessException(Exception): pass
函数
# 参数类型标注 返回值类型标注def f(name:str) -> str: return 'hello'
metaclass
通过在创建类时指定 metaclass,可以控制类的创建过程
class Mymeta(type): def __init__(self, name, bases, dic): # 当 Foo 创建时,会进入到这里 super().__init__(name, bases, dic) print('===>Mymeta.__init__') print(self.__name__) print(dic) print(self.yaml_tag) class Foo(metaclass=Mymeta): yaml_tag = '!Foo' def __init__(self, name): print('Foo.__init__') self.name = namefoo = Foo('foo')
IO
打开文件
f = open('test.py','r')# 指定编码f = open('test.py','r',encoding='gbk')
读写模式
'r':只读,若文件不存在则抛出 FileNotFoundError 异常'rb': 以二进制的形式'w':只写,将覆盖所有原有内容,若文件不存在则创建文件'a':只写,以追加的形式写入内容,若文件不存在则创建文件'r+':可读可写,若文件不存在则抛出 FileNotFoundError 异常'w+':可读可写,若文件不存在则创建文件'a+':可读可写,写入时使用追加模式,若文件不存在则创建文件
文件写入
f = open('a.txt','w')f.write('a dog')
文件读取
f = open('test.py','r',encoding='utf8')# 读出全部内容print(f.read())# 读出文件行的列表print(f.readlines())
文件关闭
f.close()
文件系统操作
import os# 创建目录os.mkdir('./test')# 枚举目录下的文件for i in os.listdir('./'): print(i)# 删除目录os.rmdir('./test')# 删除文件os.remove('a.txt')# 重命名文件os.rename('test.py','test1.py')
上下文管理器
Python 的 with 语句,类似于 Java 的 try(...),在离开作用域后会自动释放资源
在被创建时,首先会调用__init__
方法,然后会调用 __enter__
方法,由 __enter__
方法返回需要被管理的对象,在离开作用域时,会调用 __exit__
方法
全局解释锁
为了实现多线程下内存管理(尤其是垃圾回收机制)的线程安全,同时 Python 通过引用计数来管理对象的生命周期,但引用计数在多线程环境中容易引发竞争条件(race conditions)。GIL 可以确保引用计数的操作是原子性的,从而避免这些竞争条件
CPython大量使用C语言库,但大部分C语言库都不是线程安全的
垃圾回收
Python 将所有对象分为三代。刚刚创立的对象是第 0 代;经过一次垃圾回收后,依然存在的对象,便会依次从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收
为了解决引用计数在发生循环引用无法回收的问题,Python 引入了一个基于跟踪的垃圾收集器 gc.collect(),其原理是通过图搜索来发现不可达的对象
序列化
- pickle(python独有)
import pickle# 序列化成二进制ret = pickle.dumps([1,2,3])print(ret)# 反序列化print(pickle.loads(ret))
- json
import json# 序列化成jsonstr = json.dumps({'a':1,'b':2})print(str)# 反序列化print(json.loads(str))
进程与线程
进程
import multiprocessingimport osdef f(): print('子进程') print('pid',os.getpid()) print('ppid',os.getppid())# 只有主进程才创建子进程if __name__ == '__main__': # 创建一个子进程 p = multiprocessing.Process(target=f) p.start() # 等待子线程运行完毕才会继续往下走 p.join()
线程
import threadingdef f(): print('sub thread')# 创建线程并启动t = threading.Thread(target=f)t.start()# 等待子线程执行完毕才继续往下执行t.join()print('main thread')
- 锁
import threadingcount = 0# 创建一个锁lock = threading.Lock()def add(): for i in range(2000000): global count # 获取锁 lock.acquire() count = count+1 # 释放锁 lock.release() print('执行完成:当前结果:',count)for i in range(10): threading.Thread(target=add).start()
安装第三方包
pip install requests --user
pbd
import pdba = 1pdb.set_trace() # 在此处暂停后可以执行一些 pbd 的脚本 比如输出变量、修改变量、跳转代码等print(a)
cProfile
使用 cProfile 可以统计代码运行的性能
import cProfile# def fib(n)# def fib_seq(n):cProfile.run('fib_seq(30)')
7049218 function calls (96 primitive calls) in 12.151 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 12.151 12.151 <string>:1(<module>)7049123/31 12.151 0.000 12.151 0.392 main.py:1(fib) 31/1 0.000 0.000 12.151 12.151 main.py:9(fib_seq) 1 0.000 0.000 12.151 12.151 {built-in method builtins.exec} 31 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 30 0.000 0.000 0.000 0.000 {method 'extend' of 'list' objects}
python编码风格
变量和函数
「全小写+下划线」
max_capacity = 10
类名
「驼峰写法」
class CodeGenerator: pass
异常名
「驼峰写法」
ValueError
常量
「全大写+下划线」
MAX_VALUE=100
模块名和包名
模块可使用「小写 + 下划线」
open_api
包名仅使用小写字母命名
requests
缩进
每级缩进应使用 4 个空格
换行
每行代码的最大字符数为 79。若某一行代码过长,可以将其换行书写
定义函数和类时,多个函数或类之间使用两个空行进行分隔
导入
import 按下列类型和顺序使用:
- 标准库导入
- 第三方库导入
- 本地库导入
注释
注释以 # 及一个空格开始行内注释和代码间至少要有两个空格分隔