在知乎上看到的问题——python有哪些优雅的代码实现。

下面的代码大概也算不上优雅。

一下代码在python3中实现

更多内容可见:http://book.pythontips.com/en/latest/args_and_kwargs.html

lambda函数的使用

lambda,又称匿名函数。当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

比如命名一个普通的函数:

def f(x):
return x * x

在这里,f为函数名,x是函数的参数,x*x则是函数的返回结果。

我们可以换成lambda的形式则是:

>>> lambda x : x*x
<function <lambda> at 0x7fa2d1298048>
>>> f = lambda x : x*x
>>> f(3)
9

lambda函数有一个限制就是函数中只能有一个表达式(事例中的x*x),该表达式的结果即是返回值。当然这个表达式可以用下面的一些技巧写的更“优雅”一些。

其中lambda函数返回是一个对象,其实在python中,绝大部分的都是对象,函数也是对象。所以我们能将lambda函数赋给其它对象(事例中的f)。但是不建议这么做。一般使用lambda表达式时要注意:

1.逻辑简单,切忌在一个lambda表达式中做出很复杂的逻辑,这么做可能感觉逼格很高但是代码的可读性会变得非常差。

2.一次性使用,就像上面所说的不建议使用f = lambda  x:....的形式

map,reduce,filter函数的使用

map()函数接收两个参数,一个是函数,一个是Iterablemap将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:

>>> def f(x):
... return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

其中注意,传进map()的第一个参数是 f 而不是f(),其中f表示的是f函数对象本身而f()则是对函数f的调用。

map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']

当然,map()中还可以传入lambda表达式:

>>> list(map(lambda x: x*x,range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

或者再结合一下:

>>> list(map(lambda x: str(x*x),range(10)))
['0', '1', '4', '9', '16', '25', '36', '49', '64', '81']

再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用reduce实现:

>>> from functools import reduce
>>> reduce(lambda x,y:x+y,[1,2,3,4])
10

Python内建的filter()函数用于过滤序列。

map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如返回一个list中的奇数:

>>> list(filter(lambda x:x % 2 == 1,range(10)))
[1, 3, 5, 7, 9]

列表推导

列表推导,又称列表生成式,即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

举个例子,要生成list [0,1, 2, 3, 4, 5, 6, 7, 8, 9]可以用list(range(10))

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

在python2中有点区别,python2中的range()直接生产列表而python3中生产的是一个range对象,需要通过list或者[]来生成。

>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

或者进阶一点点:

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [str(x) for x in range(10)]
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

感觉它的写法有点想lambda表达式。

然后其中也可以多几层的嵌套:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

三层和三层以上的循环就很少用到了。

yield和generator生成器

简单地讲,yield 的作用就是把一个函数变成一个 generator。

例如使用yield生成裴波那契数列:

 def fab(max):
n, a, b = 0, 0, 1
while n < max:
yield b
# print b
a, b = b, a + b
n = n + 1
 >>> for n in fab(5):
... print n
...
1
1
2
3
5

使用yield的好处在于,它返回的是一个generator生成器。类似于python3中的range()和python2中的xrange()。带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

因为返回的是一个生成器,所以可以使用next()方法进行访问:

>>> f = fab(5)
>>> next(f)
1
>>> next(f)
1
>>> next(f)
2
>>> next(f)
3
>>> next(f)
5

generator生成器,前面我们看了列表推导,使用[]进行生成,其中把[]换成(),就创建了一个generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x7fd2264607d8>

L是一个list,而g是一个generator。其中generator是可迭代的。

装饰器

装饰器(Decorator),当我们希望为函数增加功能,但是却不想修改原函数又或者没有权限修改原函数的时候,就需要用到装饰器了。

比如我们有一个函数:

def func():
print("I have a dream!")
func() I have a dream!

是的,我有一个梦想!现在我们想要知道我什么时候有一个梦想,就是我们需要在执行函数的时候打印时间。那么:

'''定义一个装饰器'''
def log_time(func):
def wrapper(*args, **kw):
print("run %s() and time is :" % func.__name__+str(datetime.datetime.now()))
return func(*args,**kw)
return wrapper @log_time
def func():
print("I have a dream!") func()

输出:

run func() and time is :2016-10-10 14:26:08.296495
I have a dream!

本质上,decorator就是一个返回函数的高阶函数。其中,我们给log_tim()传入一个参数,这个参数是一个函数对象,并且返回一个函数对象。然后在其中定义了wrapper(),这两个参数并没有意义,只是为了说明这里面可以传入任意类型的参数。

然后用@语法将其放在函数定义处。其相当于:

func = log_time(func)

由于log_time()是一个decorator,返回一个函数,所以,原来的func()函数仍然存在,只是现在同名的func变量指向了新的函数,于是调用func()将执行新函数,即在log_time()函数中返回的wrapper()函数。

在使用装饰器时请注意:

用decorator修饰一个函数得到另一个函数时,原来的那个函数依然是逻辑中心,而decorator所增加的只是相对外围的功能,不能那个什么宾那个什么主。

即使去掉装饰器,整个函数的逻辑仍需完整、清晰。

欢迎多来访问博客:http://liqiongyu.com/blog

微信公众号:

优雅的python的更多相关文章

  1. 优雅的python 写排序算法

    arr=[] while True: #输入数据 当输入q结束 a=raw_input() if a=="q": break arr.append(int(a)) s=len(ar ...

  2. 代码这样写更优雅(Python 版)(转载)

    转载:https://mp.weixin.qq.com/s?timestamp=1498528588&src=3&ver=1&signature=DfFeOFPXy44ObCM ...

  3. 如何写出优雅的Python代码?

    有时候你会看到很Cool的Python代码,你惊讶于它的简洁,它的优雅,你不由自主地赞叹:竟然还能这样写.其实,这些优雅的代码都要归功于Python的特性,只要你能掌握这些Pythonic的技巧,你一 ...

  4. 如何写出优雅的Python之设置class缺省值

    今天有个需求时需要为某个类设置缺省值 最开始的代码如下: Class myClass def __init__(self,datalen=None,times=None): if datalen == ...

  5. 编写高效且优雅的 Python 代码

    http://python.jobbole.com/86808/ http://python.jobbole.com/86869/?utm_source=blog.jobbole.com&ut ...

  6. 微信公众平台开发(免费云BAE+高效优雅的Python+网站开放的API)

    虽然校园App是个我认为的绝对的好主意,但最近有个也不错的营销+开发的模式出现:微信平台+固定域名服务器. 微信公众平台的运行模式不外两个: 一.机器人模式或称转发模式,将说话内容转发到服务器上完成, ...

  7. python笔记7:优雅的python

    7. 如何让python代码更 Pythonic : 1.变量交换: a, b = b, a 2.带有索引位置的集合遍历: colors = ['red', 'green', 'blue', 'yel ...

  8. #华为云·寻找黑马程序员# 如何实现一个优雅的Python的Json序列化库

    在Python的世界里,将一个对象以json格式进行序列化或反序列化一直是一个问题.Python标准库里面提供了json序列化的工具,我们可以简单的用json.dumps来将一个对象序列化.但是这种序 ...

  9. 简洁优雅的Python教你如何在工作中“偷懒”

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: A字头 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

随机推荐

  1. Analysis about different methods for reading and writing file in Java language

    referee:Java Programming Tutorial Advanced Input & Output (I/O) JDK 1.4+ introduced the so-calle ...

  2. SQL Server 数据类型陷阱

    1. bit 类型:bit(1) 不要以为它只占一个位,事实上它要占一个字节!也就是说当n < 8 时都是这样的! 2. varchar(n)  这里的n不能大于8000,如果想要比8000大你 ...

  3. kafka初探

    http://www.infoq.com/cn/articles/kafka-analysis-part-1

  4. Vim 实用技术,第 1 部分: 实用技巧(转)

    原文链接:http://blog.jobbole.com/20604/ 0. Vim 简介 作为开源世界最重要的编辑器之一(另一个是 Emacs),Vim 以其强大的功能和可定制能力被众多开发者所喜爱 ...

  5. php mvc 框架演示

    <pre name="code" class="cpp"><pre name="code" class="pyt ...

  6. 害人的VS2008,manifest导致“应用程序配置不正确,应用程序未能启动”

    在VC++2008的项目中,如何显示地指定要使用的C++库的版本? 开发环境:VS2008 SP1 + Win2003 SP2         因为我的VS2008安装了SP1补丁,所以有了9.0.3 ...

  7. linux下安装python3.3.4

    下载安装包 # wget http://www.python.org/ftp/python/3.3.4/Python-3.3.4.tgz 解压 # tar -xzvf Python-3.3.4.tgz ...

  8. 嵌入式系统 Boot Loader

    基于嵌入式系统中的 OS 启动加载程序 ―― Boot Loader 的概念.软件设计的主要任务以及结构框架等内容.

  9. 获取多个div,点击第几个,显示第几个

    1.闭包:函数内部又定义了一个函数,内部函数引用外部函数的变量,就构成了闭包. <script type="text/javascript"> var divs = d ...

  10. cocos2dx中Action汇总

    本文由qinning199原创, 转载请注明:http://www.cocos2dx.net/?p=119 今天总结一下cocos2dx中的一些Action动作,其中To表示到达某个点,而By表示偏移 ...