虽然去不了 Google,走到这步大概也不错了

周五面完了 Google,这一周的疯狂面试终于结束了,不算明天的阿里笔试的话。

上一篇日志里我说,“我知道自己不可能拿到 Offer”。当时的想法是,自己的水平不够,不足以通过 Google 的面试。不过这一周四面下来,虽然发觉题目也并没有那么难,但是却更加确信自己没法拿到 Offer 了。是周边几个同学的遭遇让我坚信这一点。

A 同学是我的本科同学,在班上和年级里都名列前茅,这可是清华电子系哦。更重要的是,他是我们班写代码最厉害的人,后来去了保研去了计算机系。我一直是很佩服他的,以前也经常去请教问题。他也去面了 Google,进了 hc,然后挂了。知道这个消息让我大受打击,突然就明白了传说中 Google 今年在海外缩招这件事是千真万确的。在我看来,如果他去不了 Google,那我是一丁点希望都没有,因为他不论从代码能力还是简历还是成绩(Google 要看成绩)上都完全碾压我。

B 同学是研究生实验室的同学,一看就是很牛的那种。然而他电面就挂了。我问了问电面的题,被吓到了,这题放到笔试里也是绝对的难题,我根本就不会做。实际上我还知道另一个人也是电面被问到这题然后挂了。这是什么情况,说明根本就不想招人嘛。

有一个类比,是我自己想出来的。从大陆去 Google,基本就和从京外考清华北大差不多。不是说 Google 从美国招人的人不行,或者清华北大从北京招的学生就差,而是名额的分配本来就是不均匀的。像 Google 或者清北,他们是不愁招不到好员工和好学生的,也就是说只有他们挑人的份,而没有应征者挑他们的份(当然这不是绝对的,ACM 金牌和各地状元就不存在这个问题)。所以他们在哪里招人少,那里的人就只能忍着,这也是没办法的事。

虽然能进 hc 我已经挺满意的了,但是一想到花了这么多精力最后还是去不了,又觉得时间都白费了
(╥﹏╥)

更新
在 Quora 上看到了一个问题,彻底浇灭了我的念想:

I was rejected by Google's hiring committee despite significant job-related experience, excellent interview feedback, and stellar references. Where do I go from here?

意思是提问者也是进了 hc 然后被 Google 拒了,但是他自己觉得表现很好。Gayle,也就是 cc150 的作者,给了一个回答:

It was almost certainly your interviews.

Going to the hiring doesn't mean much. Only about 10% of candidates presented to hiring committee get an offer.

(Note: this was roughly the statistic for my hiring committee, where almost all candidates were presented to the hiring committee. It varies by hiring committee. In any case, most candidates who reach the hiring committee do not get hired.)

意思是基本上所有人都会进 hiring committee,但是大部分都会被拒。

在评论里她回复了提问者:

Still, I'm fairly certain that it was your interviews. Your perception of your performance has no correlation, in my experience, with how you actually did. Think about it: why do you think you did BETTER (and, in fact, much better) than other candidates on those interview questions?

所以说,Google 并不在乎你的表现如何,在乎的是你的表现必须超出别的应聘者一大截。对我来讲,这是不可能做到的事,至少我没法在中国做到。

去年实验室有四个人拿到 Google 的 Offer,我觉得他们都是神。

最近的几个面试

今年的校招来得格外早。上一级的师兄师姐说十月份才是面试高峰。然而我有一种八月份就要面完的感觉。。。

知乎是我最早去面的一家。四月份向认识的工程师问知乎的招聘流程,说并没有固定的时间点,于是六月份就去面试了。一共有两轮,各种知识都有涉及,然而一问到操作系统我基本就懵了,因为没有怎么看。面试之前我临时又看了一遍之前写的 Tornado 的一些总结,多少还是有点用。第二面要我写一个 class decorator,结果我错把应该在 __init__ 传入的函数放到 __call__ 里传入了。最后问问题,了解到知乎用 Go 写了很多基础架构的东西,还是比较出乎意料的。

面试完之后和 hr 聊得挺开心,她问我怎么才能招到技术牛人,我说你们不是都从豆瓣招么,她说也不能全部从豆瓣招吧。于是我就推荐她去加 CPyUG。她还想从技术博客发掘牛人,我说这种找法比较困难,博客都太分散了。

然后面了美团的云计算部门。之前师兄说美团算法会面很难,比国内其它公司难,要我好好准备。于是面试前一周我一直疯狂看算法+刷题。搞笑的是,面了三轮技术面,就考了一道算法题,还是反转链表。竟然也并没有考设计题。基!本!都!在!问!项!目!我简历上的每个项目至少讲了两遍。当然也问了网络和操作系统。问得挺深,于是就又一堆不会,比如 fork 之后发生了什么,socket 是怎么创建的(((゚Д゚;)))。有意思的是一个面试官居然纠正了我在《还在疑惑并发和并行》一文中的观点,他用“指令集并行”的例子反驳了并行是属于并发的说法,并且指出“并发”是逻辑上的,“并行”是物理上的,两者并没有包含关系。我之前都不知道指令集并行这件事。还有就是问问题环节,一个面试官提到了“程序员如何面对重复性的日常工作的态度”,确实是一个值得思考的问题。

