python脚本
excel文件操作
- xlrd读取excel内容
- .pen_workbook 打开文件
- .sheet_by_index 获取某一个表单
- .sheets 获取所有表单
- .cell_value 获取指定单元格的数据
- xlwt写入excel文件:
- .Workbook 创建文件对象
- .add_sheet 新增一个表单
- .write 在指定单元格写入数据
- xlutils操作文件:
- .copy
列表(可变)
-
删除列表元素
要删除列表中元素,如果知道要具体删除的元素可使用del语句。如果不知道具体要删除的列表项索引可使用remove()。
list1=[1,2,3,'sk'] del list1[1] list1.remove('sk')
-
切片访问列表的值
list1=[1,2,3,4] list2=list1[1:3]
集合( 无序且无重复值,可变)
如果想要创建一个空的集合,使用set()而不是{}。
-
集合推导式
a = {x for x in 'abracadabra' if x not in 'abc'}
字典(可变)
-
字典推导式
{x: x**2 for x in (4, 6, 8)}
python调试技术
为更好的调试Python程序,可以使用不同的技术。
- print()语句:这是了解具体发生情况的最简单的方式,这样我们可以检查执行的内容
- logging:这类似于print语句但带更多的上下文信息,因此我们可以更全面的了解情况
- pdb调试器:这是最常使用的调试技术。使用 pdb 的优势是能够在命令行、解释器以及程序中使用 pdb
- IDE调试器:IDE有内置的调试器。这让开发者可以执行自己的代码,然后开发者可以在程序执行过程中检查代码
python中支持的调试器
- winpdb
- pydev
- pydb
- pdb
- gdb
- pyDebug
pdb调试器
创建一个pdb_example.py的脚本文件
class Student:
def __init__(self, std):
self.count = std
def print_std(self):
for i in range(self.count):
print(i)
return
if __name__ == "__main__":
Student(5).print_std()
-
在解释器中调试
要从Python交互控制台中启动调试器,我们使用run()或runeval()。
$ python 导入我们的pdb_example脚本名和pdb模块。下面我们将使用run(),并且我们会传入一个字符串表达式来作为run()的参数,由Python解释器自身进行运行: >>> import pdb_example >>> import pdb >>> pdb.run('pdb_example.Student(5).print_std()') > <string>(1)<module>() (Pdb) continue 0 1 2 3 4
-
命令行调试
运行调试器最简单也最直接的方式是通过命令行。我们的程序将作为调试器的输入。我们可以这样在命令行中使用调试器:
在从命令行运行调试器时,源代码会被载入并在调试器找到的第一行停止执行。输入continue来继续调试。输出如下: vagrant@python-scripting:~$ python3 -m pdb pdb_example.py > /home/vagrant/pdb_example.py(1)<module>() -> class Student: (Pdb) continue 0 1 2 3 4 The program finished and will be restarted > /home/vagrant/pdb_example.py(1)<module>() -> class Student: (Pdb)
-
Python脚本内调试
以上两种技术会在Python程序开始时启动调试器。但第三种方法对于长期处理来说最佳。要在脚本中启动调试器,使用set_trace()。
现在修改pdb_example.py文件如下:
import pdb class Student: def __init__(self, std): self.count = std def print_std(self): for i in range(self.count): pdb.set_trace() print(i) return if __name__ == "__main__": Student(5).print_std()
基本程序崩溃调试
race模块有助于追踪程序的执行。因此不论何时程序崩溃,我们都能了解在哪里出现的崩溃。我们可以在脚本中导入也可以通过命令行来使用trace模块。
vagrant@python-scripting:~$ python3 -m trace --trace 脚本名.py
程序性能和时耗分析
对Python程序进行性能分析(profiling)表示度量程序的执行时间。它计量每个函数所花的时间。Python的cProfile模块用于对Python程序进行性能分析。
cProfile模块
编写一个cprof_example.py脚本
mul_value = 0
def mul_numbers(num1, num2):
mul_value = num1 * num2
print("Local Value:", mul_value)
return mul_value
mul_numbers(58, 77)
print("Global Value:", mul_value)
运行程序
vagrant@python-scripting:~$ python3 -m cProfile cprof_example.py
Local Value: 4466
Global Value: 0
6 function calls in 0.001 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 cprof_example.py:1(<module>)
1 0.000 0.000 0.000 0.000 cprof_example.py:2(mul_numbers)
1 0.000 0.000 0.001 0.001 {built-in method builtins.exec}
2 0.001 0.000 0.001 0.000 {built-in method builtins.print}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
使用cProfile,所有调用的函数都被打印,并包含各个函数所消耗的时间。列头的含义:
- ncalls: 调用次数
- tottime: 给定函数花费的总时间
- percall: tottime除以ncalls所得的商
- cumtime: 当前以及其子函数所花费的累计时间
- percall: cumtime除以原始调用所得的商
- filename:lineno(function): 提供函数各自的数据
timeit
timeit是一个Python模块,用于对Python脚本的各部分进行计时。我们可以在命令行中调用timeit,也可以在脚本中导入timeit模块。
创建一个timeit_example.py脚本
import timeit
prg_setup = "from math import sqrt"
prg_code = '''
def timeit_example():
list1 = []
for x in range(50):
list1.append(sqrt(x))
'''
# timeit 语句
print(timeit.timeit(setup = prg_setup, stmt = prg_code, number = 10000))
使用timeit,可以决定要对哪段代码进行性能的度量。因此,我们可以轻易地定义setup代码来作为我们想单独执行测试的代码片断。主代码默认运行100万次,但setup代码仅运行一次。
单元测试
unittest是Python中的一个单元测试框架。它支持多任务,如测试夹具(test fixture)、编写测试用例、聚合测试用例进入一个测试套件,以及运行测试。
unittest支持以下4种主要概念:
- 测试夹具:这包括执行一个或多个测试的准备和清理活动
- 测试用例:这包括我们的单个测试。通过使用unittest中的TestCase基类,我们可以新建测试用例
- 测试套件:这包含一个测试用例、测试套件或两者的合集。用于一起执行测试用例
- 测试运行器:这包括安排测试执行和向用户给出输出
Python有一个我们可以在脚本中导入的unittest模块。unittest模块有TestCase类用于创建测试用例。
单个测试用例可以方法形式创建。这些方法名以单词 test 开头。因此,测试运行器可以知道哪些方法表示测试用例。
创建单元测试
要创建两个脚本来进行实现。一个是普通脚本,另一个是包含测试的代码。
首先,创建一个名为arithmetic.py的脚本并编写如下代码:
# 在这个脚本中,我们将创建4个函数:add_numbers, sub_numbers, mul_numbers, div_numbers
def add_numbers(x, y):
return x + y
def sub_numbers(x, y):
return x - y
def mul_numbers(x, y):
return x * y
def div_numbers(x, y):
return (x / y)
为add_numbers函数编写测试用例。创建test_addition.py脚本
import arithmetic
import unittest
# Testing add_numbers function from arithmetic.
class Test_addition(unittest.TestCase):
# Testing Integers
def test_add_numbers_int(self):
sum = arithmetic.add_numbers(50, 50)
self.assertEqual(sum, 100)
# Testing Floats
def test_add_numbers_float(self):
sum = arithmetic.add_numbers(50.55, 78)
self.assertEqual(sum, 128.55)
#Testing Strings
def test_add_numbers_strings(self):
sum =arithmetic.add_numbers('hello','python')
self.assertEqual(sum, 'hellopython')
if __name__ == '__main__':
unittest.main()
最后运行test_addition.py测试脚本 ( 可以在命令行中使用unittest模块, python3 -m unittest test_addition.py )
不论何时运行测试脚本,我们可能得到的三种测试结果如下:
结果 | 描述 |
---|---|
OK | 成功 |
FAIL | 测试失败-抛出AssertionError异常 |
ERROR | 抛出AssertionError以外的异常 |
单元测试中使用的方法
使用unittest时,有一些方法可以在我们的脚本中使用。这些方法如下:
- assertEqual()和assertNotEqual():检测预期结果
- assertTrue()和assertFalse():验证条件
- assertRaises():验证抛出指定的异常
- setUp()和tearDown():定义每个测试方法执行之前和之后的指令
创建一个if_example.py脚本并加入如下代码:
def check_if():
a = int(input("Enter a number \n"))
if(a == 100):
print("a is equal to 100")
else:
print("a is not equal to 100")
return a
创建test_if.py测试脚本并编写如下代码:
import if_example
import unittest
class Test_if(unittest.TestCase):
def test_if(self):
result = if_example.check_if()
self.assertEqual(result, 100)
if __name__ == '__main__':
unittest.main()
最后运行python3 -m unittest test_if.py
执行外部命令并获取输出
Python的子进程模块。使用subprocess,可以很容易地生成新的进程并获取它们的返回码,执行外部命令和启用新的应用。
创建一个名为execute_external_commands.py的脚本并编写如下脚本
import subprocess
subprocess.call(["touch", "sample.txt"])
subprocess.call(["ls"])
print("Sample file created")
subprocess.call(["rm", "sample.txt"])
subprocess.call(["ls"])
print("Sample file deleted")
输出结果
$ python3 execute_external_commands.py
accept_by_input_file.py handling_password.py sample.txt
accept_by_pipe.py redirection.py
execute_external_commands.py sample_output.txt
Sample file created
accept_by_input_file.py execute_external_commands.py redirection.py
accept_by_pipe.py handling_password.py sample_output.txt
Sample file deleted
使用子进程模块捕获输出
我们可以传递PIPE作为标准输出stdout的参数来捕获输出。。编写名为capture_output.py的脚本并添加如下代码:
import subprocess
res = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE,)
print('returncode:', res.returncode)
print('{} bytes in stdout:\n{}'.format(len(res.stdout), res.stdout.decode('utf-8')))
执行如下命令运行脚本:
$ python3 capture_output.py
在运行时和验证时弹出密码输入
getpass模块来在运行时处理密码。Python中的getpass()模块弹出让用户输入密码并不进行打印。getpass模块用于终端中程序需要处理密码弹出的用户交互。
创建名为no_prompt.py的脚本
这个脚本中,我们没为用户提供提示文件。因此默认的提示内容为Password。
import getpass
try:
p = getpass.getpass()
except Exception as error:
print('ERROR', error)
else:
print('Password entered:', p)
为密码输出添加提示文本。创建一个名为with_prompt.py的脚本
import getpass
try:
p = getpass.getpass("Enter your password:")
except Exception as error:
print('ERROR', error)
else:
print('Password entered:', p)
编写一个脚本,如果密码输入错误,将打印一条普通消息,并不再弹出输入正确密码的提示。 getpass_example.py脚本 。
import getpass
passwd = getpass.getpass(prompt='Enter your password:')
if passwd.lower() == '#pythonworld':
print('Welcome!!')
else:
print('The password entered is incorrect!!')
在密码输入错误时要求重新输入正确的密码。为获取登录用户,我们使用了getuser()。getuser()函数将返回系统登录的用户。创建一个名为password_prompt_again.py的脚本 。
import getpass
user_name = getpass.getuser()
print('User Name : %s' % user_name)
while True:
passwd = getpass.getpass('Enter your password : ')
if passwd == '#pythonworld':
print('Welcome!!!')
break
else:
print('The password you entered is incorrect.')
读取配置文件
configparser模块。通过使用configparser模块,我们可以管理应用的用户可编辑配置文件。
这些配置文件常用于用户或系统管理人员通过普通文本编辑器来编辑文件设置应用的一些默认值,然后应用会读取并解析文件,根据文件中写入的内容来进行运行。
读取配置文件可使用configparser中的read()方法。下面我们编写一个名为read_config_file.py的普通脚本。在这之前,编写一个名为read_simple.ini 的.ini文件并加入如下内容
[bug_tracker]
url = https://www.baidu.com/
创建 read_config_file.py
from configparser import ConfigParser
p = ConfigParser()
p.read('read_simple.ini')
print(p.get('bug_tracker', 'url'))
read()方法可接收一个以上的文件名。对每个文件名进行扫描并且该文件存在时,就会打开并读取。下面我们编写脚本来读取一个以上的文件名。创建名为read_many_config_file.py的脚本 。
from configparser import ConfigParser
import glob
p = ConfigParser()
files = ['hello.ini', 'bye.ini', 'read_simple.ini', 'welcome.ini']
files_found = p.read(files)
files_missing = set(files) - set(files_found)
print('Files found: ', sorted(files_found))
print('Files missing: ', sorted(files_missing))
我们使用了Python中的configparser模块,它有助于管理配置文件。首先我们创建一个名为files的列表。read()函数将读取配置文件。在本例中,我们创建了一名为files_found的变量,用于存储目录中存在的配置文件名。接着我们创建了另一个名为files_missing的变量,用于返回目录中不存在的文件名。最后,我们打印出了存在和不存在的文件名。
在脚本中添加日志和警告代码
文件、目录和数据处理
使用os模块来处理目录
目录或文件夹是一个文件和子目录的集合。os模块提供了允许我们与操作系统交互的不同函数。
获取工作目录
要开始对目录进行处理,首先我们会获取当前工作目录的名称。os有一个getcwd()函数,使用它我们可以获取到当前的工作目录。
$ python3
Python 3.5.2 (default, Nov 12 2018, 13:43:14)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.getcwd()
'/home/student/Chapter05'
更换目录
使用os模块,我们可以更换当前工作目录。os模块中有一个chdir()函数可用于实现。
>>> os.chdir('/home/student')
>>> print(os.getcwd())
/home/student
列出文件和目录
列出目录内容在Python中也很容易。我们将使用os中带有的listdir()函数,它会返回当前工作目录的文件和目录名。
>>> os.chdir('/home/student')
>>> os.listdir()
重命名目录
Python中的os模块有一个rename()函数,可帮助更换目录的名称:
>>> os.mkdir('work')
>>> os.rename('work', 'work1')
>>> os.listdir()
复制、移动、重命名和删除数据
Python内置一个名为shutil的模块,用于执行这些任务,在我们的程序中使用shutil模块,只需要编写import shutil导入语句即可。
复制数据
移动/剪切数据
重命名数据
删除数据
文本处理和正则表达式
文本封装
Python的textwrap模块。该模块提供了TextWrapper来完成所有任务。textwrap模块用于格式化或封装普通文本。该模块提供了5个主要的函数:wrap(), fill(), dedent(), indent()和shorten()。
wrap()函数
wrap()函数用于将整个段落封装为单个字符串。输出结果是一个输出行列表。
语法为textwrap.wrap(text, width):
- text: 要封装的文本
- width: 封装行允许的最大长度,默认值为70
创建一个脚本wrap_example.py并编写如下内容:
import textwrap
skstring = '''lihuiruissb skkuoisashuaige lihuiruhaochou shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..'''
w = textwrap.wrap(text=skstring,width=30)
print(w)
换行符及空格占一个字符。
运行结果
['lihuiruissb skkuoisashuaige', 'lihuiruhaochou shenkuohaoshui,', 'zenmoshuone,', 'woshiyigehenshanlaing', 'henzhengyi henqiong dediaosi', 'zhangwanyuni..']
首先我们创建一个名为skstring的字符串。接着我们使用TextWrapper类指定了width。再后使用了wrap函数,字符串被封装长度30。最后打印出了各行。
fill()函数
fill()函数与textwrap.wrap的作用相似,只是它返回的数据是连接的、以新行分隔的字符串。该函数将输入封装为文本并返回包含封装文本的单个字符串。
该函数的语法为:textwrap.fill(text, width)
- text:封装的文本
- width:封装的一行允许的最大长度。默认值为70。
创建一个fill_example.py脚本并编写如下内容:
import textwrap
skstring = '''lihuiruissb skkuoisashuaige lihuiruhaochou shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..'''
w = textwrap.fill(text=skstring,width=30)
print(w)
运行结果
lihuiruissb skkuoisashuaige
lihuiruhaochou shenkuohaoshui,
zenmoshuone,
woshiyigehenshanlaing
henzhengyi henqiong dediaosi
zhangwanyuni..
dedent()函数
dedent()是textwrap模块中的另一个函数。该函数将我们文本每一行的普通前置空格进行移除。
该函数的语法如下:
textwrap.dedent(text)
其中text为取消缩进的文本。
创建一个脚本dedent_example.py并编写如下内容:
import textwrap
skstring = '''
lihuiruissb skkuoisashuaige lihuiruhaochou
shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..
'''
w = textwrap.dedent(skstring)
print(skstring)
print(w)
运行结果
lihuiruissb skkuoisashuaige lihuiruhaochou
shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..
lihuiruissb skkuoisashuaige lihuiruhaochou
shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..
创建了一个字符串变量skstring。然后使用了textwrap.dedent()来移除了常见前置空白内容。制表符和空格都可视作空白内容,但两者并不等价。因此,本例中的对唯一空白内容 tag 进行了删除。
indent()函数
indent()函数用于在文本选择定行的起始处添加指定前置内容。
该函数的语法为:textwrap.indent(text, prefix)
- text: 主字符串
- prefix: 要添加的前置内容
创建一个脚本indent_example.py并编写如下内容:
import textwrap
skstring = '''lihuiruissb skkuoisashuaige lihuiruhaochou shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..'''
w = textwrap.fill(text=skstring,width=30)
t = textwrap.indent(w,'$')
print(t)
运行结果
$lihuiruissb skkuoisashuaige
$lihuiruhaochou shenkuohaoshui,
$zenmoshuone,
$woshiyigehenshanlaing
$henzhengyi henqiong dediaosi
$zhangwanyuni..
使用了fill方法将数据存储在变量w中。接着使用了indent方法,输出的每行都会添加一个前缀$。
shorten()函数
textwraps模块中的这一函数用于截断文本来适配指定的宽度。例如,想要创建摘要或预览时,可
使用 shorten()函数。使用 shorten()时,文本中所有的空白内容都会被标准化为单个空格。
该函数的语法为:textwrap.shorten(text, width)
创建一个脚本shorten_example.py并编写如下内容:
import textwrap
skstring = '''lihuiruissb skkuoisashuaige lihuiruhaochou shenkuohaoshui, zenmoshuone,
woshiyigehenshanlaing henzhengyi henqiong dediaosi zhangwanyuni..'''
w = textwrap.shorten(skstring,width=50)
t = textwrap.shorten(skstring,width=30)
print(t)
print(w)
运行结果
lihuiruissb [...]
lihuiruissb skkuoisashuaige lihuiruhaochou [...]
使用了shorten()函数来截取文本来适配指定的宽度。首先,所有的空白内容都被截断为单个空格。如果结果符合指定宽度,则会将结果显示在屏幕上。否则,指定宽度的单词会显示在屏幕上,而其余的则放在占位符中。
正则表达式
正则表达式是一种专用编程语言,内置在Python中,用户可通过re来进行使用。为想要匹配的字符串集定义规则 。使用正则表达式,可以从文件、代码、文档、电子表格等中提取指定的信息。
在Python中,正则表达式由re表示并可通过re模块来进行导入。正则表达式支持4种内容:
- 标识符
- 修饰符
- 空白字符
- Flag标记
以下表格列出了标识符(identifier),对每一个都有相关的描述:
标识符 | 描述 |
---|---|
\w | 匹配字字母数字字符,包含下划线(_) |
\W | 匹配非字母数字字符,不包含下划线(_) |
\d | 匹配一个数字 |
\D | 匹配一个非数字字符 |
\s | 匹配一个空格 |
\S | 匹配空格以外的字符 |
. | 匹配一个点号 (.),注:应为任意字符 |
\b | 匹配任意新行以外的字符 |
下表中列出了修饰符(modifier)以及对应的描述:
修饰符 | 描述 |
---|---|
^ | 匹配字符串的起始处 |
$ | 匹配字符串的结尾处 |
? | 匹配0次或11次 |
* | 匹配0次或多次 |
+ | 匹配1次或多次 |
| | 匹配两边内容之一x/y |
[ ] | 范围匹配 |
{x} | 前面标识符的匹配次数 |
下表中列出了空白字符(whitespace)及相应描述:
字符 | 描述 |
---|---|
\s | 空格 |
\t | 制表符 Tab |
\n | 新起一行 |
\e | 回撤Escape |
\f | 换页Form feed |
\r | 返回 |
以下表格列出了标记及相应描述:
Flag 标记 | 描述 |
---|---|
re.IGNORECASE | 忽略大小写匹配 |
re.DOTALL | 匹配包括新行在内的任意字符 |
re.MULTILINE | 多行匹配 |
Re.ASCII | 仅对ASCII字符进行转义匹配 |
要使用Python中的正则表达式,必须要在脚本中导入re模块,这样才能对正则表达式使用所有的函数和方法。函数方法例如match(), search(), findall()和sub()函数。