Python进阶和高阶学习(持续更新)

Python是一门非常方便的静态语言,使用语法简洁,语言格式更易于让大众理解,在当今的大数据的浪潮下,Python的数据分析,机器学习等等起到了巨大的作用,因此学习Python必不可少。

当然在我看来,对于一些偏于计算机方向的同学,Python不适宜作为一门个人的主要语言,因为相对于C/C++他缺少了很多东西,比如内存,指针这些,这些关乎代码的存储和运行效率,不可或缺!

本博客将持续更新,以进阶和高阶为主,基础部分(列表,字典等等不做概述)。

go for it!

Python基础

函数

关键字:global,nonlocal

global:将变量声明为全局变量

def varible():
    global a	# 此时a是全局变量

nonlocal:将变量声明为外层变量(外层函数的局部变量,而且不能是全局变量)

# 自裁

拷贝

浅拷贝:拷贝了最外层的对象(变量名称),内部的元素只拷贝了一个引用,地址不变,把存放变量的地址值传给被赋值,最后两个变量引用了同一份地址

# the first channel
a = b
# the second channel
import copy
b = copy.copy(a)

深拷贝:外层的对象和内部的元素都拷贝(赋值)了一遍,被赋值的变量开辟了另一块地址用来存放要赋值的变量的值(内容)

import copy
b = copy.deepcopy(a)

五大高级函数

map(映射函数):把函数一次作用在列表中的每个元素上

map(func, object)
# example
def func(x):
    return x * 3

lambda(匿名函数):函数名 = lambda 形参:返回值

la = lambda x : x * 3
# x相当于func的形参,x*3是functional的返回值

reduce(累积函数):一次把序列中的元素进行累积;新把对象中的前两个元素取出,计算出一个值然后保存,依次累积

from functools import reduce
reduce(func, object)
# func函数是有两个参数的函数
# example
def func(x, y):
    return x + y

zip(拉链函数):用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表

zip([iterable, ...])
# example
a = [1,2,3]
b = [4,5,6]
zipped = zip(a,b)     # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
zip(*zipped)          # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]

filter(过滤函数):消除一个序列中不符合规律的元素

fliter(func, object)
# example
stack = [1, 2, 3, 4]
filter(lambad x : x%2 == 0, stack)

异常

异常种类

捕获异常

# 通用格式
try:
    # 监测的代码块(可能发生异常)
except:
    # 如果发生异常,执行此代码

# 特定异常格式
try:
    # 监测的代码块
except ErrorType as e:
    # 如果发生异常,执行此代码
    print(e)# 表示把异常输出信息放入e变量中

# 万能异常格式
try:
    # 监测的代码块
except Exception as e:
    # 如果发生异常,执行此代码
    print("报错信息是e:", e)
    
# else:没有异常时执行的代码

#finally:不管有没有异常都会执行的代码

抛出异常

# 关键字:raise
# 执行了raise后面的代码不可执行
raise Exception("xxx")

自定义异常

# 自裁

模块

.py文件,里面定义了一些函数和变量,需要的时候就可以导入这些模块

模块分类:

  • 内置模块(标准库)
  • 第三方模块(第三方库)
  • 自定义模块

导入模块

import package
from father-package import son-package
# 调用自定义模块
# 调用模块内的函数,函数,类:
1. module.func()
2. from ... import ...
# 把模块内的所有内容导入
from ... import *

模块起别名

import test as name

定义:包含__init__.py的文件夹

import导入包时,首先执行__init__.py文件的代码(不建议在__init__写太多代码)

init.py

# __init__.py的主要作用:导入这个包内的其他模块
from __init__ import other_module

# 定义一个变量列表__all__,放入要引入的模块,类等等
__all__ = ['module1', 'module2', 'module3']

module1.py

def res():
    print("YES")

go.py

from packagename import *
module1.res()	# module1是__all__列表里面的内容

