公众号后台回复“图书“,了解更多号主新书内容
作者:麦叔
来源:麦叔编程
本文挑选了全球第二大同性交友网站StackOverflow上被点赞最多的10个问题,其中总点赞数超过了5万,考虑到很多白嫖党,至少有10万人对这些问题感兴趣!
这么多人点赞,说明两个问题:
这些问题很常用,编程的时候经常碰到
这些问题不简单,否则不用去论坛上文
Yield关键词是做什么的?
ifname== 'main'是做什么的 ?
Python有三元运算符吗?
Python的metaclasses是做什么的?
如果在不出异常的情况下检查文件是否存在?
如何一句话合并两个字典?
Python如何调用外部命令,比如启动QQ?
如何安全的创建一个多层文件夹?
循环中如何访问下标?
staticmethod和classmethod的区别?
这10个问题,有的复杂,有的简单。你会几个呢?可以在评论区留言。
我原本打算讲解10个问题,但由于篇幅原因,本文只涵盖了被问最多的一个问题,后续文章可能会涵盖多个问题。
下面我们重点看第一个问题:
这个问题是所有Python问题的排名第一:
有10000多人对问题点赞,表示有同样疑问。
其中高赞回答有15000多点赞。
有超过2百40万的浏览。
我曾经录制过一个关于Yield关键词的视频,自认为比高赞答案还要更清楚一点,建议视频和答案一起看。
Yield关键词是做什么的?
比如下面的代码:
def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
这是调用的代码:
result, candidates = [], [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
当_get_child_candidates被调用时,发生了什么?返回了一个list吗?还是一个元素?它会被反复调吗?后续调用什么时候停止?
看着有点懵?可以继续往下看解答,然后再回来看问题。
要理解yield,先理解generators,要理解generators先理解iterable(可迭代的)。
当你创建1个list,你可以一个个读取它的值,这叫做迭代:
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
上面mylist是一个iterable(可以被迭代的)。当你使用一个列表推导式,你创建了一个列表,也就是一个iterable:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
所以可以使用for...in...语法遍历的就是iterable:list, str, file等等
这些iterable很有用,你可以循环访问他们。但是它们所有的值都保存在内存中。如果你的list中有10亿个字符串的时候,创建这个list会很慢,而且会很占用内存,所以我们需要Genertor.
Generator是iterable,可以被循环。但和上面不一样,它一般只能被循环一次。它不会把所有的值保存在内存中,他们在循环中动态产生元素的值。
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
这个生成器和列表推导式几乎一样,唯一区别使用小括号(),而不是中括号[]. 但,你不能两次使用for i in mygenerator,因为生成器只能被循环一次:他们计算0x0,返回结果,自己并不保存,下一次调用它,他计算1x1,以此类推。
Yields是一个关键词,可以先理解成和return一样,区别是它返回一个generator.
>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
>>> for i in mygenerator:
... print(i)
0
1
4
上面这个例子先创建了range,已经占用了内存,但平方数没有占用。这个例子不是很好,这是原作者举的,我的视频中应该有更好的例子。
首先,因为yield的存在,当你调用上面的函数,里面的代码并没有执行,而不是返回了一个Generator。
然后是关键的地方:
当for循环第一次调用generator的时候,它会从头开始执行,直到yield关键词,返回第一个值,也就是0。
然后记住执行到哪一行代码,也就是yield的位置。
下次for循环再次调用它,它从yield的下一行继续执行,直到再次碰到yield,返回下一个值,也就是1.
这个过程一直重复,直到generator中没有内容了。例子中就是range里的数字被用完。
这是一个对树的遍历算法,查找树上符合条件的节点。代码中加了详细的中文注释。
Generator:
# 这个函数会返回一个生成器(Generator),这是一个二叉树的node对象中的方法
def _get_child_candidates(self, distance, min_dist, max_dist):
# 如果还有左孩子,并且距离符合条件,返回左孩子,然后暂停在这里
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
# 如果还有右孩子,并且距离符合条件,返回右孩子,然后暂停在这里
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
# 如果执行到了这里,说明没有符合条件的左右孩子了,生成器空了,就迭代结束了。
Caller:
# 创建一个空的列表,和当前对象节点
result, candidates = list(), [self]
# 循环,开始里面只有自己
while candidates:
# 弹出最后一个节点
node = candidates.pop()
# 获得obj对象和目标节点的距离
distance = node._get_dist(obj)
# 如果距离ok,写入到结果列表中
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# 把自己的子节点加入到candidates中,这样循环会继续,直到树上的所有节点都被遍历
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
◆ ◆ ◆ ◆ ◆麟哥新书已经在当当上架了,我写了本书:《拿下Offer-数据分析师求职面试指南》,目前当当正在举行活动,大家可以用相当于原价5折的预购价格购买,还是非常划算的:
数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以扫描下方管理员二维码,进群前一定要关注公众号奥,关注后让管理员帮忙拉进群,期待大家的加入。
管理员二维码:
猜你喜欢
● 卧槽!原来爬取B站弹幕这么简单● 厉害了!麟哥新书登顶京东销量排行榜!● 笑死人不偿命的知乎沙雕问题排行榜
● 用Python扒出B站那些“惊为天人”的阿婆主!● 你相信逛B站也能学编程吗