《Python忍者秘籍》:忍者让人想起不规则战术。秘籍告诉我们应用正确的技术提升代码质量、可用性以及性能。

这本书目的是深入研究python中一些开发者从未体验过的相关技术。 揭示一些鲜为人知的内容,扩宽读者视野。 接触到几种提高应用程序的速度和并发性的方法。

python模块:是python程序中的组件,一个程序可以插入其他模块,使得代码复用变得容易。****并且提供单独的命名空间。****

开发人员创建的每一个python未见都被认为是一个单独的模块,允许将不同的文件导入,形成最终应用程序的单个整体文件。

包和模块的区别有:包是多个模块的集合,包含一个__init__.py文件。 通常,一个模块内的对象,在该模块外部是不可见的。即试图调用位于单独模块中的变量将产生错误。

命名空间:是模块或组件的控制域。 命名空间举例:某个函数内部定义了一个变量,在另一个函数调用这个变量,会产生错误。 而全局变量不同,它们可以被任何函数调用并相互作用。

如果在一个函数中查找变量,查找的范围空间依次为:局部范围---全局范围---内置模块---报错。 如果使用randint()函数,就必须在之前导入其所属的random库。导入后,就可以通过<模块名>和<函数名>来进行相关调用

 

randint(0,1000)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-06399591c897> in <module>
----> 1 randint(0,1000)

NameError: name 'randint' is not defined

In [2]:

import random
random.randint(0,1000)
Out[2]:
927

 

当模块被导入程序中时,python会假定一些命名空间。如果正常导入,例如import foo,则主程序和foo都会保持他们各自的命名空间。要使用foo中的函数xxx,则需要使用点命名方法即以foo.xxx()明确的进行标识;如果模块的一部分是从foo导入的,如(from foo import bar或from foo import *),那么导入的组件就成为主程序命名空间(namespace)的一部分。

from random import randint
randint(0,10)#可以直接使用
Out[4]:
2
In [5]:

randrange(0,25)#未导入,不可直接使用
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-5-a2f2ba4c1df4> in <module>
----> 1 randrange(0,25)#未导入,不可直接使用

NameError: name 'randrange' is not defined

 

举例:

def first_func():
    x=1
    print(x)
    def second_func():
        x=2
        print(x)
    second_func()
    
first_func()

second_func()嵌套在first_func()中,对外是不可见的

 

 

可以用*通配符来代替所有函数所在的位置,来从一个模块导入所有函数,即将所有函数导入到主命名空间:(但不建议这样导入,应该使用点命名法准确调用对象,不必担心导入各种模块导致命名重复等问题)

>>> from math import *
>>> sin(45)
0.8509035245341184

 

将模块作为脚本使用的一种常见方式是直接从命令行显式调用模块,并在必要时提供所需参数。

如:

def print_func(arg):
    print(arg)  # 打印出参数内容


if __name__ == '__main__':
    import sys

    print_func(sys.argv[1])  # argv[1]表示第一个参数;argv[0]表示文件名

结果为:

(venv) lzh@192 pythoncss % python print_result.py hahah
hahah

 

同样支持多参数:

def print_func(arg1, arg2, arg3):
    print(arg1, arg2, arg3)


if __name__ == '__main__':
    import sys

    print_func(sys.argv[1], sys.argv[2], sys.argv[3])

结果:

(venv) lzh@192 pythoncss % python print_func1.py aaa  bbb   ccc
aaa bbb ccc

sys.argv()函数允许python解析命令行提供的参数,并将它们放入列表中以供使用。

sys.argv[0]是接收参数的程序名称,因此可以忽略。

 

使用*args可以接收任意数量的参数:

def print_func(*args):
    print(*args)


if __name__ == '__main__':
    import sys

    print_func(sys.argv[1], sys.argv[2], sys.argv[3],sys.argv[4])
(venv) lzh@192 pythoncss % python test3.py aaa  bbb   ccc ddd eee fff ggg zzz
aaa bbb ccc ddd

 

使用**kargs可以实现和*args相同效果,但是需要使用关键字:键值对。

 

 