递归函数

  • 一个函数在内部不调用其他的函数,而是调用他本身
  • 必须有一个明确的结束条件
  • 每进行更深一层的递归时,问题规模相比上次递归都要有所减少
  • 相邻两次重复之间有紧密的联系
  • 递归深度有限度,默认为1000
# 斐波那契
# 从第三项开始,每一项等于前两项之和

闭包

在嵌套函数的前提下,内部函数使用了外部函数的变量,外部函数返回了内部函数,则称使用了外部函数变量的内部函数称为闭包

  • 函数体嵌套了一个函数
  • 内层函数使用了外层函数的变量
  • 外层函数的返回值是内层函数的函数名
def outer():
    n = 10
    def inner():
        print(n)
    return inner
outer()	# 返回是内层函数的地址
ot = outer()
ot()	# 调用内部函数

# problem:为什么要写成这种写法:当有参数的时候,方便传参
# such as
ot = outer(m)
ot(n)

装饰器

装饰器本质上是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象

def wrapper(func):	# func是形参,但是往里面传入的值是被装饰的函数名
    def inner():
        print("是否登录:已经登录")
        func()
    return inner
def test():
    print("发表评论:很喜欢~")
# 使用装饰器来装饰函数
wr = wrapper(test)
# 调用装饰器里面的inner函数
wr()

语法糖用法:@装饰器名称

def wrapper(func):	# func是形参,但是往里面传入的值是被装饰的函数名
    def inner():
        print("是否登录:已经登录")
        func()
    return inner
# 使用语法糖的形式
@wrapper
# 被装饰的函数
def test2():
    print("it is nice")
# 直接调用被装饰的函数即可
test2()

当被装饰函数里面有参数时

def outer(fn):
    def inner(c, d):	# 如果要在被装饰函数里面传参数则在内层函数里面也要传参
        fn(c, d)
    return inner
@outer
def exam(a, b):
    print("和为:", a + b)
exam(1, 2)

被装饰的函数有可变参数

def funa(hanshu):
    def inner(*args, **kwargs):
        print("开始执行被装饰的函数")
        hanshu(*args, **kwargs)
        print("执行完成")
    return inner

def test(*args, **kwargs):
    print(*args)
    print(**kwargs)
fa = funa(test)
fa('a', 'b', 'c', 'd', name="app")
# a, b, c, d用元组来接收,name = "app"用字典来接收

多个装饰器:离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程

# the one
def maketest1(fn):
    def inner():
        print("a:fn", fn)
    return inner
# the two
def maketest2(fn):
    def inner2():
        print("b:", fn)
    return inner2
# the one of adj
@maketest1
def test1():
    return "a"
# the two of adj
@maketest1
@maketest2
def test3():
    return "阿萨德"
# the three of adj

test1()
test3()

类和对象

类:具有相同属性和功能的一切事物

对象:就是类的具体表现,是面向对象编程的核心

class 类名:
    pass

类的三要素:类名,属性(对对象的特征描述),方法(对象具有的行为)

class Hunman:
	hair = "brown"
# 看
print(Human.hair)
# 增
Human.name = "liuhao"
# 删
del Human.hair
# 改
Human.hair = "black"

对象:对象名 = 类名()

实例方法:由对象调用,至少一个self参数;执行实例方法时,自动将调用该方法的对象赋值给self

class Person:
    name = "liuhao"	# 类属性
    def speak(self):	# 实例方法
        print("liuhao is speak")
        
# 实例化对象
p1 = Person()
# 调用对象里面的方法
p1.speak()

构造方法

__init__方法:通常用来做属性初始化或赋值操作;类被实例化的时候会自动执行init方法

# the first example
class Test:
    def __init__(self):
        print("this is a init")
te = Test()

# the second example
class Hero:
    def __init__(self, name, hp, at):
		self.name = name
        self.hp = hp
        self.at = at
    def move(self):
        print(f'{self.name}在移动')
    def attack(self):
        print(f'{self.name}的生命值是{self.hp},发出了一招青莲剑歌{self.at}')
# 实例化对象
hero1 = Hero("李白", 1000, 2000)
hero1.move()
hero1.attack()
hero2 = Hero("刘浩", 2000, 3000)
hero2.move()
hero2.attack()

