python基础高级概述

https://blog.csdn.net/weixin_45912307/article/details/115682730

1.1环境管理

1. virtualenv的安装和应用

  • pip install virtualenv
  • pip install virtualenvwrapper-win
  • 创建一个存放虚拟环境的目录(建议命名为.env或.virtualenv)
  • 配置环境变量(变量名:WORKON_HOME,值:上面创建的虚拟环境目录路径)

2. 虚拟环境常用命令:

  • workon列出所有虚拟环境
  • workon [name] 进入指定的虚拟环境
  • deactivate 退出当前虚拟环境
  • mkvirtualenv -p python3 虚拟环境名称 创建虚拟环境(python3 可省略-p python3)
  • mkvirtualenv -p python2 虚拟环境名称 创建虚拟环境
  • rmvirtualenv [name] 删除虚拟环境

3. requirements.txt文件

  • 导出当前环境到requirements.txtpip freeze > requirements.txt
  • 使用requirements.txt恢复环境 pip install -r requirements.txt

4. pipenv的安装和使用
pipenv集成了pip、virtualenv两者的功能,且完善两者的一些缺陷。

  • 安装:pip install pipenv
  • 创建虚拟环境
    • 第一步创建目录 mkdir py3env
    • 第二步进入文件夹cd py3env
    • 第三步初始化虚拟环境 pipenv install
  • 创建好虚拟环境之后生成:一个pipfile文件和一个Pipfile.lock,项目提交时,可将Pipfile文件和Pipfile.lock文件一并提交,待其他开发克隆下载,根据此Pipfile运行pipenv install -dev生成自己的虚拟环境。
  • Pipfile.lock文件是通过hash算法将包的名称和版本,及依赖关系生成哈希值,可以保证包的完整性

5. pipenv的相关使用命令

pipenv --rm    |      删除虚拟命令
pipenv --where |     列出本地工程路径
pipenv --venv  |     列出虚拟环境路径
pipenv --py    |     列出虚拟环境的python可执行文件
pipenv graph   |     查看包依赖
pipenv lock    |     生成lock文件
pipenv --shell |     激活虚拟环境
exit           |     退出虚拟环境


1.2 编码规范

尽量避免使用from 模块名 import *
定义变量尽量避免使用小写l、大写O

1.3 项目结构

  1. readme.md 对项目的整体介绍,同时也是一份使用手册,需要时常维护更新,通常为readme.rst或readme.rst文件格式
  2. LICENSE 阐述该项目的许可说明和授权
  3. setup.py 通过setup把核心代码打包发布
  4. sample 存放项目的核心代码(随意命名)
  5. requirements.txt 存放项目的所有依赖第三方库
  6. docs 包的参考文档
  7. tests 所有的测试代码存放于该目录下
  8. makefile 用例项目的命令管理

1.4 元组和列表的原理

  1. 计算时间模块
  • timeit.timeit(stmt=‘pass’, setup=‘pass’, timer=<default timer>, number=default_number)
    • timeit() 函数有四个参数,每个参数都是关键字参数,都有默认值。
    • stmt:传入需要测试时间的代码,可以直接传入代码表达式或单个变量,也可以传入函数。传入函数时要在函数名后面加上小括号,让函数执行,如 stmt = ‘func()’ 。
    • setup:传入 stmt 的运行环境,如 stmt 中使用到的参数、变量,要导入的模块等,如 setup = 'from __main__ import func'。可以写一行语句,也可以写多行语句,写多行语句时用分号隔开。
    • 如果 stmt 和参数 setup 参数不传值,那么就失去了测试的意义,所以这两个参数是必要的。
    • timer: timer参数是当前操作系统的基本时间单位,默认会根据当前运行环境的操作系统自动获取(源码中已经定义),保持默认即可。
    • number:要测试的代码的运行次数,默认1000000(一百万)次,对于耗时的代码,运行太多次会花很多时间,可以自己修改运行次数。
  • timeit.repeat(stmt="pass", setup="pass", timer=default_timer, repeat=default_repeat, number=default_number) 函数介绍
    • repeat() 函数有五个参数,每个参数都是关键字参数,都有默认值。参数含义与timer()相同
    • repeat:表示测试要重复几次,可以理解为将相同参数的 timeit() 函数重复执行。最终的结果构成一个列表返回,repeat 默认为3次。
  • class timeit.Timer(stmt=‘pass’, setup=‘pass’, timer=<timer function>)
    • 计算小段代码执行速度的类,构造函数需要的参数有stmt,setup,timer。前两个参数的默认值都是’pass’,timer参数是平台相关的;
    • 前两个参数都可以包含多个语句,多个语句间使用分号(;)或新行隔开
  1. 命名元组
