常用函数
argparse
argparse
是 Python 的一个标准库,用于编写用户友好的命令行接口。它允许开发者定义命令行参数,并解析这些参数以供程序使用。下面是对 argparse
中常用参数的一些说明:
参数说明
- name or flags
这是参数的名称或标志。对于可选参数,通常使用 --
或 -
前缀。例如,--verbose
或 -v
。约定俗称的写法是 --
后面跟完整参数名,-
后面是简写。
- action
定义参数被解析时执行的操作。常见的操作包括 store
(存储值)、store_const
(存储常量值)、append
(将值添加到列表中)等。
- default
当参数未在命令行中提供时使用的默认值。
- required
一个布尔值,表示这个参数是否一定需要设置。如果设置为 True
,那么用户必须在命令行中提供这个参数。
- type
参数的类型。默认是字符串类型,但也可以指定为其他类型,如 int
、float
或自定义类型。
- choices
参数值只能从几个选项中选择。这可以确保用户只能提供有效的参数值。
- help
指定参数的说明信息。当用户在命令行中使用 -h
或 --help
参数时,这些说明信息会被打印出来,帮助用户理解如何使用参数。
- nargs
指定命令行参数应该读取的个数。可以是具体的数字,也可以是 ?
(表示参数是可选的)或 *
(表示可以接收任意个参数)。
- const
与 action
和 store_const
一起使用,表示当参数被触发时存储的常量值。
- metavar
在帮助信息中显示的参数名。有时,参数的实际名称可能不适合在帮助信息中显示,这时可以使用 metavar
来提供一个更友好的名称。
示例
以下是一个简单的示例,展示了如何使用这些参数:
import argparse
# 定义一个ArgumentParser实例
parser = argparse.ArgumentParser(description='一个简单的示例')
#jupyter notebook系统默认会给一个奇怪的参数-f,用-f来接收这个参数避免报错
parser.add_argument("-f","--file",default="file")
parser.add_argument('--input', type=str, required=True, help='输入文件的路径')
parser.add_argument('--output', type=str, default='output.txt', help='输出文件的路径(默认为 output.txt)')
parser.add_argument('--verbose', action='store_true', help='是否打印详细日志')
# 解析参数:
args = parser.parse_args()
2
3
4
5
6
7
8
9
10
11
在这个示例中:
--input
是一个必需的参数,类型为字符串。--output
有一个默认值'output.txt'
,如果用户在命令行中没有提供该参数,将使用这个默认值。--verbose
是一个布尔类型的参数,当它被提供时,action='store_true'
会将args.verbose
设置为True
。
用户可以通过以下方式运行这个脚本:
python script.py --input data.txt --output result.txt --verbose
在这个例子中,args.input
的值将是 'data.txt'
,args.output
的值将是 'result.txt'
,而 args.verbose
将被设置为 True
。
parser.add_argument
ArgumentParser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
每个参数解释如下:
- name or flags - 选项字符串的名字或者列表,例如 foo 或者 -f, --foo。
- action - 命令行遇到参数时的动作,默认值是 store。
- store_const,表示赋值为 const;
- append,将遇到的值存储成列表,也就是如果参数重复则会保存多个值;
- append_const,将参数规范中定义的一个值保存到一个列表;
- count,存储遇到的次数;此外,也可以继承 argparse.Action 自定义参数解析;
- nargs - 应该读取的命令行参数个数,可以是具体的数字,或者是?号,当不指定值时对于 Positional argument 使用 default,对于 Optional argument 使用 const;或者是 * 号,表示 0 或多个参数;或者是 + 号表示 1 或多个参数。
- const - action 和 nargs 所需要的常量值。
- default - 不指定参数时的默认值。
- type - 命令行参数应该被转换成的类型。
- choices - 参数可允许的值的一个容器。
- required - 可选参数是否可以省略 (仅针对可选参数)。
- help - 参数的帮助信息,当指定为 argparse.SUPPRESS 时表示不显示该参数的帮助信息.
- metavar - 在 usage 说明中的参数名称,对于必选参数默认就是参数名称,对于可选参数默认是全大写的参数名称.
- dest - 解析后的参数名称,默认情况下,对于可选参数选取最长的名称,中划线转换为下划线.
map()
map()
函数是 Python 中的一个内置函数,常用于将某个函数应用到一个或多个可迭代对象(如列表、元组等)的每个元素上。map()
函数返回一个迭代器,其中包含函数应用后的结果。
1. map()
函数的语法
map(function, iterable, ...)
function
:要应用的函数。可以是一个内置函数、用户自定义函数或lambda
表达式。iterable
:一个或多个可迭代对象,如列表、元组、字符串等。map()
函数会逐一将每个可迭代对象的元素传递给函数。
2. map()
的返回值
map()
返回一个迭代器(<class 'map'> 对象),如果你想查看 map()
的结果,可以将它转换为列表、元组等类型:
result = list(map(function, iterable))
3. 示例
3.1 使用 map()
处理单个可迭代对象
假设我们有一个列表,我们想对列表中的每个元素应用平方运算。
numbers = [1, 2, 3, 4, 5]
# 使用 map 应用平方运算
squared_numbers = map(lambda x: x ** 2, numbers)
# 转换为列表查看结果
print(list(squared_numbers)) # 输出:[1, 4, 9, 16, 25]
2
3
4
5
6
7
3.2 使用自定义函数
我们可以用自定义函数代替 lambda
表达式。
# 定义一个函数来计算平方
def square(x):
return x ** 2
numbers = [1, 2, 3, 4, 5]
squared_numbers = map(square, numbers)
print(list(squared_numbers)) # 输出:[1, 4, 9, 16, 25]
2
3
4
5
6
7
8
3.3 处理多个可迭代对象
map()
可以同时接受多个可迭代对象,将每个对象对应位置上的元素传递给函数。例如,我们想对两个列表的每个元素进行相加:
numbers1 = [1, 2, 3]
numbers2 = [4, 5, 6]
# 使用 map 对两个列表中的元素逐一相加
summed_numbers = map(lambda x, y: x + y, numbers1, numbers2)
print(list(summed_numbers)) # 输出:[5, 7, 9]
2
3
4
5
6
7
当 map()
处理多个可迭代对象时,它会根据最短的可迭代对象长度进行截断,这意味着如果一个列表的长度比另一个列表短,那么 map()
会忽略多出来的元素。
3.4 处理字符串
map()
也可以用于字符串的处理,例如我们想将字符串中的每个字符转换为大写:
letters = ['a', 'b', 'c']
# 使用 map 将字符转换为大写
uppercase_letters = map(str.upper, letters)
print(list(uppercase_letters)) # 输出:['A', 'B', 'C']
2
3
4
5
6
4. 使用 map()
与多个函数结合
map()
通常会与其他函数(如 lambda
、filter
、reduce
)结合使用,帮助你构建简洁的函数式编程逻辑。
例如,我们可以先用 map()
来对列表中的元素进行平方,再用 filter()
来筛选出偶数:
numbers = [1, 2, 3, 4, 5, 6]
# 先用 map 进行平方运算
squared_numbers = map(lambda x: x ** 2, numbers)
# 再用 filter 筛选出偶数
even_squared_numbers = filter(lambda x: x % 2 == 0, squared_numbers)
print(list(even_squared_numbers)) # 输出:[4, 16, 36]
2
3
4
5
6
7
8
9
5. map()
与列表推导式的对比
map()
常常与 Python 的列表推导式相比较。两者的功能非常相似,但在某些情况下,使用列表推导式可能会更简洁,尤其是当操作比较简单时。
例如,使用列表推导式来计算平方:
numbers = [1, 2, 3, 4, 5]
# 使用列表推导式
squared_numbers = [x ** 2 for x in numbers]
print(squared_numbers) # 输出:[1, 4, 9, 16, 25]
2
3
4
5
6
在这个例子中,列表推导式比 map()
更加直观。
6. 总结
map()
是一个非常有用的函数式编程工具,用于将一个函数应用到一个或多个可迭代对象的每个元素上。- 它返回一个惰性计算的迭代器,适合处理大数据集时的高效内存管理。
- 在某些简单场景下,列表推导式可能更具可读性,但
map()
在处理多个可迭代对象或结合其他函数时显得更加灵活。 - 惰性计算:
map()
返回的是一个迭代器,这意味着它不会立即计算所有结果,而是在需要时逐个生成。与生成完整的列表相比,map()
在处理大数据集时可以节省内存。 - 返回值是迭代器:
map()
返回的是迭代器,而不是列表。因此,在某些情况下需要将其转换为列表或元组来查看结果。
lambda 函数
lambda 函数是 Python 中一个非常重要的语法,它允许我们创建匿名函数。它是一个函数,但没有函数名,没有 def 语句,只有参数列表和一个返回值。lambda 函数的语法格式如下:
lambda 参数列表: 返回值
例如,一个加法函数的 lambda 表达式如下:
lambda a, b: a + b
以下是一些使用 lambda 表达式创建的函数:
# 定义一个加法函数
def add(a, b):
return a + b
# 定义一个 lambda 表达式
add_lambda = lambda a, b: a + b
# 调用函数
print(add(1, 2))
print(add_lambda(1, 2))
2
3
4
5
6
7
8
9
10
输出结果:
3
3
2
在上面的代码中,add
是一个定义好的函数,add_lambda
是使用 lambda 表达式创建的函数。它们的使用方式是相同的,只是 add
是一个定义好的函数,add_lambda
是使用 lambda 表达式创建的函数。
lambda 表达式使用场景
- 作为函数参数传递
- 作为装饰器
- 作为生成器表达式中的生成器函数
- 作为 sorted() 函数中的 key 参数
- 作为 filter() 函数中的函数参数
作为 map() 函数中的函数参数
# ===========一般写法:===========
# 1、计算平方数
def square(x):
return x ** 2
map(square, [1,2,3,4,5])# 计算列表各个元素的平方
# 结果:
[1, 4, 9, 16, 25]
# ===========匿名函数写法:============
# 2、计算平方数,lambda 写法
map(lambda x: x ** 2, [1, 2, 3, 4, 5])
# 结果:
[1, 4, 9, 16, 25]
# 3、提供两个列表,将其相同索引位置的列表元素进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
# 结果:
[3, 7, 11, 15, 19]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
filter
filter
是 Python 中的一个内置函数,它用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象。filter
函数通常用于处理数据筛选,它接收两个参数:一个函数和一个序列。这个函数用于判断序列中的每个元素是否符合条件,返回布尔值(True 或 False)。序列可以是列表、元组、字典等任何可迭代对象。
语法
filter(function, iterable)
function
:一个函数,用于判断每个元素是否保留。iterable
:一个序列,如列表、元组等。
返回值
返回一个迭代器,可以通过 list()
转换为列表。
示例
- 基本使用
# 定义一个过滤函数
def is_even(num):
return num % 2 == 0
# 使用 filter 函数过滤偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = filter(is_even, numbers)
# 将结果转换为列表
print(list(even_numbers)) # 输出: [2, 4, 6, 8, 10]
2
3
4
5
6
7
8
9
10
- 使用 lambda 表达式
# 使用 lambda 表达式过滤偶数
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
# 将结果转换为列表
print(list(even_numbers)) # 输出: [2, 4, 6, 8, 10]
2
3
4
5
6
- 过滤字符串
# 过滤出包含字母 'a' 的字符串
words = ['apple', 'banana', 'cherry', 'date']
filtered_words = filter(lambda word: 'a' in word, words)
# 将结果转换为列表
print(list(filtered_words)) # 输出: ['apple', 'banana', 'cherry', 'date']
2
3
4
5
6
- 过滤字典
# 过滤出值大于 10 的字典项
data = {'a': 5, 'b': 12, 'c': 7, 'd': 18}
filtered_data = filter(lambda item: item[1] > 10, data.items())
# 将结果转换为字典
print(dict(filtered_data)) # 输出: {'b': 12, 'd': 18}
2
3
4
5
6
注意事项
filter
返回的是一个迭代器,不是列表。如果需要列表形式,可以使用list()
函数转换。filter
函数本身不会修改原始数据,它只是创建一个新的迭代器。- 过滤函数必须返回布尔值,True 表示保留该元素,False 表示不保留。
- 惰性计算:
filter()
返回一个迭代器对象,它是惰性求值的,意思是它不会立即计算所有结果,而是每次迭代时才进行计算。这意味着它比直接生成一个完整的列表更高效,特别是当数据量很大时。 - 函数为
None
的行为:当filter()
的第一个参数function
被设置为None
时,它会将iterable
中所有 "truthy" 的值保留下来,也就是会自动过滤掉等价于False
的元素,比如None
、0
、空字符串等。
next()和 iter()函数详解
迭代器就是重复地做一些事情,可以简单的理解为循环,在 python 中实现了__iter__
方法的对象是可迭代的,实现了next()
方法的对象是迭代器,这样说起来有点拗口,实际上要想让一个迭代器工作,至少要实现__iter__
方法和next
方法。很多时候使用迭代器完成的工作使用列表也可以完成,但是如果有很多值列表就会占用太多的内存,而且使用迭代器也让我们的程序更加通用、优雅、pythonic。
如果一个类想被用于for ... in
循环,类似 list 或 tuple 那样,就必须实现一个__iter__()
方法,该方法返回一个迭代对象,然后,Python 的 for 循环就会不断调用该迭代对象的next()
方法拿到循环的下一个值,直到遇到 StopIteration 错误时退出循环。
容器(container)
容器是用来储存元素的一种数据结构,容器将所有数据保存在内存中,Python 中典型的容器有:list,set,dict,str 等等。
class test():
def __init__(self,data=1):
self.data = data
def __iter__(self):
return self
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
for item in test(3):
print(item)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
输出结果:
4
5
6
2
3
for … in…
这个语句其实做了两件事。第一件事是获得一个可迭代器,即调用了__iter__()
函数。 第二件事是循环的过程,循环调用__next__()
函数。
对于 test 这个类来说,它定义了__iter__
和__next__
函数,所以是一个可迭代的类,也可以说是一个可迭代的对象(Python 中一切皆对象)。
迭代器
含有__next__()
函数的对象都是一个迭代器,所以 test 也可以说是一个迭代器。如果去掉__itet__()
函数,test 这个类也不会报错。如下代码所示:
class test():
def __init__(self,data=1):
self.data = data
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
t = test(3)
for i in range(3):
print(t.__next__())
2
3
4
5
6
7
8
9
10
11
12
13
14
输出结果:
4
5
6
2
3
生成器
生成器是一种特殊的迭代器。当调用 fib()函数时,生成器实例化并返回,这时并不会执行任何代码,生成器处于空闲状态,注意这里 prev, curr = 0, 1 并未执行。然后这个生成器被包含在 list()中,list 会根据传进来的参数生成一个列表,所以它对 fib()对象(一切皆对象,函数也是对象)调用next方法。
def fib(end = 1000):
prev,curr=0,1
while curr < end:
yield curr
prev,curr=curr,curr+prev
print(list(fib()))
2
3
4
5
6
7
输出结果:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
上面只是做了几个演示,这里具体说明一下:
当调用 iter 函数的时候,生成了一个迭代对象,要求__iter__
必须返回一个实现了__next__
的对象,我们就可以通过next
函数访问这个对象的下一个元素了,并且在你不想继续有迭代的情况下抛出一个 StopIteration 的异常(for 语句会捕获这个异常,并且自动结束 for),下面实现了一个自己的类似 range 函数的功能。
class MyRange(object):
def __init__(self, end):
self.start = 0
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
ret = self.start
self.start += 1
return ret
else:
raise StopIteration
from collections.abc import *
a = MyRange(5)
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
for i in a:
print(i)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
输出结果是:
True
True
0
1
2
3
4
2
3
4
5
6
7
接下来我们使用 next 函数模拟一次:
class MyRange(object):
def __init__(self, end):
self.start = 0
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start < self.end:
ret = self.start
self.start += 1
return ret
else:
raise StopIteration
a = MyRange(5)
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a)) # 其实到这里已经完成了,我们在运行一次查看异常
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
可以看见一个很明显的好处是,每次产生的数据,是产生一个用一个,什么意思呢,比如我要遍历[0, 1, 2, 3.....]一直到 10 亿,如果使用列表的方式,那么是会全部载入内存的,但是如果使用迭代器,可以看见,当用到了(也就是在调用了 next)才会产生对应的数字,这样就可以节约内存了,这是一种懒惰的加载方式。
总结
- 可以使用
collection.abs
里面的Iterator
和Iterable
配合isinstance
函数来判断一个对象是否是可迭代的,是否是迭代器对象。 iter
实际是映射到了__iter__
函数。- 只要实现了
__iter__
的对象就是可迭代对象(Iterable),正常情况下,应该返回一个实现了__next__
的对象(虽然这个要求不强制),如果自己实现了__next__
,当然也可以返回自己。 - 同时实现了
__iter__
和__next__
的是迭代器(Iterator),当然也是一个可迭代对象了,其中__next__
应该在迭代完成后,抛出一个 StopIteration 异常。 - for 语句会自动处理这个
StopIteration
异常以便结束 for 循环。
enumerate()
enumerate
是 Python 中的一个内置函数,用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
enumerate
函数返回的是一个枚举对象,其中包含了元素及其索引(下标)。你可以通过遍历枚举对象来获取每个元素的索引和值。
以下是 enumerate
的基本用法:
# 示例:对一个列表使用 enumerate
my_list = ['apple', 'banana', 'cherry']
# 使用 enumerate 遍历列表
for index, value in enumerate(my_list):
print(f"Index: {index}, Value: {value}")
# 输出:
# Index: 0, Value: apple
# Index: 1, Value: banana
# Index: 2, Value: cherry
2
3
4
5
6
7
8
9
10
11
在这个例子中,enumerate(my_list)
生成了一个枚举对象,该对象在每次迭代时产生一个包含索引和值的元组。然后,通过解包这个元组到 index
和 value
变量中,我们可以在循环体内部同时访问到每个元素的索引和值。
此外,enumerate
函数还接受一个可选的 start
参数,用于指定索引的起始值:
my_list = ['apple', 'banana', 'cherry']
# 从索引 1 开始枚举
for index, value in enumerate(my_list, start=1):
print(f"Index: {index}, Value: {value}")
# 输出:
# Index: 1, Value: apple
# Index: 2, Value: banana
# Index: 3, Value: cherry
2
3
4
5
6
7
8
9
10
在这个例子中,我们指定 start=1
,所以索引从 1 开始而不是默认的 0。
logging 模块
logging
是 Python 标准库中的一个模块,它提供了一套灵活且强大的日志系统。通过logging
,你可以记录程序中发生的事件,这对于调试、监控、分析以及理解程序行为都非常有帮助。
基本概念
日志级别:
logging
模块定义了几个日志级别,包括DEBUG
、INFO
、WARNING
、ERROR
和CRITICAL
。每个级别都对应一个数字,数字越大,级别越高。通常,级别高的日志会包含级别低的日志信息。日志处理器(Handlers):负责将日志记录(Log Record)发送到指定的目的地,比如文件、控制台、网络等。
日志记录器(Loggers):记录器是
logging
模块的核心部分,它负责处理日志记录。你可以为应用程序的不同部分创建不同的记录器。日志格式化器(Formatters):用于定义日志的最终输出格式。
常用功能
配置日志:你可以使用
basicConfig
方法进行简单的日志配置,也可以手动创建记录器、处理器和格式化器进行更复杂的配置。记录日志:使用记录器的
debug
、info
、warning
、error
和critical
方法来记录不同级别的日志。日志传播:一个记录器可以有一个或多个处理器,如果处理器没有处理该记录,记录将被传递给该记录器的父记录器处理(如果存在的话)。
线程安全:
logging
模块是线程安全的,可以在多线程环境中使用。
示例
下面是一个简单的 logging
示例:
import logging
# 配置日志的基本设置
logging.basicConfig(filename='app.log', level=logging.DEBUG,
format='%(asctime)s:%(levelname)s:%(message)s')
# 记录不同级别的日志
logging.debug('这是一条 debug 级别的日志')
logging.info('这是一条 info 级别的日志')
logging.warning('这是一条 warning 级别的日志')
logging.error('这是一条 error 级别的日志')
logging.critical('这是一条 critical 级别的日志')
2
3
4
5
6
7
8
9
10
11
12
在这个示例中,我们首先使用 basicConfig
方法配置了日志的基本设置,包括日志文件名、日志级别和日志格式。然后,我们使用不同级别的日志方法来记录日志。这些日志将被写入到 app.log
文件中。
高级配置
对于更复杂的日志需求,你可能需要手动创建记录器、处理器和格式化器,并使用 addHandler
方法将它们关联起来。例如,你可能希望将不同级别的日志记录到不同的文件中,或者将日志同时输出到控制台和文件。
总之,logging
模块是 Python 中非常强大且灵活的日志系统,它可以帮助你更好地管理、监控和调试你的应用程序。