类属性,实例属性

1.类属性属于类,实例属性属于对象

2.类属性在内存中只保存一份,实例对象在每个对象中都保存一份

3.类属性,类可以访问到,实例属性也可以访问到;实例属性,类访问不到,实例属性可以访问到

(类属性是公共属性publish,实例属性是私有属性private)

析构方法

删除对象时,解释器默认会调用del方法

class Person:
    def __init__(self):
        print("this is a init")
    def __del__(self):
        print("this was destroyed")
p = Person()
print("这是最后一句")

# output
# this is a init
# 这是最后一句
# this was destroyed

封装

  • 类本身就是一种封装
  • 类中定义私有,只在类的内部使用,外部无法访问(在属性名和方法加上__):一般不能直接调用,需要通过另外一个类中函数来调用(类名.方法/变量),第二种直接使用self.函数名
  • 保护成员:_

继承

类间关系,描述一个类从另一个类获取成员信息的类间关系

  • 子类具有父类的所有属性和方法
# 格式:class 类名(父类名) 
class Father:
    def move(self):
        print("我是沙雕")
class Son(Father):
    def mo(self):
        print("yes")
son = Son()
# 子类的实例化对象调用父类的公有函数
son.move()		

多态

同一种事物的多种形态

静态方法

类中的函数,不需要实例,可以通过实例化对象调用

@staticmethod
def run():
    print("刘浩是小狗")

类方法

针对类对象定义的方法,类方法内可以直接访问类属性,或者调用其他类方法

@classmethod
def run(cls):		# cls是类对象
    print("刘浩还是小狗")

new方法:类名实例化对象时,python解释器会首先会调用new方法为对象分配空间,然后再执行init初始化对象

'''
 在内存总为对象分配空间
 返回对象的引用
'''

单例模式

# __init__:其实不是实例化对象调用的第一个方法

# __new__:最先调用的是__new__方法
    '''
    类名()实例化对象时,python解释器首先会调用new方法为对象分配空间,然后再执行init初始化对象
    new方法作用:
    1. 在内存中为对象分配空间
    2. 返回对象的引用
    
    '''
class Test(object):
	def __init__(self):
        print('这个是init方法')
        
    # cls代码类对象本身,如__main__.Test()
    def __new__(cls, *args, **kwargs):
        print(cls)
        print('这是new方法')
te = Test()

重写new方法

class Person(object):
    # 4. 利用这个实例对象调用init方法
    def __init__(self):
        # 5. 执行init里面的代码
		print('init')
    def __new__(cls):
		print('new')
        
        # 第一种写法
        # 1. 父类名.方法名()
        # 2. res是实例对象的引用
        res = object.__new___(cls)
        # 3. 返回res,返回对象引用
        return res
    	
        # 第二种写法
        # super().方法名()
        super().__new__(cls)
        
p1 = Person()

# output:init, new

'''
new:创建对象
init:初始化对象
'''

单例模式:是一种常见的软件设计模型,该模式的主要目的是确保某一个类只有一个实例存在,当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场

实例化不同的对象,资源分配空间不同

单例模式可以节省内存空间,实例化不同对象会产生不同的内存地址,造成资源浪费

'''
实现单例模式的方法:
1. 通过@classmethod
2. 通过装饰器
3. 通过__new__实现
4. 通过导入模块
'''
# 设计流程
# 定义一个类属性,初始值是None,用于记录仪单例对象的地址
class Exam(object):
    # 记录第一个被创建的对象引用
    ins = None
    def __init__(self):
		print('init')
    # 重写new方法
	def __new__(cls, *args, **kwargs):
        if cls.ins = None:
        	# 调用父类的new方法,为第一个对象分配空间
        	cls.ins = object.__new__(cls)
        return cls.ins

    # 单例模式,每一次实例化所创建的实例都是同一个,内存地址都一样
a1 = Exam()
print(a1)
a2 = Exam()
print(a2)
a3 = Exam()
print(a3)

