代码改变世界

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>>