python怎么返回上一行代码_那些好玩的一行python代码和背后的原理

之前看过很多python一行代码的文章,但对其中原理并不十分了解,相信其他人也有同样问题。这次就来选取一些有趣的一行代码,并深入分析其中的原理~

0. 预备知识

range()函数

range(start, end, step) 生成[start, end)范围内的数,每个数相隔step。start默认为0,step默认为1。注意区间是左闭右开,即包含start,不包含end。

列表推导式

[元素 for i in range(n) if 条件] 列表推导式的结果是一个列表。

for i in range(n)的作用可以理解为生成n次元素,if又对元素进行了限制。

先看个简单的[i for i in range(3)]结果是[0, 1, 2]。一共生成3次元素,第i次生成元素i。所以:第0次生成元素0,第1次生成元素1,第2次生成2。没有if限制,那么所有元素都保留。

再看个稍难的[i*i for i in range(6) if i%2!=0]结果是[1, 9, 25]。if i%2!=0限制了i必须是奇数,那么i只能是1,3,5。表达式是i*i,所以结果就是1,9,25。

lambda表达式

lambda *args:return_value

lambda表达式又称为匿名函数,没错它就是个没有名字的函数。。

*args是参数,可传入任意个数。retuan_value是函数的返回值。

比如算2*x+1,那么需要的参数就是x,返回结果就是2*x+1。

g(3)=7。是不是和数学的表达一样?

filter过滤器

filter(Function, iterable object)

Function是一个函数,iterable object是一个可迭代对象。

filter功能是每次从可迭代对象中取出一个元素,作为Function的参数运算,如果Function的返回值是False,那么该元素就会被丢弃,如果返回值是True,就会被保留。

lambda表达式和filter一起用就很强大了!

看个简单例子filter(lambda x: x %2, range(3))。从range(3)中筛选对2取余为真的数(奇数),结果是1,3。

True和False

在python里面,0,空字符串,空列表,空元组会被认为是False。

or和and

如果某个数能够完全确定表达式的值了,就把这个数返回,作为整个表达式的值。

or表达式左右两边,只要一边为真,表达式就为真。因此在判断中,如果左边为真,直接返回左边,没有必要再判断右边。

比如2 or 3 = 23,因为根据左边的2判断出表达式为真,无论右边是什么都不影响,可以直接返回2。

and表达式左右两边都为真,表达式才为真。因此在判断中,如果左边为假,可以判断表达式为假,直接返回左边,没有必要再判断右边。如果左边为真,就要再判断右边。

比如3 and 2 = 2。左边是3,还需要判断右边,右边是2,所以返回2

分片

对字符串的分片可以理解为截取子字符串。

s[start:end]的结果是s的子字符串,从第start个元素开始,长度为end-start,不包括第end个元素。start默认为0,end默认为s的长度。若start>=end,则长度=end-start<=0,只能返回空字符串。

列表分片的分法也是一样的,只不过返回的是一个列表。

join()

s.join([...])。s和str列表内的元素都是str类型。join函数把s加入到列表相邻两个元素中,组成一个新的字符串。

初学者应该都会学习这些基础的python知识。东西还是挺多的。

1 hello world

print("hello world!")

没错就是hello world!大家可以回想一下学习c和java时候输出一个hello world有多困难?!而用python这一行就搞定。

python里面函数是一等公民,Java里面类是一等公民,它们的设计理念是不一样的。python对比java,就不需要又public又class的,只需要调用内置函数print()就行。

2 求素数

[prime for prime in filter(lambda x: not[i for i in range(2, x) if x%i==0], range(2, 101))]

这么鬼畜一长串能看懂??后面有更长的!

最外层是个表列推导式,保存了求出来的素数,那么看filter是怎么筛选的就行了。

filter里面的range也不用看,只是个范围而已,那么重点只剩下:

lambda x: not[i for i in range(2, x) if x%i==0

假设x是一个素数,那么range(2, x)的范围内x%i 一定是不等于0的。于是一直不满足if的条件,推导式得到一个空列表[]。加个not,not [] = True。

素数->得到空列表[]->not []->True。也就是素数才会满足filter的条件!

filter筛选出来的就是素数。如果lambda里面没有not呢,那么筛选出来的就是非素数。

3 FizzBuzz问题

3的倍数替换成Fizz,5的倍数替换成Buzz,既是3的倍数又是5的倍数替换成FizzBuzz。

["fizz"[i%3*4:]+"buzz"[i%5*4:] or i for i in range(1, 100)]

这是个列表推导式。or i 好懂,如果前面都不为真,那么返回i。

如果i是3的倍数那么i % 3 * 4 = 0,对"Fizz"的切片就是"Fizz"[0:]="Fizz"。否则start的范围会超过"Fizz"的长度4,切片失败,返回''。

对"Buzz"的切片同理。如果i既是3又是5的倍数,就会得到"Fizz"+"Buzz"="FizzBuzz"

4 打印99乘法表

print('\n'.join([' '.join(['%s*%s=%-2s' % (y, x, x*y) for y in range(1, x+1)]) for x in range(1, 10)]))

两个for可理解为两层循环,感觉这个很好懂没什么好过多解释的??

5 打印爱心

print('\n'.join([''.join([('iloveu'[(x-y)%6]if((x*0.05)**2+(y*0.1)**2-1)**3-(x*0.05)**2*(y*0.1)**3<=0 else' ')for x in range(-30,30)])for y in range(15,-15,-1)]))

这是最高能的一个!结果还是很好看的。

下面研究这一行十二分鬼畜的代码究竟是怎么回事。

这一行太长了,我们可以把两个列表提取出来,便于观察。

再把列表推导式写成循环的形式。

逻辑清晰之后,用正常人的思路把功能实现。

对于if里面那一串公式,估计就是心形线的函数了,小于等于0表示该点(x, y)在心形里面,所以从"iloveu"中选字符填充,否则就用' '填充。

至于为什么取下标为(x-y)%6,%6很好理解,因为'iloveu'的长度就是6嘛。(x-y)我原以为是作者故意弄复杂的,用x%6试了结果是这样的:

单以x%6选择下标导致不同行的同一个位置都是一样的字符(和上面的心对比一下)。所以(x-y)是做了一个偏移,视觉效果更好了。

颜色也最好调一调。。这颜色太丑了

6 其他想法

有的一行代码已经违背了python简洁易读的初衷,但其中对于内置函数的妙用和透彻理解是值得学习的。

最后一个打印心形的方法,换一个判断函数就能打印其他形状了。填充的字符也可以改,只要把长度也改成对应的就行。

水平有限,如有错误,欢迎交流和批评指正!转载注明出处即可。

转自公众号「小z的笔记本」

每周更新各种内容

包括但不限于Python、爬虫、其他骚操作

欢迎关注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值