# 通过装饰器实现
def outer(fn):
    # 创建一个字典来保存类的实例对象
    ins = {}
    def inner():
		if fn not in ins:
            # 创建一个对象保存在字典中
			# fn()是实例化的对象
            fn()
            # fn是类名,fn()是实例化的对象
            ins[fn] = fn()	
            return ins[fn]
    return inner

@outer	# 装饰器修饰的是Test类
class Test(object):
	pass

te = Test()

迭代器和生成器

迭代器

# for循环工作原理
# 在内部对刻碟的对象调用__iter__方法,获取迭代器对象
# 再一次次的通过迭代器对象调用__next__方法获得迭代结果
# 判断对象是否可迭代:isinstance()
for collections.abc import Iterable
isinstance(对象, Iterable)	# 返回布尔值

迭代器有两个函数:iter()和next()

iter():得到一个可迭代对象
next():获取迭代结果

生成器:python中,使用了yield的函数被称为生成器

# 原来
for i in range(30):
    print(i*2)
# 生成器,得到的结果是一个迭代器,可通过next得出
'''
1. yield语句一次返回一个结果,在每个结果中间,挂起函数,以便下次从他离开的地方继续执行
2. yield效果使函数中断,并保存中断的状态
'''
li2 = [i*2 for i in range(30)]

线程

线程是CPU调度的基本单位,每个进程至少都有一个线程,这个线程通常就是主线程。

程序启动默认会有一个主线程,自己创建的线程称为子线程。

一个进程默认有一个线程, 线程里面可以创建多个线程,线程是依附在进程里面的,没有进程没有线程。

单线程

import time
def func1():
    print('a')
    time.sleep(1)
    print('b')
    
def func2():
    print('c')
    time.sleep(1)
    print('d')

if __name__ == '__main__':
	...

模块

import threading
# 开始线程
start()
# 创建子线程
Thread()

参数

'''
target:执行的任务名
args:以元组的形式给执行任务传参
kwargs:以字典的形式给执行任务传参
'''

守护线程:主线程执行完了,子线程也会跟着结束。

# t1表示的是子线程,规定放在开启线程的前面
t1.setDaemon(True)

t1.start()

阻塞主线程:暂停的作用,等添加了join的子线程执行完,主线程才继续执行。

t1.start()
# t1表示的是子线程,规定放在开启线程的后面
t1.join()

获取线程名字

t1.getName() 

修改线程名字

t1.setName("啊啊啊!")

显示当前线程的对象名

threading.current_thread().name

线程执行代码的封装:定义一个线程类

from threading import Thread
import time

class MyThread(Thread):
    # 重构一个run方法,表示线程活动的方法
    def run(self):
        print('面向对象')
        time.sleep(2)
        print('线程')
    
if __name__ == '__main__':
    # 创建一个线程实例
    my = MyThread()
    # 启动线程,默认调用run方法
    my.start()

多线程资源竞争、线程同步

from threading import Thread
import time
# 1.资源共享
# 2.线程同步的方式:继续等待(join)、互斥锁
# 同步:有两个线程,线程A写入,线程B读取线程A的值。主线程和子线程之间各自执行完自己的代码直到结束

互斥锁:保证多个县访问共享数据不会出现数据错误问题,保证同一时刻只能有一个线程去操作

from threading import Lock
# 加锁
acquire()
# 解锁
release()

# 创建一个全局互斥锁
lock = Lock()

def jia1():
    lock.acquire()	# 加锁
    for i in range(1):
        global a
        a += 1
    print('a的值为:', a)
    lock.release()
    
def jia2():
    lock.acquire()	# 加锁
    for i in range(b):
        global a
        a += 1
    print('a的值为:', a)
    lock.release()
    
if __name__ == '__main__':
	one = Thread(target=jia1)
    two = Thread(target=jia2)
    
    one.start()
    two.start()

'''
使用互斥锁使得多任务变成了单任务,影响了效率
互斥锁如果没有使用好会出现死锁
'''

