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 ...
随机推荐
- java标准-密码用数组比用字符串安全
转载:http://my.oschina.net/jasonultimate/blog/166968 1) Since Strings are immutable in Java if you sto ...
- 利用web工具splinter模拟登陆做自动签到
首先,我需要的工具和组件有: Chrome浏览器 浏览器驱动ChromeDriver Python 3.5 Web应用测试工具Splinter 代码部分: from splinter import B ...
- HotSpotOverview.pdf
从oracle官网下载的这个HotSpot虚拟机的概况文档,现在翻一下锁的部分: Java 锁 *每一个java对象都是一个潜在的monitor(监视器) >synchronized 关键字 * ...
- [Spring MVC] - JSON
Spring MVC中使用JSON,先必需引用两个包:jackson-core-asl-1.9.13.jar.jackson-mapper-asl-1.9.13.jar 因为需要使用到jquery测试 ...
- winform基本控件的使用2(用户登录界面的设计)
首先还是通过例子来讲解,这次的实验主要是使用messageBox的使用方法,关于messageBox的使用方法在我的博客里面有相关的转载,请自己查看,下面说一下实验要求. 功能要求:模拟一个用户登陆的 ...
- cPage分页源码,分享给大家,可作参考
cPage是asp.net分页控件,也可以叫做分页组件,更确切的应该叫做分页模块,也或者叫做分页通用代码. cPage,版本3.2,源码如下: using System; namespace cPag ...
- Adaptive Decontamination of the Training Set: A Unified Formulation for Discriminative Visual Tracking
Martin Danelljan 判决类追踪模型是由训练样本学习得到,但是为了适应目标和背景的变化sample set在每一帧中都会更新. 令(xjk, yjk)表示第k帧k={1,2,...,t}中 ...
- 使用 Linq 对多个对象进行join操作 C#
class A { public int id { get; set; } public string name { get; set; } } class B { public int id { g ...
- jQuery源码:从原理到实战
jQuery源码:从原理到实战 jQuery选择器对象 $(".my-class"); document.querySelectorAll*".my-class" ...
- OAF_开发系列27_实现OAF中Java类型并发程式开发调用XML Publisher(案例)
20150814 Created By BaoXinjian