IMAP 是通信协议,和 HTTP 是一个性质,但 IMAP 不是储存格式。
Email 的流行存储格式可能是 mbox(服务器较少用), Maildir(较常见), 也可能是任意的邮件服务器所自定义的格式 (比如存进 SQL 数据库什么的). 具体要看你所使用的邮件服务器了。按照 LZ 目前提供的信息... 还无法判断。
RVM 还是挺友好的:http://ruby-china.org/wiki/rvm-guide 其中 curl
开头的那一行可以考虑换成 rvm 官网的:curl -L https://get.rvm.io | bash -s stable --rails
真的不是手写输入把 6 月写成了 8 月么 - -
如果这个 head 确实不需要 merge 回去,搜了一下发现这个:http://stackoverflow.com/questions/3688263/mercurial-beheading-a-head 但愿有用。
注:我自己以前稍微用过一阵子 hg, 但已经很久不用了所以很生疏。但愿我对 head 的理解没错。
Object
这个对象是 Class
的实例,而 Class 的超类 (Class.ancestors
) 中包含 Object
类。
顺便,我觉得还是得稍微说明下:把前面 #17 楼 的代码换成 Python 的大致等价物:
class Foo(object):
def bar(self):
return 'bar'
接下来 Foo.bar
返回的不是函数,是未绑定的方法 Foo.bar(1)
并不会返回 'bar'
, 而是会抛异常。
Foo().bar
返回的也不是函数,是已绑定的方法。
所以我所理解的 Python 在"函数是一等公民"这个特性上更优秀的地方,仅在于函数/绑定方法/未绑定的方法的调用方式是与常规的方法调用的语法完全相同的,都是后面直接加一对括号。而 Ruby 更加地以对象为中心,就得用 func.call()
或 func.()
.
#23 楼 @iBachue 无法否认,这种情形下 Python 的写法打字更少。
但是在现实的充分 OO 的代码中,使用协作者对象,要比使用从协作者对象身上"取下来"的已绑定的方法直观得多。更不要说取未绑定的方法,然后再伺机把未绑定方法所属的类的实例传进去调用 (你看用文字描述就这么费劲,更不要说后来人阅读代码时会有多大的认知障碍了).
如果你确实面对着需要频繁使用方法对象的场景,那么我无可辩驳。对我来说,目前能迅速回想起来的,Ruby 的方案对我而言更优越的用例有这么两个:
Getter API 演变。
比如说我们有个 UserPresenter 类 (在 fat model 的风格下很可能会是 User 类), 需要提供 avatar 属性返回头像 URL. 习惯上会觉得"啊既然是返回个 URL 字符串那么就用属性 getter 好了". 接下来需求变更,avatar 可能会有需要多个不同的大小。之前所需的尺寸只是最常用的而已。对 Ruby 而言这个状况很容易解决:把 avatar 方法实现成多接受一个参数来制定尺寸即可。而反观 Python, 假如把属性 getter 换成方法,旧的代码都要逐个改掉。如果不换,就没法制定尺寸参数。这个问题在我现在面对的 codebase 里就真实地存在着。
Stub
写隔离测试时,stub 是个常用的解除依赖的手段。Python 对象想要做 stub, 就要考虑"这个要 stub 的东西的获取方式是属性还是方法?". 而且在面对这种情况时:
class Foo(object):
@property
def bar(self):
return 'bar'
def test_foo(monkeypatch):
foo = Foo()
monkeypatch.setattr(foo, 'bar', 'bar')
assert foo.bar == 'bar'
在 monkeypatch.setattr(foo, 'bar', 'bar')
处会抛异常。虽说这种情形 stub 的方法也不是彻底没有,我正在用这个库. 但瞄了一眼具体实现,发现背后全是黑魔法。项目也不再维护了。用着多少有点担心。以及,这个库在 stub 时,所使用的预设返回值不能是 Mock 的实例。全是令人头疼的因素。而这些问题在 Ruby 的设计中根本不存在。
以及可能还有更多例子,但一时也想不起来了。就写这么两个吧。
不过,我依然无法下结论说 Python 和 Ruby 谁的方案更"好". 我只能说对于我个人的编程习惯和面对的问题领域而言,Ruby 的设计更适合我而已。
EDIT: 忘了说,前面 Python 代码示例中的 monkeypatch 是来自 py.test 测试框架的一个自带的插件 (在 pytest 的术语中属于 fixture 插件): http://pytest.org/latest/monkeypatch.html
看了 LZ 的编辑,那么我单就技术问题说说吧。做了一年左右的"职业" Python web 开发,觉得 LZ 提出的问题所考察的知识还是很重要的。如果这些知识还要在用的时候临时去查,多少有点对不起简历上的"有 Python 使用经验".
一个例外是第 15 题,我个人目前还没有心情去扣流行的 web 开发框架底层的代码,因为现在的工作用的是个不怎么流行的...... 以及,流行的框架经由社区的打磨,一般也足够稳定,没出什么故障的话我反正很少去扣。话说回来,如果这方面的知识和 LZ 招的职位需求很契合 (比如需要为框架开发插件/自行 patch), 那么问问无妨。
以及,我觉得还可以补充一下模块系统 (虽然不难) 和 new style class 的方法解析顺序什么的。这些在我看来也属于必须掌握,随时脑内取用,最好不要临时去查的知识。虽说工作时总归是有条件去查文档,但解决稍微复杂一些的问题 -- 尤其是 debug 别人的代码 -- 时,如果这些知识不能像蝙蝠侠腰带上的工具一样熟悉,估计是会有些吃力的。
话又说回来,既然 LZ 对这种答题的形式也反感,完全可以换一种形式来考察这些知识点。比如这篇文章的作者采用的方法是:制造一个相对真实的简单问题,让面试者现场解决。问题本身要能覆盖若干面试官所关心的知识点 (可能覆盖不全,但可以再引导面试者重构,覆盖更多知识点的同时也考察重构能力), 也能观察得到面试者的工作方式。这样的形式估计就好很多。
果然自己的代码写得有点冗余~ .to_i 本身就已经转换成整数了,再 .round 没有意义。只调用 .to_i 的话就可以像 #7 楼 那样利用 &to_i 的语法了。
其实看了 #2 楼 的描述,我依然不能确定 lz 的原始需求是什么。如果能确定输入数据肯定都是干净的浮点数(只是暂时存成字符串),那么按 .to_i 的结果分组应该肯定是够用的。以及,如果数据是稀疏的,比如缺少 1.x 的输入,那么在输出的数组里原本属于 1.x 的位置上应该是 nil, 还是空数组,都只能看具体需求。
#12 楼 @alsotang 既然你用了正则,那么我也引用一下自己学习正则的知识。这本书教会我的一个重要理念是:先熟悉你手头的数据,正则写得足够好即可,十分严谨的、面面俱到的 parser 用一个巨大的正则来做非常的痛苦。像 LZ 这个问题,如果已知数据都是存成了字符串的浮点数,确定有“浮点数”这个语义在的话,用 .to_i 我觉得非常合适。但如果真如 #2 楼 所言,每个元素只是“中间恰好有一个 .
的字符串”,那么用正则确实更合适。在背景信息完整之前,我觉得没法断言哪个方案更正确。我们写代码都是想解决问题,而不是为了让自己的答案反映出自己学会了课本上的知识点。
依然,如果原始需求不明,数据来源不确定,output = [ a[0..2], a[3..4], ... ]
这个答案我觉得也未必不可。但是在社区里扔下这么一个答案就跑给人太 trolling 的感觉,所以我没敢这么做。
能描述一下需求么?只看这个输入输出的话,我觉得可以这样
a = ["0.0", "0.1", "0.2", "1.2", "1.3", "2.2", "2.3", "3.2", "4.0", "4.2"]
output = [
a[0..2],
a[3..4],
a[5..6],
a[7..7],
a[8..9],
]
假如需求是"按照每个元素的整数位分组", 那么可以这样
a = ["0.0", "0.1", "0.2", "1.2", "1.3", "2.2", "2.3", "3.2", "4.0", "4.2"]
grouped = a.group_by {|n| n.to_i.round}
output = grouped.values_at(*grouped.keys.sort) # => 应该就是你需要的.
不过话说回来,直接拿 grouped
这个 hash 去用可能更方便?而且,假如说输入的数据中没有 1.x 的数,那么这个方法的输出可能会有问题。总之还是希望 LZ 完整严密地描述一下需求。否则我觉得还是前一个办法更好
#24 楼 @vincent #10 楼 @zj0713001
Ruby 2.0.0 的 zlib 已经不会占 GVL 了:https://github.com/ruby/ruby/blob/v2_0_0_0/NEWS#L512-L513
不妨给 ruby-build 开个 issue 吧~
#28 楼 @bhuztez 说到 OpenStruct,Python 也是可以自己山寨一个的:
class OS(object):
# __eq__, __setitem__ 什么的也都可以实现得了。
def __init__(self, **attrs):
self.__dict__.update(attrs)
恼人的是这么好用的东西竟然在 Python 标准库里就是没有。如果写二者的标准库的话我还可以至少再写一篇,FileUtils, OpenStruct, rake, Minitest, URI, Forwardable, Pathname, YAML 等等,以及 Core 里面的 Time 和 Struct,在 Python 那边要么干脆没有对应物,要么有但易用性完败。但想想绝大多数情况下开发者可以装第三方的包,只对比标准库的意义不那么大了。而且库的演进要容易得多,语言设计留下缺陷就是长期硬伤。
#30 楼 @bhuztez 发现 object
的直接子类的 __bases__
不让改 - - 搜了一手发现有这么个问题:http://bugs.python.org/issue672115 如果自己额外定义个用来替代 object
的基类似乎可以做到,但这么搞又麻烦了 oTL
#TIL
#27 楼 @bhuztez 啊没错,直接用已绑定的方法(bound method)也是一个制造 callable 属性的办法。但这又要求方法定义在当前对象的方法解析顺序中能找得到。如果方法定义在别处,恐怕又会受限。
依然,虽然理论上可以做到,但因为种种实现门槛/细微的不舒适的存在,在现实世界的代码里就难得一见。比如我在生产环境还见过 Python 中实现 Ruby 的“重新打开一个类去添加 mixin”。具体的实现是:用 mixin 与旧类创建新的类,然后去修改旧类所在模块的作用域,把新类塞进去。结果代码稍显肮脏,更糟糕的是会因为旧类在 mixin 之前被别处 import 拿到引用(虽然利用了 Python 的 package 中 __init__.py
优先执行的逻辑但还是出了问题,诡异得很,至今原因不明),而导致新旧两个类并存使用。导致我现在的想法就是“有时间一定把那玩意重构掉”。当然实际上也一直没那个时间......
#23 楼 @bhuztez Yes and no. Python 虽然可以用“callable 属性”来模拟按实例多态 (per-instance polymorphism),但这个 callable 并不像常规的方法那样可以拿到 self
作为第一个参数。虽然我们还可以用实现了 __call__
的类,或者闭包,以及动用 partial
模块等方式来让这个方法访问实例,但是有这样的实现门槛摆在面前,开发者往往习惯上就不会积极地去使用了。至少我很少见到。当然我个人阅历也实在有限。
唔现在看来觉得确实应该把这一段加入到文章里去。并且也指出这种做法在 Python 社区并不多见。反观 Ruby 因为 eigenclass 的存在,统一地解决了类方法和按实例多态的问题,还提供了 extend
方法来简化使用。
Python 的 import
更显式,而且每个模块有自己的作用域,可以不受外界干扰(EDIT: 按照下文所述,还是可能会受干扰,只是不到万不得已不会这么做)。而 Ruby 的模块系统借鉴自 Perl,所有文件共享一个作用域,相当于大家一起堆砌全局变量(虽然有良好的命名空间支持)。这样看来 Python +1.
但是现实世界中,拿 Python 的模块标识符当作全局唯一标识,藉此访问/修改全局状态的用例也越发地多了起来。比如 [Mock] 模块的 patch
方法,就依赖这种访问方式,甚至随着调用方的 import
方式不同,patch 的使用还要多加小心。我还看到有生产环境的代码:模块本身提供了类似于 Rails 中的一组 model 对象,然后这个模块提供一个 init
函数来允许用户传入数据库和 memcache 的客户端,而这个配置逻辑也是依赖了模块标识符的全局性的。这样看来,Python 的模块系统反而是在制造不必要的复杂度。Ruby +1。
所以既然有这样的争议,我就没有去写。只写了 Ruby 比较有把握完胜的 :)
假设你是用 ruby-build 编译的 Ruby,可以参考它的 wiki 来看看你遇到的问题是否有解决方案:https://github.com/sstephenson/ruby-build/wiki
不知道 vim 行不行~
vim * '+argdo setl fenc=utf-8' '+wall' '+qall'