from collections import namedtuple
# namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)
# typename: 元组名字(字符串形式)
# field_names: 列表格式
student = namedtuple('student',['n_001','n_002','n_003'])
# 元组字段赋值
s = student('zhangsan','lisi','wangwu')
print(s.n_001)

1.5 字典和集合的原理

1. 空字典和空集合定义

set1 = set()
dict1 = {}

2. 集合主要作用:列表去重

list(set(list_name))
# 集合常用五个方法
s = set()
s.add(1) # 1添加一个元素
s.remove(1) # 2移除一个元素
s.update({4,5,6}) # 3追加多个元素,一般用{}
print(s) 
s.copy() # 4复制
s.clear() # 5清除

1.6 推导式

1. 列表推导式

  • [表达式 for 变量 in 旧列表 ]
  • [表达式 for 变量 in 旧列表 if 条件 ]
  • [表达式 for 变量 in 旧列表 if 条件1 and 条件2 and 条件n ]
  • if …else…
    [if的执行语句 if else else的执行语句 for 变量 in 旧列表]
# 1到100的和
sum_100 = sum([i for i in range(1,101)])
print(sum_100)
# 双if
result = [(x,y) for x in range(6) if x%2==0 for y in range(11) if y%2!=0]
# if...and...
result2 = [num for num in range(1, 101) if num % 3 == 0 and num % 5 == 0]
# if...else...
list1 = [{'name':'001','salary':1000},{'name':'002','salary':3000},{'name':'003','salary':5000},{'name':'004','salary':8000},{'name':'005','salary':10000}]
new_list = dict([[employee['name'],employee['salary']+500] if employee['salary']>5000 else [employee['name'],employee['salary']-500] for employee  in list1])

2. 集合推导式 去重功能
{}

# 集合推导式
list1 = [1,3,5,9,100]
new_set = {list+5 for list in list1 if list>5}
print(new_set)

3. 字典推导式
{表达式 for 变量 in 旧字典 if条件}

dict1 = {'jason':165,'lucy':180,'mack':190,'jack':170,'詹姆斯':200,'乔丹':225}
print({value:key for key,value in dict1.items()})
print({value for value in dict1.values() if value>=190})
print({value for key,value in dict2.items() if len(key)>4})

1.7 迭代器和生成器

1. 生成器定义:使用了 yield 的函数被称为生成器

2. 生成器表达式(用()表示),节约内存:

  • (表达式 for 变量 in range())
  • 通过yield定义生成器(相当于return)

3. 可迭代对象:

  • 可以for循环遍历的都是可迭代对象,只实现了 __iter__方法

4. 迭代器:

  • 可以被next() 函数调用并不断返回下一个值的对象称为迭代器;内部实现了 __iter()__外,还实现了__next__()

5. 生成器和迭代器的区别:

  • 生成器是迭代器的一种,
  • 生成器比迭代器多了三种方法sen()、close()、throw()
    • send() 发送数据
    • close() 关闭生成器
    • throw()
  • 生成器<迭代器<可迭代对象
from collections import Iterable,Iterator,Generator
print(isinstance([1,3,5,7],Iterable)) # 列表
print(isinstance([i for i in range(100)],Iterable)) # 迭代器
print(isinstance((i for i in range(10)),Iterable)) # 生成器

1.8 函数递归

  1. 定义:在函数调用函数自身(函数自己调用自己)

  2. 更改最大递归次数:

from sys import setrecursionlimit
setrecursionlimit(__limit=8000)
  1. 递归应用
def fun(n):
    if n == 1:  # 递归临界点,不再调用自身函数
        return 1
    else:
        return n * fun(n - 1)

