再梳理一遍 Python 系列知识点,夯实基础,无他,唯手熟尔
Python 系列总结都是我自己平时的学习笔记,如果有不正确的地方,希望各位佬儿哥指正纠偏
布尔类型的变量名用 is,has 这类词语前缀
is_superuser
has_errors
allow_empty
释义为数字的单词
port
age
radius
以_id 为结尾的单词
user_id
port_id
以 length/count 开头或结尾的词
length_of_username
max_length
users_count
注:不要用名词的复数形式来作为 int 类型的变量名,因为名词的负数形式更像是一个容器。建议使用 number_of_apples 或 trips_count;
超短命名
数组索引三剑客 i、j、k
某个整数 n
某个字符串 s
某个异常 e
文件对象 fp
在 Python3.5 之后,可以使用类型注解功能来注明变量类型,在变量后添加类型,并用冒号隔开;
def repeat_message(message: str, count: int) -> str:
return message * count
input 输入的数据类型都是字符串类型
vb1 = 'Tom'
print("hello %s" % vb1)
vb2 = 5
print('有符号十进制整数:%d' % vb2)
print('输出显示位数的整数:%06d' % vb2)
vb3 = 3.1415926
print('保留两位小数:%.2f' % vb3)
print('保留三位小数:%.3f' % vb3)
vb4 = 80
print('正确率为:%d%%' % vb4)
--------------------------------------------------------------------
hello Tom
有符号十进制整数:5
输出显示位数的整数:000005
保留两位小数:3.14
保留三位小数:3.142
正确率为:80%
and:
条件 1 and 条件 2
or:
条件 1 or 条件 2
not:(取反)
not 条件
a = 10
b = 20
c = 10
if c == a and c == b:
print('right')
else:
print('error')
-------------------------------
error
a = 10
b = 20
c = 10
if c == a or c == b:
print('right')
else:
print('error')
-------------------------------
right
初始条件设置 -- 通常是重复执行的 计数器
while 条件 1:
条件满足时,做的事情 1
条件满足时,做的事情 2
条件满足时,做的事情 3
……
while 条件 2:
条件满足时,做的事情 1
条件满足时,做的事情 2
条件满足时,做的事情 3
……
处理条件 2
处理条件 1
在默认情况下,print 函数输出内容之后,会自动在内容末尾增加换行;
如果不希望末尾增加换行,可以在 peint 函数输出内容的后面增加,end=""
其中""中间可以指定 print 函数输出内容之后,继续希望现实的内容;
语法格式如下:
print("*",end="")
使用 list 函数可以把元组转换成列表
list(元组)
使用 tuple 函数可以把列表转换成元组
tuple(列表)
Python3.6 之后的字典是有序的,如果解释器版本没有那么新,也可以使用 collections 模块里的 OrderedDict 方法保证字典的有序性。
OrderedDict 与新版字典在比较上面的区别:在对比两个内容相同但顺序不同的字典时,新版字典会返回 True,OrderedDict 则会返回 False。
from collections import OrderedDict
d = OrderedDict()
d['one'] = 1
d['two'] = 2
print(d)
————————————————————
OrderedDict([('one', 1), ('two', 2)])
字典 [key]--可以从字典中取值,key 不存在会报错;
1.返回的数据类型类似列表,但不是真正意义的列表,没有 append() 方法;
2.但是可以用于 for 循环;
3.可以用 list() 方转换成真正的列表;
字典.get(key)--可以从字典中取值,key 不存在不会报错;
del 字典 [key]--删除指定键值对,key 不存在会报错;
字典.pop(key)--删除指定键值对,并且返回删除键对应的值,key 不存在会报错;
字典.pop(key, default=msg)--删除指定键值对,并且返回删除键对应的值,key 不存在不会报错,会返回 msg;
字典 popitem() 方法返回并删除字典中的最后一对键和值。
字典.clear()--清空字典;
字典 [key] = value
如果 key 存在,修改数据
如果 key 不存在,新建键值对
字典.setdefault(key,value)
如果 key 存在,不会修改数据
如果 key 不存在,新建键值对
字典.update(字典 2)--将字典 2 的数据合并到字典 1,如果字典 2 中有和字典 1 重复的键值对,则替换字典 1 中的键值对;
生成字典的方法:d = dict.fromkeys(["name","age","code"],0) #0 为默认值
-1
;step:为负,表示从右到左进行截取,start 必须在 end 之前(从右开始算前,下标必须从右到左)
s = "hello,world"
print(s[:]) # 取全部
print(s[1:]) # 从第 2 位取到最后
print(s[:-1]) # 从开始取到倒数第二位
print(s[::2]) # 步长为 2
print(s[::-1]) # 反序
指定的区间属于 左闭右开 型 [开始索引, 结束索引) => 开始索引 >= 范围 < 结束索引
从 起始 位开始,到 结束位的前一位 结束(不包含结束位本身)
从头开始,开始索引 数字可以省略,冒号不能省略
到末尾结束,结束索引 数字可以省略,冒号不能省略
步长默认为 1,如果连续切片,数字和冒号都可以省略
索引的顺序和倒序:
在 Python 中不仅支持 顺序索引,同时还支持 倒序索引
所谓倒序索引就是 从右向左 计算索引
最右边的索引值是 -1,依次递减
# 将username靠右对其,左侧补空格一共到20位
username = 'Lili'
print(f'{username:>20}')
-------------------------------------
Lili
username = 'Lily'
sore = 10
print('{0}:{0}的成绩是{1}'.format(username, sore))
s1 = set([1,2,3])
s2 = set([2,3,4])
s1.update(s2)
s1.update('hello')
print(s1)
------------------------
{1, 2, 3, 4, 'o', 'h', 'e', 'l'}
s1 = set([1,2,3])
s1.add([1])
-----------------------
TypeError: unhashable type: 'list'
集合支持集合运算,比如交集、并集、差集。所有的操作都可以用两种方式:方法和运算符;
fruits_1 = {'apple','orange','pineapple'}
fruits_2 = {'tomato','orange','grapes','mango'}
print(fruits_1 & fruits_2)
-----------------------------
{'orange'}
fruits_1 = {'apple','orange','pineapple'}
fruits_2 = {'tomato','orange','grapes','mango'}
print(fruits_1 | fruits_2)
----------------------------------------------------------
{'tomato', 'pineapple', 'orange', 'apple', 'grapes', 'mango'}
fruits_1 = {'apple','orange','pineapple'}
fruits_2 = {'tomato','orange','grapes','mango'}
print(fruits_1 - fruits_2)
------------------------------------
{'apple', 'pineapple'}
fruits_1 = {'apple','orange','pineapple'}
fruits_2 = {'tomato','orange','grapes','mango'}
print(fruits_1.symmetric_difference(fruits_2))
{'apple', 'mango', 'tomato', 'pineapple', 'grapes'}
fruits_1 = {'apple','orange','pineapple'}
fruits_2 = {'apple','orange','pineapple','water'}
print(fruits_1.issubset(fruits_2))
print(fruits_2.issubset(fruits_1))
--------------------------------------------------
True
False
lambda 返回的是该匿名函数的指针
func = lambda x,y:x*y
print(func(2,3))
实例方法
1、只能通过对象 (实例) 调用的方法
2、实例方法在定义时总是以 self 作为第一个参数
3、实例方法在调用时不需要传入 self,这个实例本身会自动传到方法中作为 self
初始化方法 (init())
1.不需要显式调用,在初始化对象时会有 python 自动调用
2.初始化方法一般只在定义对象属性的时候才会定义
类方法
1、可以直接通过类名调用的方法,也可以通过实例调用
2、类方法必须通过@classmethod装饰器进行装饰
3、所有的类方法第一个参数必须是 cls
4、类方法不能访问实例属性,只能访问类属性
属性方法
使用场景:属性方法对应的属性的值无法直接确定,要通过一系列的操作才能得到这个值,而且用户不关心这个操作过程,只想得到这个值。
定义:当成属性使用的方法,调用属性方法时不需要加 ()
静态方法
1、通过@staticmethod装饰器来进行装饰的方法
2、静态方法既不能访问实例属性,也不能访问类属性
3、可以通过类名直接调用,也可以通过对象调用
封装
暴露接口,隐藏细节
继承
1.子类通过继承直接获得父类的全部属性和方法,实现代码复用
2.初始化的几种情况:
2.1 当子类中没有定义init() 方法,则初始化子类时将默认使用父类的初始化方法,并传入对应的参数
2.2 当子类定义了自己的初始化方法,但没有调用父类的初始化方法,则父类中的相关属性不会被初始化
2.3 若在子类中重新定义了 init 方法,若仍要继承父类的属性,则需要显示调用父类的 init 方法:super().init()
多态
反射原理
通过字符串的形式在运行时动态修改程序的变量、方法及属性,所有的修改都在内存中进行,所以他并不会实际修改代码,主要目的就是提高代码在运行时的灵活性;
反射相关的方法
hasattr 输入一个字符串,判断对象有没有这个方法或属性;
getattr 获取对象属性值或方法的引用,如果是方法,则返回方法的引用,如果是属性,则返回属性的值,如果该方法或属性不存在,则抛出异常;
setattr 动态添加一个方法或属性;
delattr 动态删除一个方法或属性;
Python 异常处理依赖的关键字:
try
except
else
finally
try
try 块里面放置所有可能引起异常的代码,一个异常处理块里面只能有一个 try;
except
放置要处理的异常类型和相应语句块,用于表明该 except 要处理的异常类型;
一个异常处理块里面可以跟 1 到 n 个 except 块;
每个 except 块后面可以跟 1 到 n 个异常类型,也可以不跟任何异常类型;
else
如果 try 块里面的语句没有引起异常,则会运行 else 里面的语句;
finally
主要用于回收再 try 块里面打开的物理资源,异常处理机制会保证 finally 块一定会被执行;
异常处理语法结构
1.只有 try 是必须的
2.如果没有 try,就不能有 except 和 finally
3.except 块和 finally 块都是可选的,但 except 和 finally 必须出现其中之一,也可以同时出现
4.可以有多个 except 块,但捕获父类异常的 except 块要写在捕获子类异常的 except 块的后面
5.多个 except 块必须位于 try 块之后,finally 块必须位于所有块的最后
open (path,mode)
默认是 r:只读模式,文件必须事先存在,不主动生成文件,从文件开头开始读;
r+:读写模式,文件也必须事先存在,不主动生成文件,从文件开头开始读或写;
w:只写模式,如果用 w 模式打开,一律会清空之前文件的所有内容,如果文件不存在,则自动创建文件,从头开始写;
w+:读写模式,也会清空之前文件的所有内容,如果文件不存在,则自动创建文件,从头开始写;
a:追加模式,只写,不会清空以前文件的内容,主动生成文件,从文件尾开始写入;
a+:追加模式,读和写,不会清空以前文件的内容,主动生成文件,从文件尾开始写入或读取;
二进制读写,一般用于图片或音视频:rb+,wb+,ab+;
查看和设置文件指针位置:
with open('user.txt', 'a+') as f:
# 将文件指针重置至开始位置(这样就不会导致f.readlines()读不到数据了)
f.seek(0)
# 返回文件指针位置
print(f.tell())
with 是 python 中的上下文管理器,它会自动帮你管理文件的句柄
with open(r'D:\testlog.txt') as f:
for line in f.readlines():
print(line,end='')
文件与文件夹
windows 文件路径用反斜线,Linux 文件路径用正斜线,要想将程序在不同系统上运行,则可用 os.path.join() 方法;
myFiles = ['accounts.txt','details.csv','invite.docx']
for filename in myFiles:
print(os.path.join('c:\\User\\asweigart',filename))
-----------------------------------------------------------------------------------------
c:\User\asweigart\accounts.txt
c:\User\asweigart\details.csv
c:\User\asweigart\invite.docx
其余相关知识点附张图吧:
概念
程序:指的是一段静态的代码指令;
进程:正在执行的程序,将静态的执行代码运行起来,进程内拥有该程序执行所需的全部资源;
线程:是指正在执行程序的最小单元。一个进程中至少必须有一个线程(主线程),在程序中线程是独立的可运行的流;
多线程:在单个程序中同时运行多个不同的线程,完成不同的工作;
进程特征
独立性:进程是系统中独立存在的实体,拥有独立的资源空间;
动态性:进程拥有自己的生命周期;
并发性:多个进程可以在单个处理器上并发执行,互不影响;
线程特征
每个线程都有自己的堆栈,自己的程序计数器,自己的局部变量,这里体现了程序的独立性;
在相同父进程下的所有线程共享进程内所有资源,可以实现线程间的消息互通;
多个线程之间也可以并发执行,互不影响;
创建多线程-threading
1.使用 threading 模块的 Thread 类的构造器创建线程对象。在创建线程对象时使用 target 参数指定函数线程的执行体;
2.调用线程对象的 start() 方法启动线程;
通过 join 方法去阻塞主线程
d = Demo()
t1 = threading.Thread(target=d.music,args=('摇篮曲',))
t2 = threading.Thread(target=d.movie, args=('灰太狼',))
t1.start()
t2.start()
t1.join()
t2.join()
设置守护线程
主线程结束后立即结束所有设置为守护线程的子线程;
多线程锁
import threading
balance = 0
lock = threading.RLock()
def change_it(n):
lock.acquire()
try:
global balance
balance += n
balance -= n
finally:
lock.release()
def run_threading(n):
for i in range(100000000):
change_it(n)
t1 = threading.Thread(target=run_threading, args=(5,))
t2 = threading.Thread(target=run_threading, args=(5,))
t1.start()
t2.start()
t1.join()
t2.join()
什么是 GIL 全局解释器锁:
GIL(Global Interpreter Lock)是 Python 的一个重要特性,它是一种机制,用于保护多线程环境下共享内存数据的完整性。它锁定了整个解释器,只允许一个线程同时执行 Python 字节码,从而避免多线程下出现数据竞争问题。这意味着即使使用多核 CPU,Python 程序也不能充分利用多核优势。GIL 在性能上可能带来一定的影响,因此不适合处理需要大量的 CPU 运算的任务。
什么条件下会释放 GIL:
当前活跃线程遇到 IO 等待,比如要访问网络或建立数据库链接等情况;
活跃线程执行了 100 个字节码的程序后,GIL 也会释放该线程的锁,然后与其他线程参与竞争;
python 的多线程适合场景:
python 的多线程只适合于 IO 密集型应用,对于计算密集型的应用最好使用多进程或协程的方式解决;
通俗的说,可迭代对象就是可以放在 for 循环内进行迭代的对象
比如列表、字典、元祖、字符串;
判断一个可迭代对象的依据是什么:
必须至少实现getitem或iter这两个方法中的其中一个
特点:
生成器中每次遇到 yield 关键字之后,会返回相应的结果;
保留函数当前的运行状态,等待下一次调用,下次调用时将从上一次返回 yield 语句处开始执行后面的语句;
生成器的 send 方法可以向函数体内去传递值;
对于 next 和 send 方法的异同:
next 和 send 都可以去调用一次生成器,从调用生成器的角度来说,他们的作用完全一样;
next 无法像生成器内部的变量赋值,但 send 可以;
next(gen) 等同于 send(None),可以互换;
在生成器中使用 for 循环
每一次 for 循环相当于调用一次 next;
for 循环会自动帮助我们处理 stopIteration 异常;
定义
装饰器本质是函数,只是它的作用是为其他函数添加特定的附加功能;
编写装饰器的原则
装饰器一定不能修改被装饰器的函数的源码;
装饰器一定不能修改被装饰的函数的调用方式;
实现装饰器的前置知识条件
1.函数即变量
函数和普通变量的存储原理是一样的,函数名可以像变量名那样去使用,比如可以进行赋值;
2.掌握高阶函数相关知识
符合下面任意条件之一即为高阶函数
条件一:接收函数名作为参数
条件二:返回值中包含函数名
3.掌握函数嵌套相关知识
通过 def 关键字在一个函数 A 中去定义另外一个函数 B,则函数 B 称为嵌套函数;
4.装饰器=高阶函数 + 嵌套函数
了解装饰器的本质优势
1.运行时校验:在执行阶段进行特定校验,当校验不通过时终止执行:
Django 框架中的用户登录态校验装饰器@login_required;
2.注入额外参数:在函数被调用时自动注入额外的调用参数:
unittest.mock 模块的装饰器@patch;
3.缓存执行结果:通过调用参数等输入信息,直接缓存函数执行结果:
functools 模块的缓存装饰器@lru_cache;
4.注册函数:将被装饰函数注册为某个外部流程的一部分:
Flask 框架的路由注册装饰器@app.route;
5.替换为复杂对象:将原函数 (方法) 替换为更复杂的对象,比如类实例或特殊的描述符对象:
静态方法的装饰器@staticmethod;
正则表达式匹配步骤:
1.import re
2.用 re.compile() 函数创建一个 Regex 对象(记得使用原始字符串)
3.向 Regex 对象的 search() 方法传入想查找的字符串。它返回一个 Match 对象(一般用 mo 接收)
4.调用 Match 对象的 group() 方法,返回实际匹配的字符串
demo:
import re
>>> phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
>>> mo = phoneNumRegex.search('my number is 415-555-4242.')
>>> mo.group(1)
'415'
>>> mo.group(2)
'555-4242'
>>> mo.group()
'415-555-4242'
>>> mo.group(0)
'415-555-4242'
额外:
我在学习中,发现正则表达式在任何语言中都占有很大部分的占比,但正则表达式相关的知识点又过于零碎,对于榆木脑袋的我真是学一遍忘一遍。在实际工作中,我自己真正用到正则的地方并不多,再看同事,目前就发现前端同学有可能会用到正则去做一些事情,并且用到的时候都是度娘,一是自己真记不住,二是度娘 copy 过来的多数情况是比自己写要严谨的多的。基于此,我把正则视为投入产出比太低的事情,仅需要记住个大概印象,真到用时能分清度娘上哪个轮子能用哪个轮子用不了就可以了。