• Python精确指南——第四章-部署和技巧


    4       Python工程打包部署

    Python程序在提供给用户使用时,要脱离Python开发环境运行,此时,需要对python工程进行打包。

    常用的Python打包工具有PyInstaller, py2exe等。

    4.1     PyInstaller

    • 特点

    一条命令即可完成打包。

    以GPL标准许可发布,但可用于闭源商业性质的打包使用。

    早先的版本不支持Python 3.x版本,最新的版本已经支持,并且具有跨平台特性,首选打包工具。

    •   安装

    pip install pyinstaller

    pyinstaller.exe将安装到Python安装目录的Scripts目录下,和pip工具在相同路径。

    • 打包命令简介

    基本命令形式:

    pyinstaller yourprogram.py

    其中yourprogram.py是程序入口源文件。

    -p指令

    这个指令后面可以增加pyinstaller搜索模块的路径。因为应用打包涉及的模块很多。这里可以自己添加路径。不过经过笔者测试,site-packages目录下都是可以被识别的,不需要再手动添加。

    -F指令

    注意指令区分大小写。这里是大写。使用-F指令可以把应用打包成一个独立的exe文件,否则是一个带各种dll和依赖文件的文件夹。

    -w指令

    直接发布的exe应用带命令行控制台窗口,在指令内加入-w命令可以屏蔽。

    --icon指令

    为打包的exe指定图标。

    -v指令

    指定版本信息。

    以上是最常用的几个可选参数指令,更多详细功能介绍可以参考PyInstaller官网:

    http://www.pyinstaller.org/

    如果Python项目工程比较复杂,可以编写一个python脚本辅助执行打包命令。

    4.2     py2exe

    官网地址:

    http://www.py2exe.org/

    •   特点

    py2exe也是比较常用的打包工具,py2exe 是在 Distutils 的基础上扩展了一个新的 "命令"。

    所以使用py2exe进行打包,需要编写一个带有setup指令的脚本。

    • 安装

    pip install py2exe

    SourceForge网站提供有历史版本的下载:

    http://prdownloads.sourceforge.net/py2exe

    安装完成后,libsite-packagespy2exesamples目录下含有使用py2exe打包的样例。

    • 使用

    可以参考官方的使用教程:

    http://www.py2exe.org/index.cgi/Tutorial

    • 注意

    使用py2exe打包完成后,包含有一个名为library.zip的压缩包,压缩包内包含了所有python源文件编译后的的pyc或者pyo字节码文件。但是pyc和pyo很容易被反编译回Python源码,这一点需要注意。

    5       Python常用编码技巧

    5.1     Python编程规范

    Python官方PEP8标准编程规范:

    https://www.python.org/dev/peps/pep-0008/

    python集成开发环境当中介绍的PyCharm,在编码过程中自带有官方PEP8标准的编程规范提示,推荐使用。

    实际使用时,可以根据公司或者部门的代码特点进行更新或者扩展。

    5.2     时间模块

    • 等待一段时间

    import time

    time.sleep(5)

    • 获得当前时间,时间差

    方法1:

    import datatime
    
    import time
    
    start_t = datetime.datetime.now() #get current time
    
    time.sleep(3)
    
    end_t = datetime.datetime.now()
    
    tdiff = (end_t - start_t).seconds

    方法2:

    import time
    
    t1 = time.localtime
    
    time.sleep(3)
    
    t2 = time.localtime
    
    tdiff = time.mktime(t2) - time.mktime(t1)
    
    if int(my_time_diff) > 30:
    
            print “30 seconds time out”

    5.3     序列类型

    序列类型包括元组,字典和字符串,以下语法这三种类型全部适用。

    5.3.1  序列类型的访问

    以常量字符串a = “1234567890”,进行举例说明:

    • 索引访问

    >>> a[3]
    
    '4'
    >>> a[2:5]
    
    '345'
    
    >>> a[:5]
    
    '12345'
    
    >>> a[5:]
    
    '67890'
    
    >>> a[:]
    
    '1234567890'
    >>> a[2:9:2]
    
    '3579'
    
    >>> a[::2]
    
    '13579'
    >>> a[-2]
    
    '9'
    
    >>> a[::-1]
    
    '0987654321'

    5.3.2  序列类型的操作

    长度:len()

    连接:+

    重复:*

    判断元素是否在序列中:in

    最大值:max()

    最小值:min()

    比较是否相同:cmp(elem1, elem2)

    5.4     多级字典

    多级字典不能一次性赋值,比如

                  level2_dict[“lvl1”][“lvl2”] = “result”

    这样就会报错。只能分两步。

                  level2_dict[“lvl1”] = {}
    
                  level2_dict[“lvl1”][“lvl2”] = “result”

    5.5     字符串

    字符串的基本方法这里不做过多介绍,主要介绍一些字符串的实际使用技巧。

    5.5.1  字符串的打印

    Python的打印是不需要加入’ ’就能换行的,这点要注意,和其他的语言不太一样。

    5.5.2  格式化字符串

    >>> "my name is %s, I'm %d years old."%("mike", 15)
    
    "my name is mike, I'm 15 years old."
    • 字符串类format方法

    按照参数索引:

    >>> "my name is {0}, I'm {1} years old.".format("mike", 15)
    
    "my name is mike, I'm 15 years old."

    按照参数名称:

    >>> "my name is {name}, I'm {age} years old.".format(name="mike", age="15")
    
    "my name is mike, I'm 15 years old."

    5.5.3  数字和字符串转换

    my_str = str(my_num)
    
    my_num = int(my_str)
    • 通过string类方法
    >>> import string
    
    >>> a="12345"
    
    >>> string.atoi(a)
    
    12345
    
    >>> b="123.678"
    
    >>> string.atof(b)
    
    123.678

    5.5.4  正则表达式

    Python对于字符串的操作十分简单方便,结合内置正则表达式re模块,几乎可以完成所有字符串操作的需求。

    >>> import re
    
    >>> tt = "Tina is a good girl, she is cool, clever, and so on..."
    
    >>> rr = re.compile(r'w*oow*')
    
    >>> print(rr.findall(tt))
    
    ['good', 'cool']
    >>> print(re.match('comw*.', 'comwww.runcomoob').group())
    
    comwww.
    >>> print(re.search('dcom', 'www.4comrunoob.5com').group())
    
    4com
    >>> a = "123abc456"
    
    >>> print(re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(0)) # 索引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))
    >>> iter = re.finditer(r'd+', '12 drumm44ers drumming, 11 ... 10 ...')
    
    >>> for i in iter:
    
          print(i)
    
          print(i.group())
    
          print(i.span())
    
    <_sre.SRE_Match object at 0x02517F38>       # 匹配到的Match对象
    
    12                                                                                                                          # 匹配到的子串
    
    (0, 2)                                                                                                                       # 匹配到的字串的索引
    
    <_sre.SRE_Match object at 0x02526250>
    
    44
    
    (8, 10)
    
    <_sre.SRE_Match object at 0x02517F38>
    
    11
    
    (24, 26)
    
    <_sre.SRE_Match object at 0x02526250>

    替换匹配到的字串

    >>> text = "Mike is a handsome boy, he is cool, clever, and so on..."
    
    >>> print(re.sub(r's+', '-', text))
    
    Mike-is-a-handsome-boy,-he-is-cool,-clever,-and-so-on...

    并获得替换的个数:

    >>> print(re.sub("g.t", "have", 'I get A,  I got B ,I gut C'))
    
    I have A,  I have B ,I have C
    
    >>> print(re.subn("g.t", "have", 'I get A,  I got B ,I gut C'))
    
    ('I have A,  I have B ,I have C', 3)
    >>> print(re.split('d+', 'one1two2three3four4five5'))
    
    ['one', 'two', 'three', 'four', 'five', '']

    5.6     断言

    Python中的assert是判断表达式是否为True的断言关键字,例如判断实例是否属于一个类:

    assert isinstance(rsm_info_preview, RsmKeyInfo)

    5.7     系统命令

    • 路径的操作

    ll_test_path = os.path.join(os.path.dirname(__file__),"win32", "IEDriver.dll")

    os.path.dirname(__file__)表示当前file的位置。

    Import sys
    
    sys.exit()

    注意有的时候在函数和类并不能使整个程序退出,注意尽量在主函数里退出才可以。

    os.system(“xxx”)

    阻塞命令,需要等待系统命令调用完成才能返回,成功返回0,失败返回1。

    os.startfile(“xxx”)

    非阻塞命令,单纯启动命令,执行后立即返回,与目标应用不存在从属关系。相当于双击操作。

    os.popen(“xxx”)

    执行后,启动一个进程,返回文件描述符对象,利用该对象可以捕获该进程的输出。

    • 命令行

    commands模块

    纯命令行调用模块,可以获得命令的输出或(且)返回值。

    •   进程高级

    subprocess模块

    更为高级的进程管理模块,提供比os.popen更加高级的接口,可以实现复杂的多进程管理。

    5.8     lambda

    在Python中,lambda是匿名函数的关键字。

    lambda可以定义一句代码覆盖的方法或者函数。大部分情况下,lambda函数当做参数传递给其他方法或者函数,在方法或者函数内部实现动态调整计算实现的过程。类似模板方法设计模式的思路。

    5.8.1  基本语法

    >>> add = lambda x, y: x + y
    
    >>> add(2,3)

    5

    如上面例子,lambda表达式中,除了lambda关键字,冒号左边等价于def函数的入参,冒号右边等价于def函数的函数体中的return返回值。

    整个lambda表达式可以作为一个函数的引用,赋值给一个变量(即例子中的add)。

    5.8.2  常用内建函数

    lamda结合内建函数map, reduce, filter可以实现强大的序列类型(元组,列表,字符串)的处理功能。

    •  map

    内建函数map可以得到入参序列中逐个元素按照lambda函数处理后返回的序列。省去循环代码实现的过程。

                  >>> list1 = range(5)
    
    >>> print list1
    
    [0, 1, 2, 3, 4]
    
    >>> map(lambda x: x*2, list1)
    
    [0, 2, 4, 6, 8]

    如上代码实现了列表中每个元素乘2的效果。

    •  reduce

    内建函数reduce进行两两元素的迭代计算,每次迭代,将上一次的迭代结果(第一次时为initial的元素,如没有initial则为列表的第一个元素)与下一个元素一同执行一个二元的lambda函数,最终得到一个计算结果。

    >>> list1
    
    [0, 1, 2, 3, 4]
    
    >>> reduce(lambda x, y: x + y, list1)
    
    10
    
    >>> reduce(lambda x, y: x + y, list1, 2)
    
    12

    如上代码实现了列表求和的效果。

    •   filter

    该内建函数的作用相当于一个筛选器。lambda函数是一个布尔函数,filter调用这个布尔函数,将每个列表中的元素依次经过一次筛选,选出使lambda返回值是Ture的元素的序列。

    >>> list1
    
    [0, 1, 2, 3, 4]
    
    >>> filter(lambda x: x % 2 == 1, list1)
    
    [1, 3]

    如上代码实现了筛选列表中所有奇数的效果。

    5.9     字符串也是代码

    5.9.1  eval

    eval可以执行字符串参数的表达式,并返回表达式执行完成的结果。

    >>> eval("((1+2)*3.0/4)**2")
    
    5.0625
    
    >>> eval("'hello '*2")
    
    'hello hello '
    
    >>> list1 = eval("[1,0.5,[3,4], 'hello python', {1:'one'}]")
    
    >>> list1
    
    [1, 0.5, [3, 4], 'hello python', {1: 'one'}]
    
    >>> type(list1)
    
    <type 'list'>

    5.9.2  exec

    exec可以执行字符串中的代码。

    >>> exec("print 'hello python'")
    
    hello python
    
    >>> exec("for i in range(3):print i")
    
    0
    
    1
    
    2

    5.9.3  区别和使用

    eval需要传入的是一个表达式,执行完成后会返回一个结果;exec则是执行字符串内包含的python代码,并不会返回结果。两者不能混用。

    因为eval和exec的存在,大大增加了python代码的灵活性。程序可以在运行时状态动态生成代码去执行,可以留作热更新的接口,免去重新编译和打包的过程。不过也因此,带来编码安全的隐患,恶意的字符串注入,将可以执行任意代码。使用时需谨慎。

    5.10   yield

    一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

    如下就生成了一个斐波那契数列的生成器:

    >>> def fib(max):
    
    a, b = 1, 1
    
    while a < max:
    
    yield a
    
    a, b = b, a+ b
    
    >>> fib_gen = fib(15)
    
    >>> fib_gen.next()
    
    1
    
    >>> fib_gen.next()
    
    1
    
    >>> fib_gen.next()
    
    2
    
    >>> fib_gen.next()
    
    3
    
    >>> fib_gen.next()
    
    5
    
    >>> fib_gen.next()
    
    8
    
    >>> fib_gen.next()
    
    13
    
    >>> fib_gen.next()
    
     
    
    Traceback (most recent call last):
    
    File "<pyshell#100>", line 1, in <module>
    
        fib_gen.next()
    
    StopIteration

    可以看到,在使用next()的时候要注意生成器的生成边界。

    在for循环当中,会自动调用 next(),并在触发StopIteration异常时自动捕获终止:

    >>> for n in fib(15): 
    
        print n
    
    1
    
    1
    
    2
    
    3
    
    5
    
    8
    
    13

    yield的实时性更高,只有在调用的时候才真正执行,可以控制对于系统资源的消耗。

    5.11   dir, setattr, getattr,hasattr

    这四个函数是Python的内建函数,结合起来使用可以获取对象的属性信息,动态调整对象的属性和值。

    >>> class BaseClass(object):
    
        '''
    
        classdocs
    
        '''
    
        def __init__(self, first, second, third=3, forth=4):
    
            self.first = first
    
            self.second = second
    
            self._third = third
    
            self.__forth = forth
    
            print "in init"
    
        def __del__(self):
    
            print "in del"
    
        def first_func(self):
    
            print "in first func"
    
        def _second_func(self, para1):
    
            pass
    
        def __third_func(self, para1, para2=0):
    
            pass
    
    >>> A = BaseClass(1, 2)
    
    >>> dir(A)
    
    ['_BaseClass__forth', '_BaseClass__third_func', '__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_second_func', '_third', 'first', 'first_func', 'second']
    
     
    
    >>> getattr(A, "first")
    
    1
    
    >>> getattr(A, "first_func")()
    
    in first func
    
     
    
    >>> hasattr(A, "five")
    
    False
    
    >>> setattr(A, "five", 5)
    
    >>> A.five
    
    5
    
    >>> hasattr(A, "five")
    
    True

    这一组内建函数为Python的面向对象特性进行了灵活性扩展,不过完全越过了对于类中成员的保护,在使用时需要注意成员访问的权限问题。

    作者|lurayvis 撰写初稿,fhk精美更新

    Python精确指南-第四章部署和技巧.pdf

    来源:华为云社区  作者:lurayvis

  • 相关阅读:
    day50 初识JavaScript
    在C#中对Datatable排序【DefaultView的Sort方法】
    Windows Phone 中查找可视化树中的某个类型的元素
    抽象类(abstract)是否可以继承自实体类 ?
    C#遍历指定目录下的所有文件及文件夹
    Log4Net总结
    Firefox 与 IE 对Javascript和CSS的区别
    RSS 订阅
    Win8 URI 方案 ms-appX 用法大全
    ProgressIndicator显示进度条以及一些文字信息
  • 原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13165707.html
Copyright © 2020-2023  润新知