执行的任务有参数

def func(a):
    print('a的值为:', a)
    time.sleep(2)
    print('b')

def func2(b):
    print('b的值为:', b)
    time.sleep(2)
    print('c')

if __name__ == '__main__':
	f1 = Thread(target=func, args=('面向对象', ))
    f2 = Thread(target=func2, args=('面向过程', ))
    
    f1.start()
    f2.start()

进程

运行一个程序就会有一个进程

打开一个程序至少就会有一个进程,他是操作系统进行资源分配的基本单元

进程的状态:就绪态(正在等CPU执行),执行态(CPU正在执行此功能),等待态(等待某些条件满足)

基本状态

print("a")		# 程序开始,运行状态
name = input('b')		# 用户输入,进行阻塞,等待态

进程语法结构

from multiprocessing import Process

# 创建一个子进程对象
'''
参数
target:调用对象,子进行要执行的任务
args:以元组的形式传值
kwargs:以字典的形式传值

方法
start():开启子进程
is_alive():判断子进程是否还活着,存货返回True,否则返回False
join():主进程等等紫禁城执行完

属性
name():当前进程的别名
pid():当前进行的进程号
'''

if __name__ == '__main__':
    p1 = Process(target=one, name='小白')
    p1.start()
    
    p2 = Process(target=two)
    p2.name = '小刘'
    print(p1.name)
    print(p2.name)

查看各个进程的控制台命令

# cmd
cd /d C:\Windows\System32
tasklist
# 查看当前进程
import os
os.getpid()
# 查看当前进程父进程
import os
os.getppid()

进程间不共享全局变量

li = []
def wdata():
	print(li)

def rdata():
    li.append(1)
    print(li)

if __name__ == '__main__':
    f1 = Process(target=wdata)
    f2 = Process(target=rdata)
    
    f1.start()
    f1.join()
    f2.start()
'''
输出:
f1:[]
f2:[1]
'''

进程间的通信(队列):资源传输

队列queue:实现多进程之间的数据传递,queue本身是一个消息队列程序

from queue import Queue

q = Queue(n)		# n表示最多可接受三条消息
q.put()		# 放入数据
q.get()		# 取出数据
q.empty()		# 判断队列是否为空
q.qsize()		# 判断队列的长度
q.full()		# 判断队列是否为满

# 进程操作队列
from multiprocessing import Queue
while True:
    if q.empty():
        break
    else:
        print(q.get())

进程池:当需要创建的进程数量不多时,可以直接利用multiprocessing中的Process动态生成多个进程,但如果是成百上千个目标,可以用multiprocessing模块提供的Pool方法。

'''
方法
p.apply_async():异步并阻塞,不用等待当前进程执行,随时根据系统调度来进行进程切换,如果用异步提交任务,等进程池处理完,用get()收集结果
p.close():关闭进程池
p.join():主进程阻塞,等待所有工作进程退出,只能在close()后调用
'''
from multiprocessing import Pool
import time

def work(a):
    print("a")
    time.sleep(2)
    return a*3

if __name__ == '__main__':
	# 定义一个进程池,最大进程数为3
    li = []
    p = Pool(3)
    for i in range(6):
        # 异步运行,每次最多三个子进程在异步执行
        res = p.apply_async(work, args=(i, ))
        li.append(res)
    # 关闭进程池
    p.close()
    # 主进程阻塞,等待所有工作进程退出,只能在close()后调用
    p.join()
    # 使用get来获取apply_async()的结果
    for i in li:
        print(i.get())

协程

微线程,英文名coroutine,单线程下的并发。

模块

import greenlet
import gevent

# simple example 
'''
在进行多个任务时,在第一个任务进行到一半的时候需要进行第二个任务,第二个任务进行到一半的时候要进行第三个任务等待	   这种情况下,此简单例子中用yield表示	   暂停运行
'''
import time
def work1():
    while True:
    	yield 'a'
   		yield 'c'
        time.sleep(1)

def work2():
    while True:
    	yield 'b'
    	yield 'd'
        time.sleep(1)

