1.一等函数: 运行时候创建,
- 可以给变量赋值;
- 也可以作为函数的返回结果;
1 2 3 4 5 6 7 8 | def factorial(n): """ return n """ return 1 if n< 2 else n * factorial(n - 1 ) fact = factorial print (fact( 20 )) |
1 2 3 4 5 6 7 8 9 10 | def make_average(): #返回一个函数; num = [] def average(value): num.append(value) return sum (num) / len (num) return average avg = make_average() avg( 3 ) |
2. 高阶函数 + 列表/字典推导:
- 接受函数作为参数
- 或者函数作为返回结果 map/reduce/filter/sorted #注意这里的map是根据提供的函数对指定的序列做映射的高阶函数,dict 是字典;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | usernames = [ "pear" , "apple" , "peach" , "cherry" ] num_list = [ 2 , 3 , 1 , 5 , 4 , 9 ] cal_list = list ( map (factorial,num_list)) #map 作为高阶函数,可以接收函数作为参数 cal_list1 = [factorial(x) for x in num_list] ##列表推导 gen_fun = (x * x for x in num_list) ##generator print (cal_list,cal_list1) print ( next (gen_fun)) #next result = {factorial(num):num for num in num_list} #函数作为参数传到高阶函数中,字典推导 与 上面列表推导类似 print (result) print ( list ( map (factorial, filter ( lambda x: x % 2 , num_list)))) ## 通过 print ( callable (factorial)) #查看是否可以调用 print ( sorted (usernames,key = lambda x:x[ 0 ])) |
1 | callable (sort) #查看是否可以被调用<br>def __call__(self): #类定义中包含这个函数时候,对象可以直接调用(p1()), 上面callable 返回也会是true; |
那么对于一个自定义的类,如何实现该类的实例化对象的可调用;定义def __call__(self) :
这样自定义的类实例,一样可以传递到这些高阶函数中使用;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Surprise(): def __init__( self ,items): self ._items = items def pick( self ): try : return self ._items.pop() except Exception as e: print ( str (e)) def __call__( self ,var = 0 ): #return self.pick() self ._items.append(var) return self ._items s = Surprise([ 1 , 2 , 3 , 4 ]) print (s()) print ( callable (s)) m_1 = map (s,[ 12 , 3 , 4 , 5 ]) for i in m_1: print (i) |
EXAMPLE2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #生成HTML标签 #<p>hellp</p> #<item clase = '' size='small'>a</item> def make_element(name, * content, cls = None , * * kwargs): #不确定参数 if cls : kwargs[ 'class' ] = cls pairs = [f "{attr}={value}" for attr, value in kwargs.items()] #字符串格式化 attr_str = ' ' .join(pairs) #join使用 if not content: return f "<{name}{attr}/>" elements = [f "<{name} {attr_str}>{con}<{name}/>]" for con in content] #字符串格式化 return '\n' .join(elements) print (make_element( "p" , "hello" , "word" , cls = "clear" ,size = "small" ,color = "red" )) |
3.打包/解包:
1 2 3 4 5 | d1 = { "a" : 1 , "b" : 2 } d2 = { "c" : 3 , "d" : 4 } #new_d = d1 + d2 #dict不支持 + 操作, list 可以 new_d = { * * d1, * * d2} #这里就是使用打包/解包操作,类似不确定参数传递 |
4. 装饰器: 参考link
- 以目前的理解,装饰器其实就是利用上面的高阶函数,一层层的调用的函数;
- 对于这些层层调用函数中的参数,如果存在额外的参数要求,通过多包装几个层级来实现;
- 最里面的两个层级是固定的:
- 最里层具体的加装部分,参数与被装饰函数相同,或者使用不确定参数;
- 次里层参数就是被装饰函数,返回就是里层装饰过的函数;这里也是使用@wraps保存原函数信息层级;@wraps(func)
函数中增加装饰器基础版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import time def build_func_with_time_record(func): '''here is the build func ''' def wrap( * args, * * kwargs): '''here is the wrap ''' start = time.time() result = func( * args, * * kwargs) end = time.time() print ( 'function {} total cost time {}' . format (func.__name__, end - start)) return result return wrap @build_func_with_time_record def test(a, b): ''' here is the test func ''' time.sleep( 2 ) return a + b test( 12 , 45 ) help (test) test.__name__ test.__doc__ |
结果可以看到这方法会丢失原始函数的相关信息; 可以通过使用functools 中的wraps 将原始函数信息保存下来;在传递func 参数内进行wrap;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import time from functools import wraps #diff def build_func_with_time_record(func): '''here is the build func ''' @wraps (func) #diff def wrap( * args, * * kwargs): '''here is the wrap ''' start = time.time() result = func( * args, * * kwargs) end = time.time() print ( 'function {} total cost time {}' . format (func.__name__, end - start)) return result return wrap @build_func_with_time_record def test(a, b): ''' here is the test func ''' time.sleep( 2 ) return a + b test( 12 , 45 ) help (test) test.__name__ test.__doc__ |
有专门的方法查看函数的签名
1 2 | from inspect import signature signature(test) |
original result:
Updated result:
对于装饰器来讲,如何传递额外参数进装饰器,比如信息打印等级;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def log1(level = None ,message = None ): def decorator(func): def wrapper( * arg, * * kw): if level: print (f 'log leve{level}, default head is {message}' ) return func( * arg, * * kw) return wrapper return decorator @log1 () def func1(a,b): return (a + b) @log1 ( 'leve1' , "DEBUG" ) def func2(a,b): return (a * b) print (func1( 1 , 4 )) print (func2( 5 , 34 )) |
python 中自带了一个logging, 下面是简单的例子;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import logging from functools import wraps<br> from operator import add, mul logging.basicConfig( format = "%(asctime)s %(name)s %(lineno)d %(levelname)s %(message)s" ) logging.root.setLevel(logging.NOTSET) def log(level,name = None , message = None ): def decorator(func): logname = name if name else func.__name__ log = logging.getLogger(logname) logmsg = message if message else f "function <{func.__name__}> is running..." @wraps (func) def wrapper( * args, * * kwargs): log.log(level,logmsg) # print(logmsg) return func( * args, * * kwargs) return wrapper return decorator @log (level = logging.DEBUG) def func_cat(tx1,tx2, * arg, * * kwarg): print ( type (arg)) print (kwarg) func_cat( 1 , 3 , 5 , 6 , 8 ,a = 5 ) print (add( 12 , 5 )) time.sleep( 2 ) func_cat( 1 , 3 , 5 , 8 , 12 ,x = 5 ) |
关于 python @property 简单介绍:这是python自带的一种装饰器,用来修饰方法的,主要是用来创建只读属性,@property 装饰器可以把方法转换成相同名称的只读属性,可以与定义的属性配合使用,防止被修改;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class HUMAN: def __init__( self , name, age): self ._name = name self ._age_readOnly = age def get_name( self ): return self ._name @property def age( self ): return self ._age_readOnly class STUDENT(HUMAN): def __init__( self ,name, age, grade): HUMAN.__init__( self , name, age) self ._grade = grade def do_homework( self ): print ( '{} finish the homework when he is {} at grade{}.' . format ( self ._name, self .age, self ._grade)) self ._name = "new_name" #error self.age=22 #假如只能根据上面猜测变量名字时候,该变量是不可以改的 self ._grade = 1 print ( 'after several years\n{} finish the homework when he is {} at grade{}.' . format ( self ._name, self .age, self ._grade)) return if __name__ = = "__main__" : h1 = HUMAN( "xiaoming" , 15 ) print (h1.get_name()) print (h1.age) #这里的表现形式,就将age方法变成一个只读属性,注意调用时候不能有() s1 = STUDENT( "Hua" , 11 , 6 ) s1.do_homework() |
5. python 风格的对象;参考link
在python 中定义一个类时候,要考虑到其他函数/对象使用它时候,需要该类能够支持一些操作;
下面只是一些简单的过程,具体使用时候注意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import math class vector: """python 风格类的定义 单下划线 : 只是语言约定,不会直接读取,私有属性 双下划线 : 在实际解释过程,该变量会被改名,并且如果继承过程中,子类与父类取了同样的名字,不会被覆盖;dir 可以用来查看实例的属性 单下划线结尾 """ __slot__ = ( '__x' , '__y' , '_z' ) #高速解释器,变量个数;否则的话,会新建一些额外属性;可以有效减少空间占用; def __init__( self ,a,b): self .__x = a self .__y = b self ._z = a + b @property def x( self ): return self .__x @property def y( self ): return self .__y def __str__( self ): return str ( tuple ( self )) def __iter__( self ): return (i for i in ( self .__x, self .__y)) def __repr__( self ): """ return vector(__x,__y) """ return (f "{type(self).__name__} ({self.__x},{self.__y})" ) def __hash__( self ): return hash ( self .__x) ^ hash ( self .__y) def __abs__( self ): return math.hypot( self .__x, self .__y) def __bool__( self ): return bool ( abs ( self )) v1 = vector( 3 , 5 ) for i in v1: #__iter__ print (i) print (v1) #__repr_ print ( str (v1)) #__repr_ print ( hash (v1)) print ( abs (v1)) print (v1._z) #约定为私有变量,但是还是可以读取到的; #print(v1.__x) #经过改名以后,是无法读到的; print ( dir (v1)) |
还有多重继承,操作符重载...
上下文管理器:通过 with expression [as target] 来实现,而expression 中实现 “上下文管理器协议”;
- __enter__: 在进入with语法前调用,返回值会 赋给 with 中的target
- __exit__: 在退出with 语法块时调用,一般用作异常处理;
- 在python中标准库提供了contextlib 模块,将上下文管理器当成一个 装饰器 来使用; 参考link
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class TimeRecord: def __init__( self ): print ( "here is __init__" ) self ._start = 0 self ._end = 0 def __enter__( self ): print ( "here is __enter__" ) self ._start = time.time() def __exit__( self ,exc_type,exc_value,traceback): print ( "args" , exc_type, exc_value, traceback) self ._end = time.time() print (f "total time is {self._end - self._start}" ) def f(n): return 1 if n < 2 else f(n - 1 ) + f(n - 2 ) with TimeRecord(): print (f( 5 )) |
6. 性能优化:
- 使用函数去处理:局部变量操作比全局变量要快
- __slot__
- 缓存: lru_cache (functools) : 空间换时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | from functools import lru_cache class TimeRecord: def __init__( self ): self ._start = 0 self ._end = 0 def __enter__( self ): self ._start = time.time() def __exit__( self ,exc_type,exc_value,traceback): print ( "args" , exc_type, exc_value, traceback) self ._end = time.time() print (f "total time is {self._end - self._start}" ) def fib(n): return 1 if n < 2 else fib(n - 2 ) + fib(n - 1 ) @lru_cache def fib_with_cache(n): return 1 if n < 2 else fib_with_cache(n - 1 ) + fib_with_cache(n - 2 ) with TimeRecord(): fib( 40 ) with TimeRecord(): fib_with_cache( 40 ) |
7. 打包分发工具,可以使用setuptools;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)