day11-python-函数-进阶
编程语言支持通过以下几种方式来解构具体问题:
- 大多数的编程语言都是 过程式 的,所谓程序就是一连串告诉计算机怎样处理程序输入的指令。C、Unix shells 都是过程式语言。
- 在 声明式 语言中,你编写一个用来描述待解决问题的说明,并且这个语言的具体实现会指明怎样高效的进行计算。 SQL 可能是你最熟悉的声明式语言了。 一个 SQL 查询语句描述了你想要检索的数据集,并且 SQL 引擎会决定是扫描整张表还是使用索引,应该先执行哪些子句等等。
- 面向对象(OOP) 程序会操作一组对象。 对象拥有内部状态,并能够以某种方式支持请求和修改这个内部状态的方法。Smalltalk 和 Java 都是面向对象的语言。 C++ 和 Python 支持面向对象编程,但并不强制使用面向对象特性。
- 函数式 编程则将一个问题分解成一系列函数。 理想情况下,函数只接受输入并输出结果,对一个给定的输入也不会有影响输出的内部状态。 著名的函数式语言有 scala和 Haskell。
python 是支持多范式编程的语言,支持OOP编程又支持函数式编程。
输入会流经一系列函数。每个函数接受输入并输出结果。函数式风格反对使用带有副作用的函数,这些副作用会修改内部状态,或者引起一些无法体现在函数的返回值中的变化。完全不产生副作用的函数被称作“纯函数”。消除副作用意味着不能使用随程序运行而更新的数据结构;每个函数的输出必须只依赖于输入。
模块化
函数式编程的一个更实用的优点是,它强制你把问题分解成小的方面。因此程序会更加模块化。相对于一个进行了复杂变换的大型函数,一个小的函数更明确,更易于编写, 也更易于阅读和检查错误。
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
惰性计算:
惰性求值是一种求值策略,它将表达式的求值延迟到需要它的值时,并且避免重复求值。它通常被认为是优化代码的一种策略。它的工作方式是每次处理一个对象,而不是一口气处理和构造整个数据结构,这样做的潜在优点是可以节省大量的内存。
与立即求值不同之处在于,Lazy evaluate
不会立即对表达式求值,而只在需要结果时才执行。这有点像一个懒惰的学生,只在需要提交作业的时候才做作业。
惰性计算可以提高代码的执行效率,节约内存资源
import sys
a = range(10)
b = range(10000000000000000)
print(sys.getsizeof(a), sys.getsizeof(b)) #48 48
a,b所占空间都是48。这是因为range()从python3就实现了惰性计算,rang()
只存储开始、停止、步骤值,并在需要时计算每个项的值,而不是一次就生成所有的值。
其实实现惰性计算的关键就是实现一个生成器(generator
)
生成器
generator是一个函数用于返回一个可迭代对象[可迭代对象,是指一个对象拥有__next__
方法与__iter__
方法],generator函数就有点像普通函数中将return
替换成 yield
,可以使用next()方法获取生成器对象中的值,直到生成器对象中的值被用尽,抛出StopIteration
的异常
创建生成器有两种方式
#方式一
g1 = (num for num in range(1000))
#方式二 yield
def fun1():
for num in range(1000):
yield num
g2 = fun1()
print(next(g1), next(g2)) #0 0
print(next(g1), next(g2)) #1 1
print(next(g1), next(g2)) #2 2
print(next(g1), next(g2)) #3 3
注意生成器表达式和列表推导式的区别:生成器表达式两边使用圆括号
"()"
,而列表推导式则使用方括号"[]"
。
g1 = (num for num in range(4))
l1=[num for num in range(4)]
print(type(g1),g1) #<class 'generator'> <generator object <genexpr> at 0x000002ADD2F84270>
print(type(l1),l1) #<class 'list'> [0, 1, 2, 3]
生成器:
import time
import sys
start_time = time.perf_counter()
g1 = (num for num in range(100000000))
end_time = time.perf_counter()
print(end_time-start_time) #1.800013706088066e-06
print(sys.getsizeof(g1)) #104
推导式:
import time
import sys
start_time = time.perf_counter()
g1 = [num for num in range(100000000)]
end_time = time.perf_counter()
print(end_time-start_time) #3.485051600029692
print(sys.getsizeof(g1)) #835128600
从上面的对比可以看出,其实生成器就是惰性求值,而列表推导式是一口气处理和构造整个数据结构的
其他的惰性求值函数
1.zip()
合并两个可以迭代对象用于生成一个元组列表。
2.with open()
with open
它不会读取整个文件内容到内存中,而是返回一个可以遍历的文件对象。正因为它的惰性求值属性,所以它能够有效地读取大的文件,而不会产生内存溢出。
3.lambda 表达式
python lambda
根据python 官网的 Python design Q&A:
Python lambdas are only a shorthand notation if you’re too lazy to define a function.
#如果您懒得定义函数,那么Python lambdas只是一种速记符号。
python 中的 lambda本质还是一个函数,只不过它是一个匿名函数而已
python lambda语法
lambda arguments: expression
语法由三部分组成:lambda
关键字 、arguments
函数的输入参数、expression
表达式,相当于函数体,但这里的表达式只支持一个。表达式的输出结果就是函数的返回值。
需要注意的是lambda表达式中不能包含任意的语句 类如:return
,
try,
assert,
if,
for,
raise等
示例:
l1 = lambda x, y: x + y
l2 = lambda x, y=3: x + y
l3 = lambda *args: sum(args)
print(type(l1)) # <class 'function'>
print(l1(1, 3)) #4
print((lambda x, y: x + y)(1, 3)) #4
print(l2(1)) #4
print(l3(1, 3, 4)) #8
高阶函数
如果一个函数包含其他函数作为参数或返回函数,则称为高阶函数。它是函数式编程的一个重要概念。Python作为一种非常灵活的编程语言,支持使用高阶函数。Python中有一些内置的高阶函数,我们也可以自己定义高阶函数。
常用高阶函数:
Map
Map()函数接受两个参数:一个函数和一个可迭代对象。映射函数将应用于可迭代对象中的每个元素。函数返回一个包含映射元素的迭代器。
例子:
def fun1(x):
return x*2
r=map(fun1,[1,2,3,4])
print(list(r)) #输出[2, 4, 6, 8]
上面列子等价于lambda表达式
r1=map(lambda x:x*2,[1,2,3,4])
print(list(r1))
reduce
reduce()函数来自Python内置模块functools。它的本质是将一个函数累积地应用到可迭代对象中的所有元素上,并生成一个单一值。Reduce()函数接受3个参数:一个输入函数,一个可迭代函数和一个可选初始化表达式。返回一个单一的值。
reduce()函数的结果与对Iterable反复使用函数是一样的。
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
示例:
nums = [1, 2, 3, 4]
to_str = reduce(lambda x, y: x + y, nums)
print(to_str) #10
filter
filter与map类似也接受两个参数一个函数一个是可迭代对象,筛选函数将应用于每个元素,filter()函数返回一个包含筛选过的元素的迭代器。
示例:
nums = [1, 2, 3, 4, 5, 6, 7, 8]
to_str = filter(lambda x: x % 2 == 0, nums)
print(list(to_str)) #[2, 4, 6, 8]
sorted
Python的内置排序方法是一个高阶函数,它有一个接收函数的关键参数,该函数定义了如何比较元素。
示例,按照字符长度比较元素
names = ['HELLO', 'python', 'hi', 'wow']
names = sorted(names, key=len)
print(names) #['hi', 'wow', 'HELLO', 'python']