【Python】编程笔记5

函数式编程(Functional Programming)

函数式编程:思想更接近于数学计算,抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量。

特点:允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

Python 允许使用变量,因此,Python 不是纯函数式编程语言。

一、高阶函数(Higher-order function)

函数本身也可以赋值给变量,即:变量可以指向函数。例如:函数名。

f = abs
print(f(-10))

输出结果

10

高阶函数:一个函数就可以接收另一个函数作为参数。(既然变量可以指向函数,函数的参数能接收变量)

def add(x, y, f):
    return f(x) + f(y)

print(add(-5, 6, abs))

输出结果

11

二、map/reduce

Python 中内建了 map() 和 reduce() 函数。

1、map() 函数

map()函数:接收两个参数,一个是函数,一个是 Iterable。map 将传入的函数依次作用到序列的每个元素,并把结果作为新的 Iterator 返回。

def f(x):
    return x * x
r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(r))

## 把这个 list 所有数字转为字符串
print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))

输出结果

[1, 4, 9, 16, 25, 36, 49, 64, 81]
['1', '2', '3', '4', '5', '6', '7', '8', '9']

2、reduce() 函数

reduce()函数:把一个函数作用在一个序列 [x1, x2, x3, ...] 上,这个函数必须接收两个参数, reduce 把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

把序列[1, 3, 5, 7, 9]变换成整数 13579 的 reduce 实现:

from functools import reduce
def fn(x, y):
    return x * 10 + y
print(reduce(fn, [1, 3, 5, 7, 9]))

输出结果

13579

str 类型 ==》int 类型

from functools import reduce
def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
    return reduce(fn,map(char2num,s))

# 13579
print(str2int('13579'))

利用 lambda 函数进一步简化:

def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s):
    return reduce(lambda x,y:10 * x + y, map(char2num, s))

str ==》float

def str2float(s):
    def char2num(s):
        return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
    def fnMuti(x, y):
        return 10 * x + y
    def fnDivid(x, y):
        return x / 10 + y
    dotIndex = s.index('.')
    return reduce(fnMuti, map(char2num, s[:dotIndex])) + reduce(fnDivid, list(map(char2num, s[dotIndex + 1:]))[::-1])/10
print('str2float(\'123.456\') =', str2float('123.456'))

输出结果

str2float('123.456') = 123.456

三、filter

filter() 函数用于过滤序列。接收两个参数:一个函数和一个序列,filter() 把传入的函数依次作用于每个元素,然后根据返回值是 True ,则保留,为 False 则丢弃该元素。

def is_odd(n):
    return n % 2 == 1
print(list(filter(is_odd, [1,2,4,5,6,9,10,15])))
# 结果: [1, 5, 9, 15]

==》filter() 函数返回结果是 Iterator,是一个惰性序列,需要使用 list() 函数获取所有的结果并返回 list。

1、用 filter 求素数

实现方法:埃氏筛法。列出从 2 开始的所有自然数,构造一个序列:取序列第一个数并筛掉其的倍数,依次类推…

# 生成器,且是一个无限序列
def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

# 过滤函数
def _not_divisible(n):
    return lambda x : x % n > 0

# 用于不断返回素数的生成器
def primes():
    yield 2
    it = _odd_iter()    # 初始序列
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)   # 构造新的序列

# 设置一个退出循环的条件
for n in primes():  
    if n < 1000:
        print(n)
    else:
        break

四、sorted

通常规定,对于两个元素 x 和 y,如果认为 x < y,则返回-1,如果认为 x == y,则返回 0,如果认为 x > y,则返回 1

1、数字

## 原始
print(sorted([36, 5, -12, 9, -21]))
## sorted()函数也是一个高阶函数,它还可以接收一个 key 函数来实现自定义的排序。
## key 指定的函数将作用于 list 的每一个元素上,并根据 key 函数返回的结果进行排序。
print(sorted([36, 5, -12, 9, -21], key=abs))

输出结果

[-21, -12, 5, 9, 36]
[5, 9, -12, -21, 36]

2、字符串

## 默认情况下,对字符串排序,是按照 ASCII 的大小比较的
print(sorted(['bob', 'about', 'Zoo', 'Credit']))
## 可实现忽略大小写的排序
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower))
## reverse 为 true 表示反向排序
print(sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower, reverse = True))

输出结果

['Credit', 'Zoo', 'about', 'bob']
['about', 'bob', 'Credit', 'Zoo']
['Zoo', 'Credit', 'bob', 'about']

五、返回函数

1、函数作为返回值

例如:返回求和的函数

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum
f1 = lazy_sum(1,3,5,7,9)
f1
f1()  # 函数需要调用才能执行
# 调用 lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数
f2 = lazy_sum(1,3,5,7,9)
f1 == f2

输出结果

<function __main__.sum>
25
False

分析:在函数 lazy_sum 中又定义了函数 sum,并且,内部函数 sum 可以引用外部函数 lazy_sum 的参数和局部变量,当 lazy_sum 返回函数 sum 时,相关参数和变量都保存在返回的函数中,这种称为“闭包( Closure) ”的程序结构拥有极大的威力。

2、闭包

返回函数不要引用任何循环变量, 或者后续会发生变化的变量。

3、匿名函数

4、装饰器

装饰器”( Decorator):在代码运行期间动态增加功能的方式。

5、偏函数


模块

模块:Python中一个.py文件就是一个模块(Module)
==》提高了代码的可维护性;复用性;避免函数名和变量名冲突。

包(Package):按目录来组织模块的方法。例如:a.py(a模块) 与 b.py(b模块)与其他模块冲突,则选择一个顶层包名,例如mycompany,则 a 模块变成 mycompany.a、b模块变成 mycompany.b
==》每一个包目录下面都会有一个__init__.py 的文件,这个文件是必须存在的,用于标识包。

1、使用模块

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

'a test module'   ## 表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释

__author__ = '盛夏光年'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print("Hello world!")
    elif len(args) == 2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__ == '__main__':
    test()

2、作用域

  • 正常的函数和变量名是公开的( public),可以被直接引用,比如: abc,x123, PI 等;
  • 类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途;
  • 类似_xxx 和__xxx 这样的函数或变量就是非公开的( private),不应该被直接引用,比如_abc, __abc 等;
    注意: Python 并没有一种方法可以完全限制访问 private 函数或变量

3、第三方库

eg: Pillow、numpy、Jinja2
查看搜索目录:

import sys
print(sys.path)

添加搜索目录——方法1:

import sys
sys.path.append('/Users/michael/my_py_scripts')

==》这种方法是在运行时修改,运行结束后失效。

添加搜索目录——方法2:
设置环境变量 PYTHONPATH

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值