if __name__ == '__main__':
    w1 = work1()
    w2 = work2()
    while True:
    	print(next(w1))
    	print(next(w2))
        time.sleep(1)

使用场景

如果一个线程里面io操作(网络等待,文件操作)比较多,协程就比较适用,适合高并发处理

'''查看模块'''
pip list
'''安装模块'''
pip install module
'''写在模块'''
pip uninstall module

IO操作:input、output,常见的有文件操作和网络等待

greenlet模块

'''
	用greenlet实现任务(手动)切换
	使用的是一个c的switch()切换的模块
'''
from greenlet import greenlet
def eat():
	print('eat 1')
    print('e')
def study():
	print('learn 1')
    print('ok')
# 实例化一个协程对象 greenlet(任务名)
g1 = greenlet(eat)
g2 = greenlet(study)

g1.switch()	# 切换到个g1中运行
g2.switch()	# 切换到个g2中运行

gevent模块

'''
	gevent实现任务(自动)切换
	在gevent中用到的主要模式还是greenlet
'''
import gevent

# 创建协程对象
# gevent.spawn('function', 参数)
# join:阻塞,等待某个协程执行完毕
# joinall:参数是一个协程对象列表,会等待所有的协程都执行完毕再退出
# 注意:py文件不要和第三方模块、内置模块重名

# 如果没有遇到可以识别的IO操作,不会进行任务切换
def write():
	print('a')
    # 模拟的是gevent可以识别的IO操作
    gevent.sleep(1)
    print('b')
    
def listen():
    print('c')
    gevent.sleep(1)
    print('d')
# 实例化一个协程对象
g1 = gevent.spawn(write)
g2 = gevent.spawn(listen)

g1.join()	# 等待g1对象执行结束
g2.join()	# 等待g2对象执行结束


def work(name):
    for i in range(3):
        gevent.sleep(1)
        print(f'aa{name}, i的值为{i}')
gevent.joinall([
    gevent.spawn(work, 'a'),
    gevent.spawn(work, 'b')
])

# 以下两个相等
'''
1. 
gevent.sleep(1)
2. 
monkey.patch_all()
time.sleep(1)
'''
'''
1. 进程是资源分配的单元,线程是CPU调度的基本单元
2. 
进程:切换需要的资源最大,效率最低
线程:切换需要的资源一般,效率一般
协程:切换需要的资源很小,效率最高
3.
多线程适合IO密集型操作(读写数据操作多,比如爬虫)
多进程适合CPU密集型操作(科学计算,计算圆周率,对视频进行高清解码)
'''

异步协程

正则

import re
result = re.match(正则表达式,要匹配的字符串)
# match从字符串的开始位置进行匹配,返回match对象,匹配不到返回None    
result		# 返回True或者None
result.group()		# 返回固定的值

# group()用于返回分组的值
import re
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0)   # 123abc456,返回整体
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1)   # 123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2)   # abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3)   # 456

匹配单个字符match

字符功能
.匹配任意一个字符(除了\n)
[]匹配[]中的字符
\d或者[0-9]匹配数字
\D匹配非数字
\s匹配空白,即空格和tab
\S匹配非空白
\w匹配单词字符,a-z,A-Z,0-9,_汉字
\W匹配非单词字符

匹配多个字符

字符功能
*匹配前一个字符出现0次或者无限次,即可有可无
+匹配前一个字符出现1次或者无限次,即至少有1次
匹配前一个字符出现0次或者无1次,要么没有
{m}匹配前一个字符出现m次
{m,n}匹配前一个字符出现m到n次

匹配开头结尾

字符功能
^匹配字符串开头,表示以什么开头;表示对什么取反
$匹配字符串结尾
# 表示匹配不是ab的字符
res = re.match('[^ab]', 'abcd')
# 表示匹配ab
res = re.match('^ab', 'abcd')

res = re.match('.{2}e$', 'jie')
'''
表示对于.{2}匹配到的字符是否以e结尾
'''
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妖怪喜欢风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值