变量作用域
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
x = int(2.9) # 内建作用域 g_count = 0 # 全局作用域 def outer(): o_count = 1 # 闭包函数外的函数中 def inner(): i_count = 2 # 局部作用域
global和nonlocal关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字。
num = 1 def fun1(): global num # 需要使用 global 关键字声明 print(num) num = 123 print(num) fun1() print(num)
如果要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量nonlocal关键字,如下:
def outer(): num = 10 def inner(): nonlocal num # nonlocal关键字声明 num = 100 print(num) inner() print(num) outer()
传入函数
变量也可以指向函数,函数的参数能接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数就称之为高阶函数。
def add(x, y, f): print(f(x) + f(y)) add(-5, 6, abs) # 11
-
map
map()函数接受俩个参数,一个是函数,一个是Iterator,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator。
def f(x): return x * x r = map(f, [1, 2, 3, 4, 5]) print(r) # [1, 4, 9, 16, 25] print(list(map(str, [1, 2, 3, 4, 5]))) # ['1', '2', '3', '4', '5']
-
filter
filter()函数用于过滤序列。filter()函数也接受一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True和False决定保留还是丢弃元素。
def is_odd(n): return n % 2 == 1 def not_empty(s): return s and s.strip() print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))) # [1, 5, 9, 15] print(list(filter(not_empty, ['A', '', 'b', ' ', 'c', None]))) #['A', 'b', 'c']
注意:filter()函数转换成list
练习题:取出1~1000中的回数。回数是指从左向右读和从右向左读都是一样的数,例如12321,909。
def get(l): s = str(l) return s == s[::-1] # 请回顾切片 print(list(filter(get, range(1,1000))))
-
sorted
sorted()函数可以对list进行排序
sorted([36, 5, -12, 9, -21]) # [-21, -12, 5, 9, 36] sorted([36, 5, -12, 9, -21], key = abs) #[5, 9, -12, -21, 36] sorted(['bob', 'about', 'Zoo', 'Credit']) # ['Credit', 'Zoo', 'about', 'bob'] 对字符串排序,是按照ASCII的大小比较的 sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower) # ['about', 'bob', 'Credit', 'Zoo'] sorted(['bob', 'about', 'Zoo', 'Credit'], key = str.lower, reverse = True) # ['Zoo', 'Credit', 'bob', 'about']
返回函数
当我们调用c时返回的是求和函数,每次调用都会返回一个新的函数,即使传入相同的参数,所以f1和f2调用的结果互不影响。
def c(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum print(c(1, 3, 4, 5, 6)()) f1 = c(1, 3, 5, 7, 9) f2 = c(1, 3, 5, 7, 9) print(f1 == f2) # False
匿名函数
- 关键字lambda表示匿名函数,冒号前面的x表示函数参数。
- 匿名函数只能有一个表达式,不用写return,返回值就是该表达式的结果
- 匿名函数没有名字,不必担心函数名冲突
- 匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
list(map(lambda x: x * x, [1, 2, 3, 4, 5])) # def f(x): # return x * x def build(x, y): return lambda: x * x + y * y
装饰器
在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
我们定义一个能打印日志的decorator——log,它能接受一个函数作为参数,并返回一个函数。调用time()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志。
def log(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('call %s():' %func.__name__) return func(*args, **kwargs) return wrapper @log # 相当执行语句now = log(now) def time(): print('2015-12-09')
如果decorator本身需要传入参数、那么需要编写一个返回decorator的高阶函数。比如,要自定义log的文本。
def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print('%s %s():' %(text, func.__name__)) return func(*args, **kwargs) return wrapper return decorator @log('execute') # 相当执行语句now = log('execute')(now) def time(): print('2015-12-09')
因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
不需要编写 wrapper._ name_ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的。
偏函数
通过设定参数的默认值,可以降低函数调用的难度,而偏函数就可以做到这一点。
假设要转换大量的二进制字符串,每次都传入++int(x, base = 2)++非常麻烦,我们就可以定义一个函数,把默认的base = 2传进去
def int2(x, base = 2) return int(x, base)
functools.partial就帮助我们创建一个偏函数,不需要我们自定义int2()
import functools int2 = functools.partial(int, base = 2)