过了几天阿里的一个工程师给我打电话说要电面。我内推的部门是蚂蚁金服,然后面试官告诉我,蚂蚁金服全部在杭州,如果你不想来杭州,我们也就没必要面了。WHAT THE FUCK??于是就没有面。现在内推时间已过,我感觉被阿里坑了_(:3」∠)_

今天昨天上午是 Google 的电话面试。为了方便美国面试官,所有中国的 candidate 都不得不在早上七点参加面试。不知道是因为紧张还是怕睡过,我一晚上都没睡好,一点半,两点半,三点半各醒了一次,后来还醒了一次但没看是几点。于是六点半起床随便吃了个面包就开始面试了。面试官直接从美国一个越洋电话打过来,是个中国人。题说实话不难,但是描述得非常含糊,第一题我 clarify 了五分钟,第二题 clarify 了超过十分钟。7:20 的时候我还在就第二题到底是什么意思反复和面试官讨论,这可是限定在 45 分钟内完成的面试啊!我急了,面试官也急了。我能感觉到她非常不理解我为什么不能理解题意,但是我 TM 就是不能理解啊!没办法了,我说,我给这样的一个输入,你能不能告诉我应该输出什么?最后终于终于通过举一个例子弄清了题意,我发现我之前想得太复杂了。做完这个又加了一问,结果这一问是我之前以为第二问要求的东西。。。

没想到很快就接到电话说电面过了,只能说十分幸运,当时一直没弄清题意的时候真的以为要挂了。

其实能进现场面就已经达到我的目标了,因为我知道自己不可能拿到 Offer。为什么呢,因为面得太早。一个去了 Google 的师兄叮嘱我,“一定要 10、11 月再面试,8、9 月好多大牛都挂了。拿到 Offer 的基本都是 10、11 月面的。”但是今年 Google 听说是缩招了,要求内推的人必须 8 月份面试完。听到这个消息的时候,我就直接把目标设定成了去感受下现场面试的气氛,因为挂了才是正常的。

理解 Python super

今天在知乎回答了一个问题,居然一个赞都没有,也是神奇,毕竟这算是我非常认真答的题之一。既然如此就贴过来好了,有些内容之后再补充。

原问题

Python中既然可以直接通过父类名调用父类方法为什么还会存在super函数?
比如
class Child(Parent):
    def __init(self):
    Parent.__init
(self)
这种方式与super(Child, self).init()有区别么?

回答
针对你的问题,答案是可以,并没有区别。但是这题下的回答我感觉都不够好。

要谈论 super,首先我们应该无视 "super" 这个名字带给我们的干扰。

不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!
不要一说到 super 就想到父类!super 指的是 MRO 中的下一个类!

一说到 super 就想到父类这是初学者很容易犯的一个错误,也是我当年犯的错误。 忘记了这件事之后,再去看这篇文章:Python’s super() considered super! 这是 Raymond Hettinger 写的一篇文章,也是全世界公认的对 super 讲解最透彻的一篇文章,凡是讨论 super 都一定会提到它(当然还有一篇 Python's Super Considered Harmful)。

如果不想看长篇大论就去看这个答案super 其实干的是这件事:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

两个参数 cls 和 inst 分别做了两件事:
1. inst 负责生成 MRO 的 list
2. 通过 cls 定位当前 MRO 中的 index, 并返回 mro[index + 1]
这两件事才是 super 的实质,一定要记住!
MRO 全称 Method Resolution Order,它代表了类继承的顺序。后面详细说。

举个例子

class Root(object):
    def __init__(self):
        print("this is Root")

class B(Root):
    def __init__(self):
        print("enter B")
        # print(self)  # this will print <__main__.D object at 0x...>
        super(B, self).__init__()
        print("leave B")

class C(Root):
    def __init__(self):
        print("enter C")
        super(C, self).__init__()
        print("leave C")

class D(B, C):
    pass

d = D()
print(d.__class__.__mro__)

输出

enter B
enter C
this is Root
leave C
leave B
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

知道了 super 和父类其实没有实质关联之后,我们就不难理解为什么 enter B 下一句是 enter C 而不是 this is Root(如果认为 super 代表“调用父类的方法”,会想当然的认为下一句应该是this is Root)。流程如下,在 B 的 __init__ 函数中:

super(B, self).__init__()

首先,我们获取 self.__class__.__mro__,注意这里的 self 是 D 的 instance 而不是 B 的

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Root'>, <type 'object'>)

然后,通过 B 来定位 MRO 中的 index,并找到下一个。显然 B 的下一个是 C。于是,我们调用 C 的 __init__,打出 enter C。

顺便说一句为什么 B 的 __init__ 会被调用:因为 D 没有定义 __init__,所以会在 MRO 中找下一个类,去查看它有没有定义 __init__,也就是去调用 B 的 __init__

其实这一切逻辑还是很清晰的,关键是理解 super 到底做了什么。

于是,MRO 中类的顺序到底是怎么排的呢?Python’s super() considered super!中已经有很好的解释,我翻译一下:
在 MRO 中,基类永远出现在派生类后面,如果有多个基类,基类的相对顺序保持不变。
关于 MRO 的官方文档参见:The Python 2.3 Method Resolution Order,有一些关于 MRO 顺序的理论上的解释。

最后的最后,提醒大家. 什么 super 啊,MRO 啊,都是针对 new-style class。如果不是 new-style class,就老老实实用父类的类名去调用函数吧。


top