掌握这些知识,你的python水平能更上一层楼
今天讲一些python中的高级用法,有助于大家更好的使用python这门语言。今天讲的这些知识是层层递进的关系,前面是后面的铺垫。
函数可变参数*args和**kwargs
python支持固定参数,默认参数,也和很多其他语言一样支持可变参数,只不过python支持的可变参数分为两种,*args是tuple,里面可以有任意多个element(包括0个)。**kwargs则是当你需要指定key word时需要用到的参数类型。
先考虑*args的情况,先看函数定义:
>>> def take_any_args(*args):
... print("type of args:" + str(type(args)))
... print("value of args:" + str(args))
...
>>> take_any_args(1)
type of args:<type 'tuple'>
value of args:(1,)
>>> take_any_args("a","b","c")
type of args:<type 'tuple'>
value of args:('a', 'b', 'c')
>>> take_any_args()
type of args:<type 'tuple'>
value of args:()
>>> take_any_args(['',''],['',''])
type of args:<type 'tuple'>
value of args:(['', ''], ['', ''])
再看参数提取:
def print_args(*args):
for arg in args:
print(arg) print_args("red", "blue", "green") def print_all(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print("{} -> {}".format(key, value)) print_all(1, 2)
print_all(a="red", b="blue", c="green")
red
blue
green
1
2
a -> red
c -> green
b -> blue
下面看看为什么需要**kwargs, 对于上面的print_args, 下面这种添加了keyword的调用方式会出错,所以就有了**kwargs的用武之地:
>>> def print_args(*args):
... for arg in args:
... print arg
...
>>> print_args(a=1,b=2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print_args() got an unexpected keyword argument 'a'
**kwargs的本质其实是dict,如下所示:
>>> def print_kwargs(**kwargs):
... for key,value in kwargs.items():
... print("{}->{}".format(key,value))
...
>>> print_kwargs(a="lalala",b="papapa")
a->lalala
b->papapa
通常再使用的时候都是二者合起来使用,如下所示:
def print_all(*args, **kwargs):
for arg in args:
print(arg)
for key, value in kwargs.items():
print("{} -> {}".format(key, value)) print_all(1, 2)
print_all(a="red", b="blue", c="green")
1
2
a -> red
c -> green
b -> blue
上面的知识大家差不多应该都知道,下面这种Unpacking的用法很多人都不太了解:
>>> def sample_function(a,b,c):
... print("{},{},{}").format(a,b,c)
...
>>> input = (1,2,3)
>>> sample_function(1,2,3)
1,2,3
#和上面的方法等效
>>> sample_function(*input)
1,2,3
unpack 使用kwargs,记住keyword要和函数声明时的变量名一致才行,否则会报错
>>> def sample_function(a,b,c):
... print("a->{},b->{},c->{}".format(a,b,c))
...
>>> input = {"a":1,"b":2,"c":3}
>>> sample_function(**input)
a->1,b->2,c->3
#与上面方法等效
>>> sample_function(a=input['a'],b=input['b'],c=input['c'])
a->1,b->2,c->3
lambda function
在python 中所有的东西都是object,不管是int也好,list也好都是object。函数也是object。这个概念很重要。
>>> def f(n):
... return n+1
...
>>> id(f)
4374076184
>>> g = f
>>> print g(2)
3
>>> id(g)
4374076184
上面的g和f所指向的object是同一个object
下面思考这样一个问题,如果 numbers = ["10", "3", "40", "14", "5"], 让你找出最大值怎么找?
>>> max(numbers)
''
这显然不对,因为max默认按照字母顺序排序了,所以需要额外提供排序信息:
>>> max(numbers, key=int)
''
int 就是一个function,然后看看如果用lambda function表示就是:
>>> max(numbers, key=lambda x:int(x))
''
再举一个例子, 下面是几个人的年龄,性别,地址,请找出年纪最大的人:
>>> person_zhangsan = {'age': 40, 'gender': 'male', 'home': 'beijing'}
>>> person_lisi = {'age': 35, 'gender': 'male', 'home': 'hangzhou'}
>>> person_wangwu = { 'age': 21, 'gender': 'female', 'home': 'chongqing'}
>>> people = [person_zhangsan, person_lisi, person_wangwu]
>>> max(people, key=lambda x:x['age'])
{'gender': 'male', 'age': 40, 'home': 'beijing'}
python在operator中提供了itemgetter这个函数,它起到的作用和lambda function一样,比如:
>>> from operator import itemgetter
>>> max(people, key=itemgetter("age"))
{'gender': 'male', 'age': 40, 'home': 'beijing'}
对比一下我还是更喜欢lambda function的定义,简洁明了
Decorator 装饰器
最长见的decorator的user case是什么?答:retry。 比如网络restful request碰到不稳定的server或者说server给你返回了5XX,你要不要retry。
一开始可能你的code长这样:
import requests
URL = "https://example.com/api" def get_items():
return requests.get(URL + "/items")
当然你还会有很多get function,比如get_apple, get_banana, get_orange, ...
实际部署之后发现server不稳定,不定期返回500,你就要加retry
如果只有一个get_items,你可能会这么写:
#第二版,加入retry
def get_items():
NUM_RETRY = 3
current_retry = 0
resp = None
while True:
resp = requests.get(URL + "/items")
if rest.status_code/100 == 5 and current_retry < NUM_RETRY:
current_retry += 1
continue
break
return resp
可是每一个fucntion都要改,是不是很累。。。
下面decorator隆重登场,decorator的本质是一个function。这个function的parameter有且仅有一个就是一个function object,返回值则是另一个不同的function
#比如已经有了一个普通function
def some_function(arg1,arg2,arg3):
#此处省略20行 some_function = some_decorator(some_function)
等效于
@some_decorator
def some_function(arg1,arg2,arg3):
#......
下面举一个decorator的例子,logging decorator
def logfuncname(func):
def wrapper(*args, **kwargs):
print("function name: " + func.__name__)
return func(*args, **kwargs)
return wrapper
>>> @logfuncname
... def some_func(n):
... return n+1
...
>>> print some_func(3)
function name: some_func
4
如上所示,logfuncname就是一个decorator,它的input是func,return了一个wrapper function。
下面我们回到一开始retry那个例子:
#第三版,定义decorator
def retry(func):
def wrapper(*args, **kwargs):
NUM_RETRY = 3
current_retry = 0
resp = None
while True:
resp = func(*args, **kwargs)
if rest.status_code/100 == 5 and current_retry < NUM_RETRY:
current_retry += 1
continue
break
return resp
return wrapper @retry
def get_items():
return requests.get(URL + "/items")
然后get_apple, get_banana, get_orange 什么的上面加上@retry就可以了
接下来问题来了,如果有另一个decorator也想用上怎么办?
decorator是可以叠加的,比如下面的例子,注意上下顺序就是decorator从左到右的顺序
@add2
@multi3
def foo(n):
return n + 1 #相当于foo = add2(multi3(foo))
#那么foo(3)就是14 @multi3
@add2
def foo(n):
return n + 1 #相当于foo = multi3(add2(foo))
#那么foo(3)就是18
如果想要改变retry的次数怎么办,比如get_apple想要retry 3次,但是get_banana想要retry 5次怎么办?
#第四版,定义带参数的decorator
def retry(num_retry):
def decorator(func):
def wrapper(*args, **kwargs):
current_retry = 0
resp = None
while True:
resp = func(*args, **kwargs)
if rest.status_code/100 == 5 and current_retry < num_retry:
current_retry += 1
continue
break
return resp
return wrapper
return decorator @retry(3)
def get_items():
return requests.get(URL + "/items")
这里其实用到了一个closure的概念,就是外层函数的参数在里层函数里是可见的,而里层函数的参数在外层不可见(当然这里也不需要)。
Decorator在flask中的实现原理
下面我们来看看flask中decorator是怎么实现的,简而言之:
class WebApp:
def __init__(self):
#初始化routes
self.routes = {}
def route(self, param):
def decorator(func):
#定义decorator时为routes赋值key/value
self.routes[param] = func
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
return decorator
def get(self, param):
try:
#get时根据key返回value
return self.routes[param]()
except KeyError:
return "ERROR - no such page" >>> app = WebApp()
>>> @app.route("/")
... def index():
... return 'Index Page'
...
>>> @app.route("/contact/")
... def contact():
... return 'Contact Page'
...
>>> app.get("/")
'Index Page'
>>> app.get("/contact/")
'Contact Page'
>>> app.get("/no-such-page/")
'ERROR - no such page'
掌握这些知识,你的python水平能更上一层楼的更多相关文章
- 掌握这些知识,你的python水平能更上一层楼(续)
笔者的上一篇python文章阅读量不错,看来python爱好者很多,所以再写一篇,以飨读者. 先接着上一篇讲一个问题,下面这段code有没有问题? def countcalls(func): coun ...
- 机器学习算法的基本知识(使用Python和R代码)
本篇文章是原文的译文,然后自己对其中做了一些修改和添加内容(随机森林和降维算法).文章简洁地介绍了机器学习的主要算法和一些伪代码,对于初学者有很大帮助,是一篇不错的总结文章,后期可以通过文中提到的算法 ...
- 制作一个简单的部门员工知识分享的python抽取脚本
需求: 基于公司的文化和公司部门间以及员工之间的工作需求状态,或者想要了解某一些技能.专业方面的知识需求.促进并提高员工们的技能认知和技术水平. 详细代码如下: 先说一下存入csv表格的表头字段: 1 ...
- [Python][小知识][NO.2] Python 字符串跨行连接,或拆分为多行显示
1.前言 又是一个字符串很长,但又是一种格式的小字符串直接连接而成的大字符串. 这么我们拆成多行,即美感,又易于我们修改. 例如 文件选择框中的 通配符: wildcard = "Pytho ...
- 深入理解python(一)python语法总结:基础知识和对python中对象的理解
用python也用了两年了,趁这次疫情想好好整理下. 大概想法是先对python一些知识点进行总结,之后就是根据python内核源码来对python的实现方式进行学习,不会阅读整个源码,,,但是应该会 ...
- Python-turtle库知识小结(python绘图工具)
turtle:海龟(海龟库) Turtle库是Python语言中一个很流行的绘制图像的函数库 使用之前需要导入库:import turtle • turtle.setup(width,height,s ...
- 完整的正则表达式知识汇总(Python知识不断更新)
## 大纲: ## 一.正则概述 1.正则是什么 正则就是一套规则,或者语法 2.正则的作用 让我们判断是否符合我们的的规则,或者根据规则找到符合规则的数据 3.使用场景 可以用正则判断我们输入的邮箱 ...
- 【知识碎片】python 篇
领域:运维 网站 游戏 搜索 嵌入式 C/S软件 Openstack二次开发 绿色版:Portable Python 面向对象.解释型动态语言 env python 切换版也好使,自己寻找系统中pyt ...
- 剑指offer-左旋转字符串-知识迁移能力-python
题目描述汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”abcX ...
随机推荐
- gitlab10.0安装手记
+ +exec chpst -e /opt/gitlab/etc/gitlab-workhorse/env -P \ + -U git \ + -u git \ + /opt/gitlab/embed ...
- git添加本地仓库与远程仓库连接
在本地建立一个文件夹,需要与远程git仓库进行连接,具体方法: <1>首先进入所在文件目录执行: git init 初始化git,紧接着 git add . git commit -m ...
- 十年磨一剑 Delphi重新崛起再写传奇
新年伊始,英巴卡迪诺公司(Embarcadero)就在其官网发布了"激动人心的RAD Studio2018年发展规划"公告(见上图).公告中指出,将在于2018年第一季度发布10. ...
- jq模仿雨滴下落的动画
效果如图: 实现思路:定时器每隔x秒生成宽高.下落速度(即动画执行时间).left随机的div. 1.CSS: body{ overflow: hidden;/*这是为了防止出现滚动条*/ } .co ...
- 机器学习03:K近邻算法
本文来自同步博客. P.S. 不知道怎么显示数学公式以及排版文章.所以如果觉得文章下面格式乱的话请自行跳转到上述链接.后续我将不再对数学公式进行截图,毕竟行内公式截图的话排版会很乱.看原博客地址会有更 ...
- @Scope注解
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)这个是说在每次注入的时候回自动创建一个新的bean实例 @Scope(value=Config ...
- web2 - JavaScript
JavaScript 知识要点 参考教材一 参考教材二 参考教材三 1.JavaScript 和 Java 的关系? 2.JavaScript 在编程中可以做什么? 3.如何在 html 中使用 Ja ...
- Mysql--Database Exception (#42) 数据库错误
mysql是phpstudy中的mysql,出现这个错误八成是php.ini中没有设置mysql.sock 使用探针或者phpinfo查看php.ini的位置. sudo find / -name m ...
- Egret学习笔记.2 (Egret开发环境)
配置Egret的开发环境是很简单的,去https://www.egret.com/products/engine.html下载 然后基本就是下一步下一步,安装好了就好了,装好了选择Wing组件,然后下 ...
- yaf框架学习文件配置
文件配置: 在配置php支持yaf的时候,可以设置一个参数yaf.environ:把本地开发设置成develop.测试环境配置成test.生产环境配置成product. [yaf] extension ...