今天遇到一个曾经学 C 语言时的一个问题, 求水仙花数水仙花数是指一个 3 位数,它的每个位上的数字的 3 次幂之和等于它本身
我给出这样一个答案
from functools import reduce
[ i for i in range(100, 1000) if reduce(lambda n1, n2: n1+n2**3,(int(j) for j in str(i)), 0 )==i]
其实这个答案并不简洁, 一点也不 pythonic. 但是涉及到了一些 python 的语法(奇巧淫技?)和知识点列表推导式
列表推导式配合其他的东西
生成器表达式
字符串是个 sequence 类型
lambda 匿名函数
reduce 函数
列表推导式
# 一个0到9的列表
[i for i in range(10)]
简言之, 列表推导式可以从一个可迭代对象得到一个列表.
列表推导式非常顺手, 舒服!!!
首先, 平常我们可以使用上面的例子得到可以迅速的得到一个列表.
好像也没什么用啊, 但是搭配其他的东西, 威力还是很大的
filter
# 得到所有的奇数
[i for i in range(10) if i%2]
过滤, 配合if语句, 完全代替filter函数 当然判断的地方我们可以更复杂, 也可以使用一个函数(那就是 filter 了), 甚至几个函数(比 filter 要强, 不过也没必要, pythonic).
map
# 平方一下
[i*i for i in range(10)]
# 一起使用
[i*i for i in range(10) if i%2]
在 i 的位置, 我们可以做些操作, 简单的平方, 或者执行一个函数foo(i), 这就代替了 map
map?
# 也算是map了
[True if i%2 else False for i in range(10)]
# 当然也可这样
[i**2 if i%2 else False for i in range(10)]
# 配合后面的if(filter)
[True if i%2 else False for i in range(10) if i ]
也算是 map 了, 其实这里用到的式 if/else 的三元表达式
v = a if a>b else b
生成器表达式
生产器表达式, 将[]换成()就可以了, 其他一样, 生成器一般就是三个应用:减少内存占用, 提升性能
函数挂起, 实现异步
无限的生成器?
当然, 这里的生成器没什么用, 没必要
生产器表达式就是这些内容, 但是生成器的其他内容留个坑吧 包括生成器函数
yield from 语句
继续生成器: next send for
...
reduce
一般我们入门 python 的时候, 经常把 map filter reduce 当作高阶函数作为进阶学习
其实现在看也不高, 当然, reduce 应该是三个里最高的吧 hh
它在functools里
# reduce函数
reduce(function, sequence[, initial]) -> value
# 从1加到100
def foo(n1, n2):
return n1+n2
reduce(foo, range(101))
reduce? 减少? 我们看下上面的计算的过程参数 function 必须有两个参数, 必须返回一个值
现在 range(101)相当于 0~100首先把 0,1 给 foo, 计算得一个值 1
把计算获得的值(这里是 1)和下一个值(这里是 2), 分别传给 foo 第一个参数和第二个参数, 再返回一个值, 作为下一次调用 foo 的第一个参数
这样, foo 依次调用的情况是(0, 1)->1, (1, 2)->3, (3, 3)->6, (6, 4)->10, (10, 5)->15, ...
最后得到的是一个结果(并不是说一个值, 应该说是最后一次 foo 调用的结果)
描述 reduce 的作用: 函数会对参数序列中元素进行累积
几乎是废话, 不如思考一下上面的计算过程(foo 被调用的过程和传递的参数)
最后一个可选参数initial是一个初始化值, 就是相当于把这个值放在序列最前面, 如果上面的例子给一个 initial, 那么调用情况就是
(initial, 0)->initial, (initial, 0)->initial, (initial, 1)->initial+1, (initial+1, 2)->initial+3, ...
lambda 匿名函数
对于一个简单的函数, 我们不需要def定义, 甚至这个函数都没有名字, 但是 lambda 函数一般不能写的太复杂, 甚至不能换行(要用\)
一般用在我们需要这样一个简单的函数, 而且还不需要名字(不需要引用, 用一次就不用了), 没错, 典型的就是上面map filter reduce
它们都需要一个函数作为参数(所以这是高阶?)
# 改写上面的例子
# lambda 参数: 表达式
# 表达式的返回值即函数的返回值
reduce(lambda n1, n2: n1+n2, range(101))
# 其实函数也可被赋值
foo = lambda v: v*2
[foo(i) for i in range(10)]
sequence
字符串是序列 sequence 类型, 再 reduce 那里我们可以看到 range 也是 当我们说到这类是...类型时, 就是说这个对象实现了一些魔术方法(应该说实现了该类型的协议), 具有了一些操作
就序列类型来说, 常见的有 list, str, tuple, bytes, range, generator等
实现了__getitem__, 实现整数索引(字典不是用整数, 是映射类型)
__len__, 支持 len, 返回长度(字典也实现了)
__contains__, 支持in关键字
...
挖的坑有点大了, 以后再说
其实坑还可以更大, 比如水仙花数中的int(i)**2为什么要 int 呢, 直接i**2不就行了吗?
你在 JavaScript 里就行, 这就涉及到 python 强类型的特点了.
不说了不说了, 坑估计填不了了
水平有限, 如果有误, 欢迎指正