dev_1

206 阅读8分钟

python高阶编程(一)

虚拟环境及编码规范

环境管理

一、虚拟环境介绍

二、virtualenv的安装和应用

安装步骤(mac)

  1. pip安装virtualenv: pip3 install virtualenv

  2. pip安装虚拟环境管理包virtualenvwrapper: pip3 install virtualenvwrapper

  3. 创建一个存放虚拟环境的目录(建议 命名为.env或者.virtualenv):mkdir ~/.virtualenv

  4. 配置环境变量

    进入环境变量配置文件:vim ~/.bash_profile

    添加如下配置:

    # 配置python虚拟环境
    export WORKON_HOME=~/.virtualenv
    
    # 路径使用命令 which python3 获取
    export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3
    
    # 路径使用命令 which virtualenvwrapper.sh 获取
    source /usr/local/bin/virtualenvwrapper.sh
    

    执行source ~/.bash_profile使配置生效

virtualenv常用命令

电脑上同时装有python2和python3时:

在python2中,创建虚拟环境:mkvirtualenv -p python2 虚拟环境名称

在python3中,创建虚拟环境:mkvirtualenv -p python3 虚拟环境名称

pip list 已安装的包,非虚拟环境中,展示本地的安装包,进入虚拟环境输入该命令,展示该虚拟环境的包。

在虚拟环境中,使用pip install也仅在虚拟环境中安装包。

三、pipenv的安装与使用

pipenv是对pip命令和virtualenv的封装,不需要配置环境变量

如果我们没有存放虚拟环境的路径,他会自动生成一个,由于我们之前装virtualenv时创建了存放虚拟环境的路径,使用pipenv时不会生成新的存放路径。

项目目录下,输入pipenv install 安装虚拟环境。 (后面不带包名)

虚拟环境安装成功后,会生成一个Pipfile和Pipfile.lock文件,记录相关依赖包的。

Pipfile.lock文件,原则上是不能进行修改。

Pipfile文件中,url表示源地址,默认是国外源,可以换成国内源。

可换成清华源:pypi.tuna.tsinghua.edu.cn/simple

pipenv install 包名 包安装在默认环境[packages]下

pipenv install 包名 --dev 包安装在开发环境[dev-packages]下

使用pipenv graph查看包的依赖,比如安装了requests包,这个包依赖了下面四个包:

复制Pipfile和Pipfile.lock文件到另一个工程下,使用pipenv install 安装虚拟环境时,会自动安装上Pipfile文件下[packages]下的包

若想安装[dev-packages]下的包,使用命令pipenv install --dev

pipenv命令,只在当前路径下运行,所以,下面命令需进入到对应目录下运行:

四、requirements.txt文件

使用virtualenv管理虚拟环境,使用下述命令导出requirments.txt文件和恢复虚拟环境:

pipenv除了可以通过Pipfile和Pipfile.lock文件进行恢复虚拟环境,也可以使用requirments.txt文件方式恢复虚拟环境:

在pipenv中使用pipenv lock -r>requirments.txt 生成requirments.txt,恢复dev的包,命令为pipenv lock -r --dev>requirments.txt

使用pipenv install -r requirments.txt安装环境

编码规范

一、python代码规范

  1. PEP 8(python代码样式规范)

    官方: www.python.org/dev/peps/pe…

    中文翻译版: blog.csdn.net/ratsniper/a…

    主要:

    标准库,不用pip安装的。相关的第三方库,需要pip进行安装的。

    mac下调整代码格式快捷键:command+option+L 格式化代码(L大写小写都可以)

  2. PEP 257(python文档说明的书写语义和约定)

    官方: www.python.org/dev/peps/pe…

    中文翻译版: blog.csdn.net/xtydtc/arti…

  3. PEP 20(python的禅宗)

    官方: www.python.org/dev/peps/pe…

项目结构

一、工程结构化

根据项目不同会有所不同,大致如是,开源项目广泛用。

数据类型&函数进阶

数据类型

python数据类型:

数值:

序列:字符串、元组、列表

散列(特征:内部元素是无序):字典、集合

一、元组和列表

  1. 元组和列表的性能分析

    ipython是一个python的交互式shell,比默认的python shell好用得多。

    安装ipython sudo pipenv install ipython (mac不加sudo不能安装)

    安装好后输入ipython进入shell:

    配合timeit模块,这分别是计算初始化一个列表和元组1000000次的时间:

    元组比列表的性能快很多。

    列表是可变的,在内存中,开辟一块空间,当检测到列表元素快占满那块空间时,会自动给列表扩容。

    元组是不可变,内存分配了固定空间,所以更快。

    拓展:timeit模块,可以用于计算代码性能,如自己编写的函数等。

    import timeit
    
    # 初始化列表,如无参数,默认次数为100w次
    list_speed = timeit.timeit('[1,2,3,4,5,6]')
    
    # 初始化元组,如无参数,默认次数为100w次
    tuple_speed = timeit.timeit('(1,2,3,4,5,6)')
    
    print(list_speed)
    
    print(tuple_speed)
    
    
    def func_speed():
        for i in range(10):
            print(i)
    
    # 调用func_speed方法,100次所需要的时间
    res = timeit.Timer(func_speed).timeit(1000)
    print(res)
    
  2. 命名元组

    使用collections.namedtuple函数,来构造一个带字段名的元组:

    from collections import namedtuple
    
    # 创建一个具名元组,需要两个参数,一个是类名,另一个是类的各个字段名
    stu_info = namedtuple("stu_info",['name','age','gender'])
    
    # 创建一个stu_info对象
    student_info = stu_info("susan",19,"男")
    
    print(student_info)
    
    # 类型
    print(type(student_info))  # <class '__main__.stu_info'> ,即在namedtuple中定义的类名。
    
    # 类似与对象的取值方式
    print(student_info.name,student_info.age,student_info.gender)
    

