Python学习一(面向对象和函数式编程)
学习了一周的Python,虽然一本书还没看完但是也收获颇多,作为一个老码农竟然想起了曾经荒废好久的园子,写点东西当做是学习笔记吧
对Python的语法看的七七八八了,比较让我关注的还是他编程的思想,那种和C语言不同的感觉
首先是面向对象的概念:
在Python中一切皆对象,因此包括类,类型,以至于函数都是对象,每个对象都有自己的一块空间用于存放他的东西,这个概念是之前的C语言编程中一直没有的概念.因此类生成对象的过程并不是类的实现,而是一个可以生成对象的对象用他方法(也可以说是构造函数)生成了一个和他具有一定关系的对象.而类这个对象本身也是由元类(MetaClass)来生成的,元类可以控制类的生成方法甚至他的一些特性和特征,但一般用到的非常少,所以暂时也没有深入去研究
而函数本身也是对象,由于Python支持动态的修改对象,因此我们可以给函数增加一些特征和属性,类似下面这样:
def foo(i):
foo.n += i
return foo.n
c = foo
c.n = 0
上面这个实际上是实现了一个累加器,重复调用这个函数里面的计数值就会不断增加,而累加器中就包含了一个变量n,这个变量存储在foo这个函数对象中,而c实际上只是对foo的引用,两个对象实际指向一个空间,那么如果我需要再生成一个累加器的话 就不能重用foo了,那么就需要一个用于生成累加器的一个函数方法
def func(n = 0):
def foo(i):
foo.n += i
return foo.n
foo.n = n
return foo c = func()
d = func()
这样实际上我们就得到了一个可以用于生成函数对象的函数对象,就和用类来生成对象是相同的.c和d是两个不同的累加器,有各自的scope,因此能够各自工作不受影响,就和两个类对象相似.
弄到这里我又关注了一下函数编程的概念,虽然了解并不深,但其中的很多思想很有意思,Python应该是可以实现部分函数编程的,包括他引入lambda表达式,当然可能跟那些本身就是函数编程的语言,如Lisp或者Haskell之类的有一定距离吧
函数编程中关注函数和表达式,而弱化命令编程中的命令和流程,因此条件和循环都会被表达式或者函数递归所替代,比如下面这个例子
feb = lambda n: (n == 0 or n == 1) and 1 or feb(n - 1) + feb(n - 2)
这段代码等同于下面这段C代码,实际上就是一个通过递归实现菲波那切数列的简单例子
int feb(n)
{
if ( n == || n == ) return ;
else return ( feb(n - ) + feb(n - ));
}
让我惊奇的是居然可以使用and和or来替代if,else的作用,这个源于and和or的短路运算,也就是A and B时如果A为True则执行B,否则不执行B,而A or B中如果A为True则不执行B,反之执行B.
但是这个代码也存在问题,如果在A and B or C中B为False也会导致再执行C,这个问题可以通过将代码改为A and (B or True) or C更为稳妥
那么相应的if...then...elif...then...else也可以写成A and (B or True) or C and (D or True) or E的形式
但是目前为止能够用在表达式中的只能是表达式或者函数,如果企图插入语句就会失效了,好在函数编程中应该是不存在语句的,连最基本的赋值语句都是要舍弃的,号称变量不变性,但是就具体来说目前我的理解还有限
那么如何直接生成一个斐波那契数列而不是单个元素呢,可以使用下面的方法:
febo = lambda n: list(map(feb, range(n)))
这个方法使用了Python在函数编程中常用的map函数,在Python3中map函数得到的是迭代器,因此想要获得列表必须用list提取一下
计算结果如下:
febo(10)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
不过这个方法在执行效率上是存在问题的,因为算每个斐波那契数的时候都要把之前的算一遍,更加理想的方式是在列表生成的过程中直接使用列表中的数值进行计算
为了便于理解,我把这个过程分为三个函数,不过即使这样理解起来仍然需要一定的逻辑思维能力.
首先是一个数列处理函数:
febon = lambda lst: len(lst) < 2 and (lst.append(1) or True) or lst.append(lst[-1] + lst[-2])
这里面首先判断长度是否小于2,如果是则给列表添加1,否则添加列表的最后两项之和.其中由于append函数返回值为None,因此必须在之后强制变为True,使其无法执行后面的or代码
然后是一个递归函数用于生成序列
feb = lambda n, lst:n == 0 and lst or (febon(lst) or True) and feb(n-1, lst)
这里面需要注意的是在Python中逻辑运算的结果并不一定是逻辑值,但当其用于逻辑判断是则会根据其值的类型自动判断其为True还是False,但是表达式的值仍然是实际的值,这点跟C语言有很大区别
比如1 and 2这个表达式的真值为True,但是表达式的值为2,因为1为True,因此表达式又判断了2,2也为True,则最终的值就定格在2了
而1 or 2的表达式结果就是1,因为1为True之后就不在计算or后面的表达式了
同样可以知道None, 0, False, [], (), {}都代表False,那么[] and {}其结果为[],而[] or{}的结果就为{}
在本例中可以看到,n的作用仅限于设定递归次数,当n减到0则直接输出列表,否则进行一次列表运算后进行递归运算,当计算n次之后终止并返回列表
但是这个代码中存在一个问题,等下再说
最后这个只是用于将递归函数中的列表不作为输入,仅作为输出
febo = lambda n: feb(n, [])
事实上也可以把列表作为函数对象的一个属性,而不是参数在递归中调用,不过我觉得这种方式更加直观并且不容易犯错误
最后的执行结果就是可以返回一个数列,而且每个元素都只进行一次计算和设置,结果和上面那个一样,就不贴了
刚才我提到这里面有个问题,就是说如果输入的参数n为0的时候lst为[],就是false,这样导致or后面的代码也被执行了,实际测试中就会引发异常.为了保证能够正确输出值,将feb函数的定义改了一下
feb = lambda n, lst:n > 0 and (febon(lst) or True) and (feb(n-1, lst) or True) or lst
实际就是把条件判断的顺序改了一下,最后返回lst,这样无论是否为False都会被返回了,经过测试当n<=0的时候结果都是[]
好啦,今天先到这里吧,这种函数编程的方式其实可读性并不好,写的时候也容易出错,也许是我理解的有些偏了,不过确实有种黑魔法的感觉,自己玩玩还是很不错的,不知道在实际项目中这么用会怎么样.
Python学习一(面向对象和函数式编程)的更多相关文章
- Python学习笔记二:函数式编程
1:Python中,内置函数名相当于一个变量,指向内置函数.所以可以通过函数名调用相应函数,也可以给函数名赋值,改变它的内容,如:可以把另一个函数变量赋值给它,那它就指向了所赋值的函数了. 2:高级函 ...
- Python学习总结之五 -- 入门函数式编程
函数式编程 最近对Python的学习有些怠慢,最近的学习态度和学习效率确实很不好,目前这种病况正在好转. 今天,我把之前学过的Python中函数式编程简单总结一下,分享给大家,也欢迎并感谢大家提出意见 ...
- python学习第十一天 -- 函数式编程
在介绍函数式编程之前,先介绍几个概念性的东西. 什么是函数式编程? 函数式编程的特点: 1.把计算视为函数而非指令; 2.纯函数式编程:不需要变量,没有副作用,测试简单; 3.支持高阶函数,代码简洁. ...
- Python学习札记(二十) 函数式编程1 介绍 高阶函数介绍
参考: 函数式编程 高阶函数 Note A.函数式编程(Functional Programming)介绍 1.函数是Python内建支持的一种封装,我们通过一层一层的函数调用把复杂任务分解成简单的任 ...
- Python学习札记(二十三) 函数式编程4 sorted
参考:sorted NOTE 1.sorted,快速排序,时间复杂度O(nlogn)渐进最优. #!/usr/bin/env python3 L = [] for i in range(10): L. ...
- Python学习札记(二十一) 函数式编程2 map/reduce
参考:map/reduce Note 1.map():map()函数接收两个参数,一个是函数,一个是Iterable.map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回. ...
- Python学习札记(二十七) 函数式编程8 偏函数
偏函数 NOTE 1.int()函数提供额外的base参数,默认值为10.如果传入base参数,就可以做N进制的转换: #!/usr/bin/env python3 import functools ...
- python学习,day3:函数式编程,递归和高阶函数
# coding=utf-8 # Author: RyAn Bi def calc(n): #递归 print(n) if int(n/2) > 0: #设置条件,否则会循环999 次,报错, ...
- python学习,day3:函数式编程,局部变量和全局变量
# coding=utf-8 # Author: RyAn Bi school = 'THU' #全局变量 def change_name(name): global age #在函数中,用globa ...
随机推荐
- 【OPENGL】第三篇 着色器基础(二)
在这一小节,主要学习GLSL的基本数据类型以及控制结构.GLSL具备了C++和Java的很多特性,我们会先了解所有着色阶段共有的特性,再了解各个着色器的专属特性. 1.着色器的基本结构 一个着色器程序 ...
- 如何写出优雅的CSS代码 ?(转)
对于同样的项目或者是一个网页,尽管最终每个前端开发工程师都可以实现相同的效果,但是他们所写的代码一定是不同的.有的优雅,看起来清晰易懂,代码具有可拓展性,这样的代码有利于团队合作和后期的维护:而有的混 ...
- 转载: 查看HADOOP中一个文件有多少块组成及所在机器ip
看文件信息 hadoop fsck /user/filename 更详细的 hadoop fsck /user/filename -files -blocks -locations -racks ...
- [2014.01.27]wfGifAnimator 动画GIF组件 3.0
组件支持设置GIF帧延时和获取GIF的帧延迟. 组件支持添加或插入或更新帧(支持bmp/jpg/gif/wmf/emf/ico格式).删除帧.清空帧操作. 组件支持GIF动画缩放大小. 组件支持绘制线 ...
- HoloLens外包团队:HoloLens有一个严重缺陷,但微软并不想改
微软的HoloLens自公布以来,几乎获得了一边倒的赞美声.它使用了增强现实(AR)技术,在现实世界中叠加一层虚拟影像,能让人仿佛置身魔法世界.但从最新的Hololens硬件体验上看,它可能有一个致使 ...
- 使用nvm安装node
安装nvm curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash 安装node nvm ...
- ionic 启用sass
转入ionic项目目录,命令行下执行:ionic setup sass 提示编译器未装: You have specified Ionic CI to set up sass.However, you ...
- RAID磁盘阵列笔记
磁盘阵列RAID是服务器维护的必备知识,以前不太关心服务器维护方面的知识.目前要负责维护机房里的几台服务器,所以要关注这方面的内容. 磁盘阵列是用多块独立磁盘组成,提供两个方面的作用:数据安全冗余 和 ...
- 为linux普通用户添加超级用户权限sudo
问题:假设用户名为:ali如果用户名没有超级用户权限,当输入 sudo + 命令 时, 系统提示: ali is not in the sudoers file. This incident wil ...
- Wampserver2.5配置虚拟主机出现403 Forbidden的处理方案
WampServer是一款由法国人开发的Apache Web服务器.PHP解释器以 及MySQL数据库的整合软件包.免去了开发人员将时间花费在繁琐的配置环境过程,从而腾出更多精力去做开发.在windo ...