PEP8(三),表达式

567 阅读3分钟

The Zen Of Python中说:“在我们完成某件相似事情时,最好只使用一种显而易见的方式。”(There should be one—and preferably only one—obvious way to do it.)

PEP8在表达式的使用中践行这一原则。

1、行内否定

# 推荐用法
if a is not b:
    pass

# 不推荐用法
if not a is b:
    pass

笔者其实没有太懂为什么推荐用法是这样的,不太懂的原因很简单:这两条语句表达的内容一致。

不懂就自己思考,笔者想到的答案是:if a is not b,读起来更顺口,在语感上会更好些,好读则意味着可读性高。

笔者再去谷歌搜索答案,看到一个相似讨论,其中高赞回答和笔者的观点一致:使用a is not b更符合我们平日里的语境表述。

相似讨论:

stackoverflow.com/questions/4…

2、判断容器是否为空

对于容器类数据结构,不用使用长度来判断它们是否为空,要使用if not A或者if A,在if A的判定当中,如果容器非空结果为True,容器为空则为False。

Effective Python有一个不太好的地方是,它只是告诉我要怎么做,而并不告诉我为什么要这样做?为什么要这样做呢?

笔者找寻答案过程中,有一个额外发现,已经先整理为此篇博客:《if A和if A is not None的区别》。

话归正题,为什么PEP8推荐使用if seq而不是使用if len(seq) == 0呢?

笔者找到两个讨论帖子:

pylint的检测:

stackoverflow.com/questions/4…

为什么更推荐使用if?

stackoverflow.com/questions/3…

由这两个帖子得出的结论是这样的:使用if A判定某个容器是否为空相较使用len(A) == 0会更健壮,当A不为容器(是否包含__len__函数)时,使用len可能会报错。

结合笔者博客《if Aif A is not None的区别》中得出的结论,其实if A内里的判定已经包含了len(A) == 0,那么此处使用if A代替if len(A) == 0则会是更Pythonic的写法。

搞清楚此处背后逻辑之后,笔者未来的代码中,会遵守这一条规则。

3、单行语句

此条直接使用代码进行说明(if、for和while均如是):

# 不推荐用法
if A: print(A)

# 推荐用法
if A:
    print(A)

未接触pep8之前,笔者很喜欢将短的if写在一行,特别是某个函数需要有很多条件限制时,这会使得我的函数显得短小精悍。

def func():
    if condA: return
    if condB: return
    if condC: return

    doWork()

关于此条,笔者有简单搜一下,社区内的讨论并不太多,说明这是一条不太重要的原则。

笔者此处的建议依然是:先遵守项目组内的规范,如果未定义规范,就遵守PEP8规则吧。(当然,如果自己一个人一个项目,请写出前后一致的风格。)

4、一行语句很长时,用括号包起来

笔者此处依然直接使用代码说明,示例代码来源于此目录:github.com/python/cpyt…

# Lib/http/server.py

    def send_head(self):
        #...

        try:
            fs = os.fstat(f.fileno())
            # Use browser cache if possible
            # 可以看到此处if语句写在一行内太长,于是用括号包起来
            if ("If-Modified-Since" in self.headers
                    and "If-None-Match" not in self.headers):
                # compare If-Modified-Since and time of last file modification
                try:
                    # 同理,函数参数
                    ims = email.utils.parsedate_to_datetime(
                        self.headers["If-Modified-Since"])
                except (TypeError, IndexError, OverflowError, ValueError):
                    # ignore ill-formed values
                    pass
# Lib/http/cookiejar.py
NETSCAPE_MAGIC_RGX = re.compile("#( Netscape)? HTTP Cookie File")
# 此处有对很长文本的处理
MISSING_FILENAME_TEXT = ("a filename was not supplied (nor was the CookieJar "
                         "instance initialised with one)")

另外,作者并不建议在行末添加\符号进行续行操作。

本篇博客只到此处,下一篇,我将跟着书中内容理一理关于import的两三事。