二、字典和集合的原理和应用

集合和字典的常用使用方法

# 空集合
set_blank = set()
# 空字典
dict_blank = {}

# 利用集合对列表进行去重
list1 = [1,1,1,2,3,3,2,5]
list2 = list(set(list1))
print(list2)

  1. 散列类型的存储过程

    集合和字典都是无序的,称之为散列类型。

    一个知识点更新:python3.7之前,字典是无序的,3.7之后新特性,字典会按你添加的顺序保存,实际有顺序了。

  2. 字典查找值的过程

三、推导式

  1. 列表推导式

  2. 字典推导式

    使用字典推导式把字符串改成字典类型数据

    str = 'name=susan,gender=女,school=上海某大学'
    dict1 = {i.split("=")[0]:i.split("=")[1] for i in str.split(",")}
    print(dict1)
    

迭代器和生成器

  1. 生成器

    使用生成器,可用于节约内存。什么时候用,什么时候取,用哪个,取哪个。

    使用next()就计算出下一个元素的值。直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

    # 通过yield自定义生成器
    def gen_func():
        yield 100
        print("hello yield")
        yield 110
        yield 119
    
    
    res = gen_func()  # 返回生成器对象
    print(res) 
    print(next(res)) # 输出第一个yield后的值
    print(next(res)) # 输出第二个yield后的值
    print(next(res)) # 输出第三个yield后的值
    

  2. 迭代协议

  3. 迭代器

    可迭代对象:可以for循环遍历的都是可迭代对象。内部只实现了__iter__方法。

    迭代器:可以通过next()取值的。内部只实现了__iter__之外,还实现了__next__方法。

    如,列表是一个可迭代对象,但不是一个迭代器。可以通过iter(),把一个可迭代对象转为迭代器。

    list1 = [1,2,3,4,4,5]
    li = iter(list1) # 通过iter() ,触发list类里的__iter__方法
    
    print(next(li)) # 触发了li这个对象中的__next__方法
    print(next(li))
    

    生成器是迭代器的一种。生成器和迭代器的区别:

高阶函数

  1. 递归函数

    # 递归函数实现斐波那契数列
    def fib(n):
        if n <= 1:
            return 1
        else:
            return fib(n-1)+fib(n-2)
    
  2. 纯函数

常用内置函数

内置函数官网: docs.python.org/zh-cn/3.7/l…

filter():一个参数是过滤的方法、第二个参数为序列,序列的每一个参数带入到过滤方法中,为True的返回,为False的过滤掉。一般使用匿名函数进行定义,此处只是为了更明白filter()的过程。

map():会根据提供的函数对指定序列做映射。第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

# 内置函数filter()、map()
li = [1, 2, 5, 10, 2, 22]

def filter_li(n):
    return n >= 5

print("filter函数的结果:{}".format(list(filter(filter_li, li))))

print("map函数的结果:{}".format(list(map(filter_li, li))))

zip():函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

# 内置函数zip()
zip1 = zip([1,2,3],[11,22,33],[111,222,333])
zip2 = zip([1,2,3,4],[11,22,33,44],[111,222,333,444,555])
zipped = zip([1,2,3],[4,5,6])

# 将对象中对应的元素打包成一个个元组
print(list(zip1))

# 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同
print(list(zip2))

# 使用*解压
print(list(zip(*zipped)))

  1. 匿名函数

    节约内存,即用即释放,所以不推荐把方法赋值给变量,推荐直接调用。

    与filter()函数结合使用,省内存,阅读更舒适:

    li = [1, 2, 5, 10, 2, 22]
    print("filter函数的结果:{}".format(list(filter(lambda n:n>=5,li))))
    

闭包、偏函数、数据锁定

  1. 偏函数

  2. 闭包

    对外层函数非全局的变量会储存在自身的__closure__中,实现数据锁定,提高稳定性。

  3. 装饰器

    先有index()功能,现在需要在网站首页前增加账号和密码验证。不改变调用方法,使用装饰器进行新增功能。

    # 装饰器
    def login(func):
    
        def verity():
            username = input("请输入username:")
            password = input("请输入password:")
            if username == 'leitx' and password=='123':
                func()
            else:
                print("账号或密码错误")
        return verity
    
    
    @login # 语法糖:相当于index = login(index),所以调用index(),实际相当于调用verity函数
    def index():
        print("展示首页")
    
    index()
    

    参数传递示意:

    通用装饰器

    def outer(func):
    
        def check(*args,**kwargs):
            print("在原index()方法前面操作的代码")
            func(*args,**kwargs)
            print("在原index()方法后面操作的代码")
        return check
    
    @outer
    def index(*args,**kwargs):
        print("原本的功能实现")
    
    index()
    

    装饰类的装饰器

    多个装饰器装饰同一个函数

    从下往上装饰,先装饰wrapper,再装饰login_check,结果导致代码从上往下运行:先运行login_check中的代码,再运行wrapper中的代码,再运行func中的代码。

    python中类里面三个内置的装饰器

    • @classmethod 类方法

      装饰了classmethod的方法,不需要self参数,此时的self指向了类。而没有装饰classmethod的方法,self是实例本身:

      装饰了classmethod的方法,参数应该是cls,cls代表了类本身:

      类方法可以直接使用类调用 MyTest.add()和实例调用MyTest().add()

    • @staticmethod 静态方法

      不用传self参数

    • @property

      这个装饰器装饰的方法,可以像属性一样被调用。一般用于设置只读属性。

      通过调用MyTest().read_attr调用,不可对MyTest().read_attr进行修改,所以一般用于设置只读属性。

    用类实现装饰器(魔法方法时讲)