1.冒泡排序
时间复杂度O(n^2) 选择、插入都是
def bubble(data, reverse):
for i in range(len(data)-1):
for j in range(len(data)-i-1):
if data[j] > data[j+1]:
data[j], data[j+1] = data[j+1], data[j]
if reverse:
data.reverse()
return data
2.快速排序
时间复杂度O(nlogn)
思路先选择一个pivot,然后左右两个指针,不断向中间比较,如果碰到不符合的就交换,直到两个指针位置相等,然后返回相等位置作为分割点,之后利用递归不断进行排序。
#快速排序
def parition(arr, low, high):
pivot = arr[low]
while low < high:
while low < high and arr[high] >= pivot:
high -= 1
arr[low], arr[high] = arr[high], arr[low]
while low < high and arr[low] <= pivot:
low+=1
arr[low], arr[high] = arr[high], arr[low]
return low
def quick_sort(arr, low, high):
if low < high:
pivot = parition(arr, low, high)
quick_sort(arr, low, pivot-1)
quick_sort(arr, pivot+1, high)
return arr
list = [8, 5, 1, 3, 2, 10, 11, 4, 12, 20]
arr = quick_sort(list, 0, len(list)-1)
print(arr)
3.requests介绍,发起HTTP请求的 强大类库,调用简单,功能强大。
requests
是一个用于发送 HTTP 请求的 Python 库,被广泛用于网络请求、数据抓取、API 调用等任务。它以简单、直观的方式让开发者能够方便地进行各种类型的 HTTP 请求(如 GET、POST、PUT、DELETE 等),并处理服务器返回的响应数据。
3. 读取键盘输入
def forinput():
input_text = input()
4.enumerate
内置函数,用于将一个可遍历的数据对象(如列表,元组,或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在for循环中;
for counter, value in enumerate(some_list):
print(counter, value)
5.正则表达式 re模块
正则表达式(Regular Expression,简称 regex)是一种用于模式匹配和文本处理的强大工具。在 Python 中,通过 re
模块使用正则表达式,可以进行字符串查找、匹配、替换等操作。以下是正则表达式中常用符号和它们的具体用法:
cat log.txt | sort | uniq -c | sort -nr | head -n 5
cat log.txt
将文件内容输出到管道。sort
排序,为uniq
统计相同行做准备。uniq -c
统计每行出现次数。sort -nr
按次数排序,从多到少。head -n 5
显示前 5 行结果。
6.字典转json字符串
dict1 = {'name': '萝卜', 'age': 18}
dict1_new = json.dumps(dict1)
print(dict1_new)
{"name": "\u841d\u535c", "age": 18}
{"name": "\u841d\u535c", "age": 18}
是字典转换后的 JSON 字符串。\u841d
和\u535c
是萝卜
这个字符串的 Unicode 转义表示。它们对应的汉字是萝
和卜
,在 JSON 格式中,汉字会被转换为 Unicode 转义序列以确保兼容性。-
总结
- 这段代码的作用是将一个 Python 字典转换为 JSON 字符串,以便于数据交换、存储等。
- 输出的字符串可以被解析回 Python 字典,也可以被其他编程语言理解,因为 JSON 是一种通用的数据格式。
7.继承
一个类继承自另一个类,可以说是一个子类、派生类,继承自父类、基类
同时获得所有的类成员。继承是我们可以重用代码,还可以更好创建和维护代码;
python支持的继承:
- 单继承:一个子类类继承自单个基类
- 多重继承:一个子类继承自多个基类
- 多级继承:一个子类继承自一个基类,而基类继承自另一个基类
- 分层继承:多个子类继承自同一个基类
- 混合继承:两种或两种以上继承类型的组合
8.tuple和list转换
>>> tuple1 = (1, 2, 3, 4)
>>> list1 = list(tuple1)
>>> print(list1)
>>> tuple2 = tuple(list1)
>>> print(tuple2)
9.Python 的断言就是检测一个条件,如果条件为真,它什么都不做;反之它触发一个带可选错误信息的 AssertionError
。
10.异步非阻塞
同步异步指的是调用者和被调度用者关系
所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用不会返回,一旦调用返回就得到了结果;
异步和同步相对,调用发出之后就直接返回了,所以没有返回结果,当该异步功能完成后,被调用者可以通过状态、通知或回调来通知调用者;
阻塞非阻塞是线程或进程之间的关系。
阻塞调用是指调用结果返回之前,当前线程会被挂起(如遇到io操作)。调用线程只有在得到结果之后才会返回。函数只有在得到结果之后才会将阻塞的线程激活
非阻塞和阻塞的概念相对应,非阻塞调用指在不能立刻得到结果之前也会立刻返回,同时该函数不会阻塞当前线程
总结
- 同步 vs 异步:同步等待任务完成才继续,异步不等待任务完成就继续。
- 阻塞 vs 非阻塞:阻塞会暂停线程等待任务完成,非阻塞不会暂停线程,会继续执行。
11.删除操作系统上的文件
>>> f = open('test.txt', 'w') # f 文件对象
>>> f.close()
>>> os.listdir() # 当前目录下文件
['.idea',
'test.txt',
'__pycache__']
>>> os.remove('test.txt')
>>> os.listdir()
['.idea',
'__pycache__']
12.简述logging模块
python内置标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:
- 可以通过设置不同的日志等级,在 release 版本中只输出重要信息,而不必显示大量的调试信息
- print 将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging 则可以由开发者决定将信息输出到什么地方,以及怎么输出。
13.字符串字符出现个数
>>> from collections import Counter
>>> str1 = "nihsasehndciswemeotpxc"
>>> print(Counter(str1))
Counter({'s': 3, 'e': 3, 'n': 2, 'i': 2, 'h': 2, 'c': 2, 'a': 1, 'd': 1, 'w': 1, 'm': 1, 'o': 1, 't': 1, 'p': 1, 'x': 1})
14. re.compile
import re
# 编译正则表达式,匹配数字
pattern = re.compile(r'\d+')
# 使用编译后的正则表达式对象进行查找
text = "The numbers are 123, 456, and 789."
matches = pattern.findall(text)
print(matches) # 输出 ['123', '456', '789']
re.compile()
将正则表达式编译成对象,便于高效、可读地执行多次匹配操作。- 编译后的对象包含丰富的方法,可以灵活地进行各种正则操作,提高代码的性能和组织性。
15. 捕获异常
16.反转列表,一道题目leetcode,不使用额外空间
import datetime
def dayofyear():
year = input("请输入年份: ")
month = input("请输入月份: ")
day = input("请输入天: ")
date1 = datetime.date(year=int(year), month=int(month), day=int(day))
date2 = datetime.date(year=int(year), month=1, day=1)
return (date1 - date2).days + 1>>> dayofyear()
请输入年份: >? 2022
请输入月份: >? 5
请输入天: >? 23
143
5.字符编码,字符串也是一种数据类型
8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111=十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535
,4个字节可以表示的最大整数是4294967295
。
由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII
编码,比如大写字母A
的编码是65
,小写字母z
的编码是122
。
但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312
编码,用来把中文编进去。
!!!Unicode字符集,这种编码把所有语言都统一到一套编码里,就不会出现乱码问题;
Unicode与ASCII编码区别:ASCII编码是一个字节,而Unicode编码通常是2个
!!UTF-8编码即针对Unicode的编码做了针对性的修改;
搞清楚了ASCII、Unicode和UTF-8的关系,我们就可以总结一下现在计算机系统通用的字符编码工作方式:
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
所以你看到很多网页的源码上会有类似<meta charset="UTF-8" />
的信息,表示该网页正是用的UTF-8编码。
总结:字符编码方案发展ASCII->Unicode->UTF-8,总的来说Unicode的出现是为了解决ACSII没有中文等其他国家字符的方案,但是使用了Unicode后,虽然补充了其他字符,但是会出现存储空间的问题,就是说即使文本大多数英文但是使用了Unicode那么会比ASCII编码多一倍的存储空间,十分不划算,为了解决这种就引出了可变长编码UTF-8,相当于对不同的字符做了自适应长度编码,这样使用的时候就不会出现Unicode那样编码所需空间全为2倍的情况;
UTF-8适用于保存,传输;读取的时候转成Unicode;
Python字符用Unicode编码;
ord():字符转整数
chr():编码转字符
这段话的意思是解释 Python 中 str
和 bytes
类型的区别:
-
'ABC'
是一个字符串 (str),表示一串字符。Python 的str
类型通常是 Unicode 字符串,每个字符可以占用多个字节,这取决于字符编码(如 UTF-8, UTF-16 等)。 -
b'ABC'
是一个字节序列 (bytes),表示一组原始字节数据。它是用字节来存储的,因此每个字符都严格占用一个字节(8 位)。在这种表示法中,每个字符的范围是 0 到 255,对应 ASCII 码的范围。
虽然 str
类型和 bytes
类型在内容上看起来一样(例如 'ABC'
和 b'ABC'
都会显示 ABC
),但它们的存储方式和处理方式不同:
-
'ABC'
(str 类型)中的每个字符是 Unicode 字符,通常在 Python 内部是使用多字节编码存储的,比如 UTF-8 编码时,一个字母可能会占用 1 个字节,但其他非 ASCII 字符可能会占用多个字节。 -
b'ABC'
(bytes 类型)中的每个字符直接映射为一个字节(例如 ASCII 码)。每个字节严格只占用 1 个字节,因此它的表示更加紧凑。
换句话说,虽然在内容上 'ABC'
和 b'ABC'
看起来相同,但 str
是面向字符的高层次抽象,bytes
是面向字节的低层次抽象。
计算str包含多少个字符,len('ABC')
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行
#!/usr/bin/env python3 # -*- coding: utf-8 -*-
第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;
第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
申明了UTF-8编码并不意味着你的.py
文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8编码。
如果.py
文件本身使用UTF-8编码,并且也申明了# -*- coding: utf-8 -*-
,打开命令提示符测试就可以正常显示中文:
字符串格式化
-
%2d
表示以至少 2 个字符宽度的形式输出一个整数 (d
代表十进制整数)。数字 3 将被格式化为右对齐,占两个字符的位置。如果数字不足 2 位,则前面补空格。 -
%02d
表示以至少 2 个字符宽度的形式输出一个整数,并且如果不足 2 位,前面补0。数字 1 将被格式化为两位的整数,即01
。
6.list And tuple
list
Python内置的一种数据类型是列表:list。list是一种有序的集合,可以随时添加和删除其中的元素。
tuple不可变
7.函数的参数:
di
8.递归
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试fact(1000)
:
9.生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
10.迭代器
是的,生成器在每次遇到 yield
时会被阻塞(或说暂停)并保存当前的执行状态,等到下一次调用 __next__()
方法时继续从上次暂停的地方执行。而迭代器的 __next__()
方法执行完之后不会自动暂停或阻塞,而是继续执行或抛出 StopIteration
异常。
生成器的阻塞机制:
- 当生成器函数执行到
yield
时,它会将当前的值“产出”(yield
出去)并暂停执行。这意味着函数的执行状态(局部变量、代码的当前行等)被保存起来,直到下次调用__next__()
时继续执行。 - 生成器的这种暂停机制类似于一种协程的行为,使它非常适合按需生成数据,避免一次性生成大量数据带来的内存开销。
迭代器不会自动阻塞:
- 迭代器是通过手动实现
__next__()
方法来定义每次迭代的逻辑。迭代器的__next__()
方法会一直执行,直到返回下一个值,或抛出StopIteration
异常。迭代器的执行过程是线性的,不会像生成器那样在特定的位置暂停。 - 迭代器执行完一次迭代后会直接返回下一个值,不会在中间的某个地方保存状态并暂停。
11.函数式编程
1.高阶函数
函数和函数调用:变量可以指向函数,函数名也是变量,其实就是指向函数的变量
>>> f = abs >>> f(-10) 10
既然变量可以指向函数,函数可以接受变量,那么函数也可以接收函数
小结
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
2.map和reduce()
map()
函数接收两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
r = map(int,[1,2,3,-4,-5])
list(r)
此处返回的r是一个迭代器,是惰性序列需要通过list()函数将整个序列计算出来并返回一个list;
再看reduce
的用法。reduce
把一个函数作用在一个序列[x1, x2, x3, ...]
上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算,其效果就是:
3.filter()
注意到filter()
函数返回的是一个Iterator
,也就是一个惰性序列,所以要强迫filter()
完成计算结果,需要用list()
函数获得所有结果并返回list。
4.sorted()
返回一个新的list
3.返回函数
这里最关键的说就是闭包,内部函数掉的是外部函数的引用 [lambda x:i*x for i in range(4)]
请再注意一点,当我们调用lazy_sum()
时,每次调用都会返回一个新的函数,即使传入相同的参数:
对外层变量赋值,但是内层函数又没有实现初始化,会报错的因此需要nonlocal x来声明
对,你理解得很准确!每次调用 f()
,fn()
都会访问并修改 inc()
作用域中保存的那个 x
,因为 inc()
的作用域在 fn()
内部函数被返回后依然存在。这个过程确保了每次调用 f()
时,x
都会基于上次的值继续递增。
总的来说,inc()
的作用域持续存在,并且 fn()
持有了对这个作用域的引用,因此每次调用 f()
时,都在对同一个 x
变量进行操作。这就是为什么 x
的值会不断增加的原因。
你可以把这个看作是闭包(closure)的一个经典应用,闭包允许函数 "记住" 它们所在的作用域,即使这个作用域的函数已经执行完毕并返回。
很高兴你理解了这个概念!
4.匿名函数
5.装饰器
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print('call %s():' % func.__name__)
return func(*args,**kw)
return wrapper
import functools def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator
带有参数的装饰器,再嵌套一层;
所以说装饰器就是在不修改原函数本身的基础上额外添加功能,实现就是通过返回函数;
即使用wrapper函数,里面添加额外功能,然后函数返回值是原函数,并且执行流程是:
我们来剖析上面的语句,首先执行log('execute')
,返回的是decorator
函数,再调用返回的函数,参数是now
函数,返回值最终是wrapper
函数。
装饰器就是基于闭包实现的,通过接受一个函数作为参数,在内部定义一个新函数来扩展或修改原函数的行为,最总返回新函数;
闭包是指一个函数(通常是内嵌函数)记住了它所在作用域中的变量,即使这个作用域已经结束,该函数依然可以访问这些变量。换句话说,闭包是“带有环境变量的函数对象”。
放到装饰其中,原函数就是变量,内部函数调用这个变量,
装饰器如何使用闭包
当装饰器定义一个内部函数(如上例中的 wrapper
),并且该内部函数引用了外部函数(decorator
)中的变量时,就形成了闭包。这个闭包会记住 func
(被装饰的函数),即使外部的 decorator
函数执行完毕,wrapper
仍然可以访问并调用 func
。
装饰器中的闭包作用:
-
状态保持:装饰器中的闭包可以记住外部函数中的状态变量,并在需要时对其操作。这非常适合扩展函数功能,而不改变函数本身的定义。
-
延迟执行:闭包会延迟对装饰器中引用变量的操作,直到闭包被调用时才进行操作。这允许灵活的控制函数的执行时机和行为。 就是Wrapper这个函数名,返回的只是函数名;
6.偏函数
int2 = functools.partial(func,base=?)
就是把某个函数的参数固定;
4.
模块
有点像类的私有成员变量只能通过公有函数来访问
2.关于模块导入 也是经常碰到的问题
这里提供两种解决方案:1直接再环境变量里面添加
2.通过 sys.path先查看,然后sys.apth.append(path)
5. 面向对象编程OOP,是一种程序设计思想;对象作为程序的基本单元,一个对象包含了数据和操作数据的函数;
面向过程的程序设计将计算机程序看做一系列命令的集合,即一组函数的顺序执行;
面向对象的程序设计将计算机程序看作一组对象的集合,而每个对象都能接收到其他对象发过来的消息,并处理这些消息;计算机程序的执行就是一些列消息在各个对象之间传递;
2.访问限制:有点像C++的private,只能通过方法来访问私有变量;
3.继承和多态
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial
实现了run()
方法,因此,Dog
和Cat
作为它的子类,什么事也没干,就自动拥有了run()
方法:
继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog
还是Cat
,它们run()
的时候,显示的都是Animal is running...
,符合逻辑的做法是分别显示Dog is running...
和Cat is running...
,因此,对Dog
和Cat
类改进如下:
当子类和父类都存在相同的run()
方法时,我们说,子类的run()
覆盖了父类的run()
,在代码运行的时候,总是会调用子类的run()
。这样,我们就获得了继承的另一个好处:多态。
继承:获得父类的全部功能,重写功能
多态:
多态的好处就是,当我们需要传入Dog
、Cat
、Tortoise
……时,我们只需要接收Animal
类型就可以了,因为Dog
、Cat
、Tortoise
……都是Animal
类型,然后,按照Animal
类型进行操作即可。由于Animal
类型有run()
方法,因此,传入的任意类型,只要是Animal
类或者子类,就会自动调用实际类型的run()
方法,这就是多态的意思:
这个解释更加清楚,正是由于python是动态类型语言不像C++一样使用int a作静态类型,导致了只要对象里面有这个方法,不管是不是依赖于继承都能够实现.sound()输出;