"""
1 1 2 3 5 8 13 21 34 55 89
f(1)=1
f(2) =1
f(3) = f(2)+f(1)
f(4) = f(3)+f(2)
f(5)  = f(4)+f(3)
"""
def fixb(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fixb(n - 1) + fixb(n - 2)
print(fixb(10))

1.9 纯函数和匿名函数

1. 纯函数定义:
一个函数的返回结果只依赖它的参数,并且在执行过程里面没有副作用,则称为递归函数
2. 匿名函数
不需要使用def去定义,也不用给函数起名字,用过lamda表达式来定义,这种函数叫匿名函数
3.匿名函数适用场景: 简单的函数定义(只有一个表达式)

3. 匿名函数应用

from functools import reduce
def func(n):
    if n < 5:
        return n
    else:
        return False
print((lambda a, b: a * b)(1, 2))
lb = lambda a, b: a + b
print(lb(1, 3))
print(reduce(lambda x, y: x + y, range(1, 101)))
print(reduce(lambda x, y: x * y, range(1, 101)))
print(list(filter((lambda i: i < 5), [i for i in range(10)])))  # 相当于func

1.10 常用内置函数

内置函数属于纯函数

  • map函数:会根据提供的函数对指定序列做映射
map(参数1:函数,参数2:可迭代对象)
  • filter函数:函数用于过滤序列(与lambda一起用)
filter(参数1:函数,函数2:可迭代对象)
  • zip函数:函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组
# zip(参数:可迭代对象) 快速创建一个字典
z = zip(['name','age','sex','address'],['张三',18,'男','北京'])
# print(dict(z))
print(dict(list(z)))

1.11 闭包

1. 定义:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用

2. 闭包条件

  • 在外部函数中定义了内部函数
  • 外层函数返回内层嵌套函数名
  • 内层嵌套函数有引用外层非全局变量

3. 作用:实现数据锁定,提高稳定性(数据存储在__closure__中,内部引用不会对外部造成影响)

1.12 装饰器

1. 作用:满足闭包条件,入参为函数对象且装饰器返回值为函数对象

2. 装饰器应用场景

  • 登录验证
  • 函数运行时间统计
  • 执行函数之前做准备工作
  • 执行函数后清理功能
  • 日志模块

3. 装饰器修饰类:必须在内部函数返回被传入修饰的函数

4. 同一函数调用多个装饰器

  • 就近原则:从下往上装饰,从上往下执行

1.13 类和实例

python类里的三个装饰器

  • classmethod:被classmethod装饰之后,该方法就是一个类方法
  • statictmethod:静态方法:实例和类都可以调用静态方法
  • property:设定只读属性,可以像实例一样被调用
  • 类不能调用实例方法和实例属性,但实例可以调用类方法和类属性;实例和类都可以调用静态方法和propert方法

1.14 面向对象之魔术方法

1. 魔术方法定义:__init__双下划线开头和结尾的方法,称为魔术方法

2. 单例模式:一个类只有单个对象被创建

  • 1、定义一个类属性,来记录该类是否创建过对象 instance = None
  • 2、在_new_方法中对类属性做判断
    • 2.1没有创建过对象。那就创建一个(保存起来),并且修改类属性的值
    • 2.2创建过了,就将之前创建的返回出去
class MyClass(object):
    __isinstance=None
    def __new__(cls, *args, **kwargs):
        if not cls.__isinstance:
            cls.__isinstance = super().__new__(cls) # 方法1
            # cls.__isinstance = object.__new__(cls) # 方法2
            return cls.__isinstance
        else:
            return cls.__isinstance

def single(cls):
    __isinstance = {}
    def wrapper(*args,**kwargs):
        if cls in __isinstance:
            return __isinstance[cls]
        else:
            __isinstance[cls] = cls(*args,**kwargs)
            return __isinstance[cls]
    return wrapper
@single
class CustomClass:
    pass
cc1 = CustomClass()
cc2 = CustomClass()
print(cc1 is cc2)

3. 多例模式:一个类可以有多个对象被创建

4. 常用魔术方法

  • ___init__创建对象时自动调用对创建的对象进行初始化设置的
  • __del__:
  • __new__:在init方法之前执行
  • __str__:比较人性化直观,返回的信息一般给用户看的,
    • 三种方法下被触发:
      • print(obj)
      • str(obj)
      • format(obj)
    • 重写__str____repr__方法时,必须要记得写return
    • 重写__str____repr__方法时,return返回的必须是一个字符串对象。
  • __repr__:创建时最开始的信息,返回的信息一般给程序员看的
  • 两种方法下被触发:
    • repr(obj)
    • obj
  • __call__:对象被调用时触发
  • __dict__:调用时返回 类/实例 属性和方法的字典
  • 总结: :
    • 使用str函数或者print打印对象时会先优先触发str方法,没定义str方法的情况下,会再去找repr方法,如果都没有,那么就会去找父类的str方法。
    • 使用repr方法或者交互环境下输入变量,会先找自身的repr方法, 自身没有repr方法,会再去找父类的repr方法。

1.15上下文管理器

1.16 多态

1. 封装:

  • 将数据和方法放在一个类中就构成了封装。

2. 继承:

  • python中一个类可以继承于一个类也可以继承多个类,被继承的类叫父类(或者叫基类,base class) ,继承的类叫子类。

3. 多态(Polymorphism) :
指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度

  • 1.定义一个父类(Base) ,实现某个方法(比如: run)
  • 2.定义多个子类, 在子类中重写父类的方法(run) ,每个子类run方法实现不同的功能
  • 3.假设我们定义了一个函数,需要一个Base类型的对象的参数,那么调用函数的时候,传Base类不同的子类对象,那么这个函数就会执行不同的功能,这就是多态的体现
  • 鸭子类型的体现:
    • 静态语言:对于静态语言(java,C#) 来讲上面传入的对象必须是Base类型或者它的子类,否则,将无法调用run()方法。
    • 动态语言:对于动态语言python来讲, 上面传入的并不-定要是Base类型, 也可以是其他类型,只要在内部实现-个run()方法就行了,这就是鸭子类型的体现。
  • 多态的意义:开放封闭原则
    • 对于一个变量,我们只需要知道它是Base类型,无需确切地知道它的子类型,就可以放心地调用run()方法,(调用方只管调用, 不管细节)
    • 当需要新增功能,只需要新增一个Base的子类实现run()方法,就可以在原来的基础上进行功能扩展,这就是著名的“开放封闭”原则:
      • 对扩展开放:允许新增Base子类; .
      • 对修改封闭:不需要修改依赖Base类型的run()等函数;

1.16 数据和自省

1. 私有属性:_attr、__attr

2. slotos属性

  • 1.限制对象属性;
  • 2.节约内存:定义了slots属性之后,那么该对象不会再自动生成__dict__属性

3. 私有属性

  • _单下划线开头:类和实例可以访问
  • __双下划线开头:对外不能访问,为了保护这个变量(对外改了一个名字),在原有的属性名前面加了一个"_类名"

4. 自定义属性访问

  • object.__getattr__:访问属性时,如果属性不存在(出现AttrError),该方法会被触发
  • object.__getattribute__:访问属性的时候,第一时间触发该方法去找属性
  • object.__setattr__:给对象设置属性时触发
  • object.__delattr__:删除属性时被触发

5. 描述器类:
一个类中,只要出现__get____set____delete__中的任何一个,该类就被称为描述器类

  • __get__:访问属性时被触发
  • __set__:设置属性时被触发
  • __delete__:删除属性时被触发

1.17 元类

1.type: python3中所有的类都是通过type类创建出来的

2.object: python3中所有类的顶级父类都是object
3.元类定义: Python中的任何新式类以及Python 3中的任何类都是type元类的一个实例。函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类
4.python唯一内置元类: type

5.利用元类直接创建类

  • type创建类需要三个参数
    • 第一个: 类名–>str
    • 第二个:继承的父类–>tuple
    • 第三个:方法和属性 -->字典键值对的形式表示属性或者对应的方法
  • type(类名,(object,),{‘属性名’:‘属性值’,…,‘函数名’:‘函数值’})

6.自定义元类:必须继承type
字典遍历时:不允许添加或修改元素

1.18 内存管理

1. 小整数池(针对数值):
[-5,256]提前创建好,放到小整数对象池

2. intern机制:大整数池(针对字符串):

  • 只存储包含标准字符(数字、字母、下划线)的字符串,包含特殊字符的字符串不会被天添加到大整数池中

3. 可变类型和不可变类型

  • 不可变数据类型(给对象赋值时内存地址发生改变):int、string、float、tuple
  • 可变数据类型(给对象赋值时内存地址不会发生改变):list、dict、set

4. 深拷贝浅拷贝
通常只在列表嵌套列表时讨论

  • 深拷贝:浅拷贝是对于一个对象的顶层拷贝。简单理解:拷贝了引用,并没有拷贝内容
  • 浅拷贝:深拷贝是对于一个对象所有层次的拷贝(递归)

5. copy.copy

  • copy.copy对于可变类型,会进行浅拷贝
  • copy.copy对于不可变类型(元组),不会拷贝,仅仅是指向

6. 引用还是指向

  • 如果用copy.copy、copy.deepcopy对一个全部是不可变类型的数据进行拷贝,都是指向引用
  • 如果拷贝的是一个拥有不可变类型的数据,即使元组最顶层,deepcopy依然是深拷贝,而copy.copy还是指向引用

7. 垃圾回收机制:
一句话形容:引用计数机制为主,标记-清除和分代收集两种机制为辅的策略

  • 引用计数存在一个缺点:那就是当两个对象出现循环引用的时候,那么这个两个变量始终不会被销毁,这样就会导致内存泄漏。
  • 标记清除:辅助引用计数
  • 隔代回收:对象达到700个之后被触发,总共三代链表

1.19 多线程

1. 并发和并行

  • 并发:指的是任务数多于cpu核数,通过操作系统的各种任务调度算法,实现用多个任务”一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
  • 并行:指的是任务数小于等于cpu核数,即任务真正的一起执行的

2. 同步和异步

  • 同步:是指线程在访问某一资源时,获得了资源的返回结果之后才会执行其他操作(先做某件事,再做某件事);
  • 异步:与同步相对,是指线程在访问某一资源时, 无论是否取得返回结果,都进行下一步操作;当有了资源返回结果时,系统自会通知线程。

3. 互斥锁

  • 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
  • 互斥锁为资源引入一个状态:锁定/非锁定。
  • 某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定”,其他线程不能更改直到该线程释放资源,将资源的状态变成”非锁定",其他的线程才能再次锁定该资源
  • 互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性

4. 锁的优点缺点

  • 锁的好处:
    • 确保了某段关键代码只能由一个线程从头到尾完整地执行
  • 锁的坏处:
    • 阳止了多线程井发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
    • 由于可以存在多个锁,不同的线程持有不同的锁,井试图获取对方持有的锁时,可能会造成死锁

5. 死锁定义

  • 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源, 就会造成死锁。

6. GIL(全局解析器锁):概念以及对python多线程的影响

  • Python语言和GIL没有任务关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL;
  • GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码
  • 线程释放GIL锁的情况:在Io操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
  • Python使用多进程是可以利用多核的CPU资源的。

7. python单线程和多线程分别完成工作,哪个快

  • io密集型多线程快:涉及到网络、磁盘I0的任务都是I0密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待Io操作完成(因为Io的速度远远低于CPU和内存的速度)
  • cup密集型单线程快: cup密集型也称为计算密集型,任务的特点是要进行大量的计算,消耗CPU资源, 比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力

8. 队列

  1. 先入先出 Queue
  • Queue.qsize() # 返回当前队列包含的消息数量;
  • Queue.empty() # 如果队列为空,返回True,反之False
  • Queue.full() # 如果队列满了,返回True,反之False
  • Queue.get(block=True,timeout=None) # 获取队列, block表示是否等待, timeout等待时间:从队列中获取数据(不等待),队列为空会报错
  • Queue.put(item=,block=True,timeout=None) # block表示是否等待,写入队列 ,往队列中添加数据(不等待),队列已满会报错
  • Queue.get_nowait() # 相当于Queue.get(False)
  • Queue.put_nowait(item=) # 相当于Queue.put(item,False)
  • Queue.task_done() # 在完成一项工作之后,使用Queue.task.done()方法可以 - 向队列发送一个信号, 表示该任务执行完毕
  • Queue.join() # 际上意味着等到队列中所有的任务(数据)执行完毕之后,再往下,否则一直等待
  1. 后入先出队列(LifoQueue)
  2. 优先级队列(PriorityQueue

1.20 多进程

1. 进程定义:一个程序运行起来后,代码+用到的资源称为进程,进程是操作系统分配资源的基本单位

2. 进程状态

  • 就绪状态:运行的条件都已经满足了,正在等在cpu执行
  • 执行状态: cpu正在执行其功能
  • 等待状态:等待某些条件满足,例如- 一个程序sleep了,此时就处于等待态

3. 进程间通信

  • 队列 multiprocess.Queue
  • 进程池

4. Python multiprocessing.Queue()queue.Queue区别

  • Queue.Qgeue是进程内非阻塞队列。
  • multiprocess.Queue是跨进程通信队列。
  • 多进程前者是各自私有,后者是各子进程共有。
  • Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信。

1.21 多协程和异步

  • 协程存在于线程中,线程默认不会等待协程执行
  • spawn(参数1:执行的任务名)
  • join:让线程等待协程执行
  • 线程之间切换条件:GIL全局解析器锁
  • 协程之间切换条件:gevent.sleep() 耗时等待的情况下才会切换
  • gevent.monkey.patch_all() 只要耗时就会切换

进程、线程、协程间区别与联系

  • 进程是资源分配的单位
  • 线程是操作系统调度的单位
  • 进程切换需要的资源很最大,效率很低
  • 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
  • 协程切换任务资源很小,效率高
  • 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中所以是并发
  • python中的线程由于GIL锁的的存在,并不能够实现并行
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值