什么是python虚拟环境:venv创建python虚拟环境,为虚拟环境创建pip和setuptools。python虚拟环境为特定的应用程序开发安装包,不影响系统范围。

实例:

import random


def randomNumGen(choice):
    if choice == 1:
        die = random.randint(1, 6)
    elif choice == 2:
        die = random.randint(1, 10)
    elif choice == 3:
        die = random.randint(1, 100)
    elif choice == 4:
        die = random.randint(1, 4)
    elif choice == 5:
        die = random.randint(1, 8)
    elif choice == 6:
        die = random.randint(1, 12)
    elif choice == 7:
        die = random.randint(1, 20)
    else:
        return '错误,不应该执行到这里'
    return die


if __name__ == '__main__':  # 告诉python,这是主程序,不用来导入其他程序中,否则导入其他程序后,此行以下代码都不会执行
    import sys

    print(randomNumGen(int(sys.argv[1])))  # 随机选出数字

 

python虚拟环境发挥的作用:

每个环境都有自己的安装目录,并且环境之间不共享库。这意味着即使更新全局库,不同环境中的每个模块也保持不变。这意味着可以同时在计算机上安装多个版本的模块,而不会发生冲突。虚拟环境也有自己的shell。

 

python wheel是预先构建的压缩文件,与源文件安装相比,他可以加快安装的过程。可将其比作为操作系统安装预先制作的二进制应用程序,而不用再进行构建和安装源文件。

 

pip自动使用wheel文件安装,加快了安装速度。

 

可以创建需求文件requirements.txt来提供要一次性安装的包的列表,通过使用

pip install -r requirements.txt

来安装。

 

pip list列出当前安装的包。

pip uninstall 卸载系统上的大多数包。

通过-r选项,一次删除多个包:pip unistall -r <requirements_file>

pip list --outdated 显示过时的包。

 

自动升级所有python包会破坏依赖关系。应该只更新需要的包。

 

pip show 包名 :可以显示特定安装包的详细信息。

 

使用pip setup.py install 安装的包不能通过pip卸载,因为其不提供关于安装文件的元数据。

 

pip wheel允许开发人员将所有项目依赖项以及任何已经编译的文件打包到单个归档文件中。

 

源代码和字节码的区别:字节码主要用于实现跨平台的兼容性。在源代码不变的基础上,为不同的体系结构使用字节码解释器的语言。

 

可以通过改变一些选项来修改解释器使用字节码的方式,以此来提高python程序的性能。

 

pyc文件是编译好的python代码文件。字节码独立于平台,python可以作为.py(源代码)或.pyc(字节码)发布。为了实现一定的模糊性和安全性,python程序可以在没有源代码的情况下发布,只提供预编译的.pyc文件。这种情况下,编译后的代码放在源目录,而不是在源代码文件中。

 

模块和包的区别:包是多个模块的集合,它们同时包含一个__init__.py文件,该文件可以为空。一个目录必须包含__init__.py文件,这样python才将其视为包。

初始化文件__init__.py通常为空,其可以包含__all__列表。

 

点命名法可以用于包,通过点号能访问包中多个模块。每个包有自己的命名空间。如果包里面还有子包的话,可以使用绝对路径和相对路径。绝对路径为点方法的完整路径,相对路径类似linux中的文件层次结构。

 

使用绝对导入通常更安全,因为可以确保知道在导入什么。

 

如果__all__没有在__init__.py中定义,那么import *只导入指定包中的模块,而不是所有子包或他们的模块。

 

py2exe是用于创建windows特定文件的一个选项。确实可以将python脚本文件转换为windows可执行文件,而不需要python的安装。py2exe不创建安装向导。虽然应用程序可以不需要向导,但windows用户通常希望在运行exe文件时可以使用向导。有许多开源免费的专有安装构建器。

py2app是用于创建mac系统的程序文件的工具。

 

pyinstaller提供多种方式来打包python代码。

 

cython将生成的代码被编译成c代码,正常的python解释器可以正常的执行c代码,且速度和编译后的c代码相同。可以通过同事使用python和c来创建功能齐全的应用程序,这是中非常强大的方法。