Python - 装饰器、高阶函数、匿名函数、类
2022-04-13 15:57 起个昵称 阅读(55) 评论(0) 编辑 收藏 举报1、装饰器
给函数加点东西
1 from functools import wraps 2 3 def addstar(func): 4 @wraps(func) # functools实现的装饰器,目的是保留被装饰的函数原本的名字 5 def diy_wrap(): # 自己定义的装饰器要的效果 6 return '*** ' + func() + ' ***' 7 return diy_wrap 8 9 @addstar # 使用自己定义的装饰器 10 def hello(): 11 return 'hello python' 12 13 print(hello()) # output: *** hello python *** 14 15 # ************************************************************************** 16 # 带上参数 17 def addstar(func): 18 @wraps(func) # functools实现的装饰器,目的是保留被装饰的函数原本的名字 19 def diy_wrap(*args, **kwargs): # 自己定义的装饰器要的效果 20 res = func(*args, **kwargs) 21 return '*** ' + res + ' ***' 22 return diy_wrap 23 24 @addstar # 使用自己定义的装饰器 25 def hello(): 26 return 'hello python' 27 28 @addstar # 使用自己定义的装饰器 29 def hi(name): 30 return 'hello ' + name 31 32 @addstar # 使用自己定义的装饰器 33 def nihao(name1, name2): 34 return 'hello ' + name1 + ' and ' + name2 35 36 print(hello()) # output: *** hello python *** 37 print(hi('Python')) 38 print(nihao('Java', 'Go')) 39 40 # ************************************************************************** 41 # 基于类的装饰器 42 class Star(): 43 def __init__(self, func): 44 self.func = func 45 46 def __call__(self, *args, **kwargs): 47 return '*** ' + self.func(*args, **kwargs) + ' ***' 48 49 @Star 50 def hh(): 51 return 'hhh'
2、高阶函数
map
1 """ 2 map(函数,待处理数据列表) 3 """ 4 l1 = list(map(str, [1,2,3,4])) 5 print(l1) 6 7 l2 = list(map(int, ['1', '2', '3', '4'])) 8 print(l2) 9 10 def double(x): 11 return 2 * x 12 l3 = list(map(double, [1,2,3,4])) 13 print(l3) 14 15 l4 = list(map(lambda x: 2 * x, [1,2,3,4])) 16 print(l4)
reduce
1 l1 = reduce(lambda x, y: x * y, [1, 2, 3, 4]) 2 print(l1) # 返回 24 3 l2 = reduce(lambda x, y: x * y, [1, 2, 3, 4], 5) 4 print(l2) # 返回 120 5 l3 = reduce(lambda a, b: a if (a > b) else b, [5, 8, 1, 10]) 6 print(l3) # 返回 10
filter
1 l1 = list(map(lambda x: x % 2 == 0, [1, 2, 3, 4, 5, 6])) 2 print(l1) # 返回 [False, True, False, True, False, True] 3 l2 = list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5, 6])) 4 print(l2) # 返回 [2, 4, 6] 5 l2 = list(filter(lambda x: x < 'i', 'hijack')) 6 print(l2) # 返回 ['h', 'a', 'c']
3、匿名函数
lambda
匿名函数,代码块简短,如一行for或一行if
list([lambda x: for x in range(10)])
list([lambda x: for x in range(10) if x % 2 == 0])
4、闭包
1 """ 2 什么是闭包 3 >一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数成为闭包Closure 4 闭包的作用 5 >闭包的最大特点就是引用了自由变量,即使生成闭包的环境已经释放,闭包仍然存在 6 >闭包在运行时可以有多个实例,即使传入的参数相同 7 >利用闭包,我们还可以模拟类的实例 8 小结 9 >闭包是携带自由变量的函数,即使创建闭包的外部函数的生命周期结束了,闭包所引用的自由变量仍会存在 10 >闭包在运行可以有多个实例 11 >尽量不要在闭包中引用循环变量,或者后续会发生变化的变量 12 """ 13 from math import pow 14 15 def make_pow(n): 16 def inner_func(x): 17 return pow(x, n) 18 return inner_func 19 20 pow2 = make_pow(2) 21 print(pow2(6)) # 返回 36.0
5、partial
当函数参数太多且有固定参数值时,可用partial函数
1 """ 2 partial:固定函数参数,返回一个新的函数 3 当函数参数太多,且某些参数固定时,可以使用functools.partial创建一个新的函数 4 """ 5 6 from functools import partial 7 8 def multiple(x, y): 9 return x * y 10 11 res = partial(multiple, y=2) 12 print(res(x=3)) # 3 * 2 = 6 13 print(res(x=4)) 14 print(res(x=5)) 15 16 res = partial(multiple, x=3) 17 print(res(y=4)) # 3 * 4 = 12 18 print(res(y=5)) 19 print(res(y=6)) 20 21 def new_math(x, y, z): 22 return str(x + y) + z 23 24 res = partial(new_math, z='元') 25 print(res(2,3)) # 5元 26 print(res(4,5)) # 9元
6、类 / 方法
类方法和静态方法
1 """ 2 静态方法没有self和cls参数,可以把它看成是一个普通的函数 3 """ 4 5 class A(): 6 bar = 1 7 8 @classmethod 9 def class_foo(cls): # 类方法 10 print('hello, ', cls) 11 print(cls.bar) 12 13 @staticmethod 14 def static_foo(): # 静态方法 15 print('hello, ', A.bar) 16 17 A.class_foo() # hello, <class '__main__.A'> 1 18 19 a = A() 20 a.static_foo() # hello, 1 21 22 A.static_foo() # hello, 1
魔法函数(也叫特殊方法)
1 """ 2 魔法函数也叫特殊方法 3 4 创建一个类的实例时,类会先调用__new__(cls[, ...])来创建实例,然后__init__方法再对该实例(self)进行初始化 5 注意事项: 6 ·__new__是在__init__之前被调用的 7 ·__new__是类方法,__init__是实例方法 8 ·重载__new__方法,需要返回类的实例 9 一般情况下,我们不需要重载__new__方法。但在某些情况下,我们想控制实例的创建过程,这时可以通过重载__new__方法来实现 10 """ 11 class A(): 12 _dict = dict() 13 14 def __new__(cls): 15 """ 16 重载__new__方法 17 """ 18 if 'key' in A._dict: 19 print('Exists') 20 return A._dict['key'] 21 else: 22 print('New') 23 return object.__new__(cls) # 不存在则创建实例 24 25 def __init__(self): 26 print('Init') 27 A._dict['key'] = self 28 29 a1 = A() # 第一次调用,不存在 30 a2 = A() # 后面调用就已经存在了 31 a3 = A()
str 和 repr
1 """ 2 str & repr 3 在类中加上repr方法,直接实例化类也能输出__str__的值,区别看最后两行注释 4 """ 5 class Foo(): 6 def __init__(self, name): 7 self.name = name 8 9 def __str__(self): 10 return self.name 11 12 def __repr__(self): # 可用 __repr__ = __str__ 替换 13 return self.name 14 15 16 f = str(Foo('hi')) # 输出hi 17 print(type(f)) # <class 'str'> 18 19 f1 = Foo('hi') # 输出hi 20 print(type(f1)) # <class '__main__.Foo'> 21 22 Foo('hi') # 加上__repr__方法,直接使用Foo('hi')也能输出name了 23 24 l = [] 25 l.append(Foo('hh')) 26 print(l) # 没有__repr__的输出 [<__main__.Foo object at 0x0000021246BD7FD0>] 27 # 有__repr__的输出 [hh]
7、property
property装饰器,可以将被装饰的方法当做属性来用。
下面示例:score方法被property装饰成一个属性,另一个score被@score.setter装饰成用来赋值的属性。
1 class Exam(object): 2 def __init__(self, score): 3 self._score = score 4 5 @property 6 def score(self): 7 return self._score 8 9 @score.setter 10 def score(self, val): 11 if val < 0: 12 self._score = 0 13 elif val > 100: 14 self._score = 100 15 else: 16 self._score = val 17 18 19 e = Exam(60) 20 print(e.score) 21 e.score = 90 22 print(e.score)
只用@property,不用@score.setter,这是score方法是一个只读属性,虽然能正常输出,但有提示。
1 class Exam(object): 2 def __init__(self, score): 3 self._score = score 4 5 @property 6 def score(self): 7 return self._score 8 9 def score(self, val): # 提示:Redeclared 'score' defined above without usage 10 if val < 0: 11 self._score = 0 12 elif val > 100: 13 self._score = 100 14 else: 15 self._score = val 16 17 18 e = Exam(60) 19 print(e.score) 20 e.score = 90 # 在Python 3.8中,依然能输出90这个值,但有黄色提示 21 print(e.score)
如果不用@property装饰器,可以用get和set方法
1 class Exam(object): 2 def __init__(self, score): 3 self._score = score 4 5 def get_score(self): 6 return self._score 7 8 def set_score(self, val): 9 if val < 0: 10 self._score = 0 11 elif val > 100: 12 self._score = 100 13 else: 14 self._score = val 15 16 17 e = Exam(60) 18 print(e.get_score) 19 e.set_score = 90 20 print(e.get_score)
打印输出是 <bound method Exam.get_score of <__main__.Exam object at 0x0000012711598400>>