Python中的Lambda函数及其用法
Lambda函数又称为匿名函数,匿名函数就是没有名字的函数。有些函数如果只是临时一用,而且它的业务逻辑也很简单时,就可以将其定义为匿名函数。
匿名函数有个限制,就是只能有一个表达式,不用写return
,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。
追求梦想,永不止步
接上一篇介绍Python中@staticmethod和@classmethod的用法的文章。虽然@classmethod
和@staticmethod
非常相似,但两个修饰符的使用情况仍略有不同。
为了调用父类(超类)的一个方法,可以使用super()
函数,比如:
1 | class A: |
super()
函数的一个常见用法是在__init__()
中确保父类被正确的初始化:
1 | class A: |
说明__init__()
函数:定义类的时候,若是添加__init__()
函数,那么在创建类的实例的时候,实例会自动调用这个方法,一般用来对实例的属性进行初始化。
super()
的另外一个常见用法出现在覆盖Python特殊方法的代码中,比如:
1 | class Proxy: |
实际上,大家对于在Python中如何正确使用super()
函数普遍知之甚少。你有时候会看到像下面这样直接调用父类的一个方法:
1 | class Base: |
尽管对于大部分代码而言这么做没什么问题,但是在更复杂的涉及到多继承的代码中就有可能导致很奇怪的问题发生。比如,考虑下面的情况:
1 | class Base: |
运行这段代码后就会发现Base.__init__
被调用两次,如图所示:
1 | >>> c = C() |
可能两次调用Base.__init__()
没什么坏处,但有时候却不是。另一方面,假设在代码中换成使用super()
,结果就很完美了:
1 | class Base: |
运行这个新版本后,你会发现Base.__init__()
方法只会被调用一次:
1 | >>> c = C() |
所以说,super()
是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
说明:MRO就是类的方法解析顺序表,其实也就是继承父类方法时的顺序表,下面会有更详尽的介绍。
为了弄清它的原理,我们需要花点时间解释下Python是如何实现继承的。对于你定义的每一个类,Python会计算出一个所谓的方法解析顺序(MRO)列表。这个MRO列表就是一个简单的所有基类的线性顺序表。例如:
1 | >>> C.__mro__ |
为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
老实说,你所要知道的就是MRO列表中的类顺序会让你定义的任意类层级关系变得有意义。
当你使用super()
函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()
并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。这也是为什么在第二个例子中你不会调用两次Base.__init__()
的原因。
super()
有个令人吃惊的地方是它并不一定去查找某个类在MRO中下一个直接父类,你甚至可以在一个没有直接父类的类中使用它。例如,考虑如下这个类:
1 | class A: |
如果你试着直接使用这个类就会出错:
1 | >>> a = A() |
但是,如果你使用多继承的话看看会发生什么:
1 | >>> class B: |
你可以看到在类A中使用super().spam()
实际上调用的是与类A毫无关系的类B中的spam()
方法。这个用类C的MRO列表就可以完全解释清楚:
1 | >>> C.__mro__ |
在定义混入类的时候这样使用super()
是很普遍的。
然而,由于super()
可能会调用不是你想要的方法,你应该遵循一些通用原则。首先,确保在继承体系中所有相同名字的方法拥有可兼容的参数签名(比如相同的参数个数和参数名称)。这样可以确保super()
调用一个非直接父类方法时不会出错。其次,最好确保最顶层的类提供了这个方法的实现,这样的话在MRO上面的查找链肯定可以找到某个确定的方法。
在Python社区内对于super()
的使用有时候会引来一些争议。尽管如此,如果一切顺利的话,你应该在你最新的代码中使用它。Raymond Hettinger为此写了一篇非常好的文章,有兴趣的话可以去查查看,文章通过大量的例子向我们解释了为什么super()
是极好的。
最后通过一个很好的实例帮助大家加深一下记忆:
1 | class FooParent(object): |
执行结果:
1 | Parent |
引用文章:
本教程针对的是Mac环境
当博文越来越多的时候,标签和分类已经不能提供太大的作用,无法准确的定位到自己想要看的博文上去了,所以添加一个站内搜索功能是很有必要的。
Hexo适配多款搜索插件,个人感觉”Local Search”已满足日常需要,所以下面介绍为Hexo添加”Local Search”搜索插件的过程。
在命令行中cd
到自己的hexo文件夹下(例:/Users/rilzob/hexo
),执行npm install hexo-generator-searchdb --save
命令进行安装,等待安装完成。
修改当前目录下的_config.yml文件(例:/Users/rilzob/hexo/_config.yml
),新增以下内容到该文件内的任意位置。
1 | # Search |
注意:每个冒号后面都有空格
修改主题目录下的_config.yml文件(例:/Users/rilzob/hexo/themes/xxx/_config.yml
),找到该文件内的
1 | # Local search |
代码段,将其修改为:
1 | # Local search |
即将enable: false修改为enable: true。
依旧在命令行中进行操作,在hexo文件夹下依次执行hexo g
,hexo server
和hexo deploy
指令即可。这样搜索功能就添加成功了。
引用文章:
本教程针对的是Mac环境
打开命令行,cd
进入博客所在文件夹。执行命令hexo new page categories
,来新建一个页面,并命名为categories。成功后会提示:INFO Created: ~/hexo/source/categories/index.md
根据上面的路径找到index.md这个文件,打开后默认内容如下:
1 | --- |
编辑新创建的页面,添加type: "categories"
到内容中(注意,这些属性和属性值之间必须有一个空格),主题将自动为这个页面显示所有分类,添加后是这样的:
1 | --- |
保存并关闭文件。
打开需要添加分类的文章,为其添加categories属性。下方的categories: Python
表示添加这篇文章到“Python”这个分类中。
注意:Hexo中一篇文章只能属于一个分类,也就是说如果在”Python”下方添加”-xxx”,Hexo不会产生两个分类,而是把分类嵌套,即该文章属于”Python“下的”-xxx“分类。
1 | --- |
回到hexo文件夹下,依次执行hexo g
,hexo server
和hexo deploy
命令(重新部署)。
cd
进/hexo/themes/hexo-theme-next-5.1.4
文件夹内,编辑该目录下的_config.yml文件(把链接加上),将源代码:
1 | menu: |
改为:
1 | menu: |
即将menu中的categories:/categories || th
的注释去掉,然后保存并退出。
回到hexo
文件夹下,依次执行hexo g
,hexo server
和hexo deploy
命令,即可看到菜单栏中新增了一个Categories选项。
至此,成功给文章添加分类,点击Index上的Categories可以看到所有的分类情况,再点击该分类就可以看到该分类下的所有文章。当然,前提是添加了categories: xxx字段。
打开命令行,cd
进入博客所在文件夹。执行命令hexo new page tags
,来新建一个页面,并命名为tags。成功后会提示:INFO Created: ~/hexo/source/tags/index.md
根据上面的路径找到index.md这个文件,打开后默认内容如下:
1 | --- |
编辑新创建的页面,添加type: "tags"
到内容中,主题将自动为这个页面显示所有分类,添加后是这样的:
1 | --- |
保存并关闭文件。
打开需要添加标签的文章,为其添加tags属性。下方的tags: Django
表示添加这篇文章到“Django”这个标签中。
1 | --- |
回到hexo文件夹下,依次执行hexo g
, hexo server
和hexo deploy
命令(重新部署)。
cd
进/hexo/themes/hexo-theme-next-5.1.4
文件夹内,编辑该目录下的_config.yml文件(把链接加上),将源代码:
1 | menu: |
改为:
1 | menu: |
即将menu中的tags: /tags/ || tags
的注释去掉,然后保存并退出。
回到hexo
文件夹下,依次执行hexo g
,hexo server
和hexo deploy
命令,即可看到菜单栏中新增了一个tags选项。
引用文章:
1.Hexo使用攻略-添加分类及标签 | linlif-blog
Python支持可变参数,最简单的方法莫过于使用默认参数。
1 | def test_defargs(one, two=2): # 参数one没有默认值,two的默认值为2 |
另一种达到可变参数(Variable Argument)的方法:
使用*args
和**kwargs
语法。
*args
是可变的位置参数(postional arguments)列表;
**kwargs
是可变的关键词参数(keyword arguments)列表;
并且规定位置参数必须位于关键词参数之前,即*args
必须位于**kwargs
之前。
以下是用位置参数正确调用函数的实例:
1 | def print_hello(name, sex): |
用于函数调用,通过“键-值”形式加以指定。
使用关键字参数可以让函数更加清晰,容易使用,同时也清除了参数的顺序需求。
以下是用关键字参数正确调用函数的实例:
1 | print_hello('Chen', sex=1) # 有位置参数时,位置参数必须在关键字参数的前面 |
以下是错误的调用方式:
1 | # print_hello(name='Chen', 1) # 有位置参数时,位置参数必须在关键字参数前面 |
顾名思义,可变参数就是传入的参数个数是可变的,可以是任意个。*args
和**kwargs
两者都是Python中的可变参数。
*args
Python中规定参数前带*
的,称为可变位置参数,只是我们通常称这个可变位置参数为*args
而已,叫其他的也是一样的。
以数学题为例,给定一组数字a,b,c……,请计算a^2 + b^2 + c^2 + ……。
要定义这个函数,必须确定输入的参数。由于参数个数不确定,我们可以首先想到把a,b,c……作为一个list或者tuple传进来,这样函数就可以定义为:
1 | def calc(numbers): |
但是调用的时候,需要先组装出一个list或tuple:
1 | >>> calc([1, 2, 3]) |
所以,为了方便起见我们把函数的参数改为可变位置函数:
1 | def calc(*numbers) # 可变位置参数 |
定义可变位置参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*
号。在函数内部,参数numbers
接收到的是一个tuple,因此函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:
1 | >>>calc(1,2) |
如果已经有一个list或tuple,要调用一个可变位置参数怎么办?可以这么做:
1 | >>>nums = [1, 2, 3] |
这种做法当然是可行的,问题是太繁琐了,所以Python允许在list或tuple前面加一个*
,把list或tuple的元素变成可变位置参数传进去:
1 | >>>nums = [1, 2, 3] |
总而言之,*args
用来表示函数接收可变长度的非关键字参数列表作为函数的输入。我们可以通过以下这个例子进一步理解*args
:
1 | def test_args(normal_arg, *args): |
上面代码的执行结果如下:
1 | first normal arg: normal |
**kwargs
同理,Python中规定参数前带
的,称为可变关键字参数,通常用kwargs表示。
**kwargs
表示函数接收可变长度的关键字参数字典作为函数的输入。当我们需要函数接收带关键字的参数作为输入的时候,应当使用**kwargs
。我们可以通过以下的例子进一步理解**kwargs
:
1 | def test_kwargs(**kwargs): |
以上代码的执行效果如下:
1 | name = python |
以上例子只是*args
和**kwargs
基本使用的例子。下面再给出一个用*args
和**kwargs
来定义能够接受列表输入和字典输入的函数的例子。
*args
和**kwargs
来调用函数比如我们有如下接受普通输入参数的函数:
1 | def normal_func(arg1, arg2, arg3): |
使用*args
和**kwargs
来调用这个函数的代码如下:
1 | # 使用*args |
以上三段代码的输出均为:
1 | arg1: python |
引用文章:
编辑文章,生成markdown文件,并将文章放到/hexo/source/_posts
目录下,一个md文件对应一篇博客文章。
修改文章头部:
1 | --- |
在命令行中cd到_posts目录下并执行hexo generate
命令(生成静态页面)。
再执行hexo server
命令(本地上传文章),上传后可以到http://localhost:4000/ 预览博客效果。
最后执行hexo deploy
命令,上传文章到github.io上就完成了。
其他Hexo命令:
引用文章: