1.一等函数: 运行时候创建,
- 可以给变量赋值;
- 也可以作为函数的返回结果;
def factorial(n):
"""
return n
"""
return 1 if n<2 else n*factorial(n-1)
fact = factorial
print(fact(20))
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 是字典;
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]))
callable(sort) #查看是否可以被调用<br>def __call__(self): #类定义中包含这个函数时候,对象可以直接调用(p1()), 上面callable 返回也会是true;
那么对于一个自定义的类,如何实现该类的实例化对象的可调用;定义def __call__(self) :
这样自定义的类实例,一样可以传递到这些高阶函数中使用;
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:
#生成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.打包/解包:
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)
函数中增加装饰器基础版:
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;
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__

有专门的方法查看函数的签名
from inspect import signature signature(test)
original result:

Updated result:

对于装饰器来讲,如何传递额外参数进装饰器,比如信息打印等级;
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, 下面是简单的例子;
import logging from functools import wraps
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 装饰器可以把方法转换成相同名称的只读属性,可以与定义的属性配合使用,防止被修改;
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 中定义一个类时候,要考虑到其他函数/对象使用它时候,需要该类能够支持一些操作;
下面只是一些简单的过程,具体使用时候注意
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
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) : 空间换时间
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;
浙公网安备 33010602011771号