Dive Into Python 学习记录3-getattr 介绍/过滤列表/and or/lambda 函数

来源:互联网 发布:网络管理专业 编辑:程序博客网 时间:2024/06/10 05:20

3.1getattr 介绍

>>> li = ["Larry", "Curly"]>>> li.pop                       1<built-in method pop of list object at 010DF884>>>> getattr(li, "pop")           2<built-in method pop of list object at 010DF884>>>> getattr(li, 'pop')(3)'why'>>> li['hard', 'difficult', 'complex']                   #也可以用 >>> getattr(li, "append")("Moe") 3>>> li["Larry", "Curly", "Moe"]>>> getattr({}, "clear")         4<built-in method clear of dictionary object at 00F113D4>>>> getattr((), "pop")           5Traceback (innermost last):  File "<interactive input>", line 1, in ?AttributeError: 'tuple' object has no attribute 'pop'
1该语句获取列表的 pop 方法的引用。注意该语句并不是调用pop 方法;调用pop 方法的应该是 li.pop()。这里指的是方法对象本身。2该语句也是返回 pop 方法的引用,但是此时,方法名称是作为一个字符串参数传递给getattr 函数的。getattr 是一个有用到令人无法致信的内置函数,可以返回任何对象的任何属性。在这个例子中,对象是一个 list,属性是pop 方法。3如果不确信它是多么的有用,试试这个:getattr 的返回值 方法,然后你就可以调用它,就像直接使用li.append("Moe") 一样。但是实际上你没有直接调用函数;只是以字符串形式指定了函数名称。4getattr 也可以作用于字典。5理论上,getattr 可以作用于元组,但是由于元组没有方法,所以不管你指定什么属性名称getattr 都会引发一个异常。

3.2 过滤列表

[mapping-expression for element in source-list if filter-expression]

这是你所知所爱的列表解析的扩展。前三部分都是相同的;最后一部分,以if 开头的是过滤器表达式。过滤器表达式可以是返回值为真或者假的任何表达式 (在Python 中是几乎任何东西)。任何经过滤器表达式演算值为真的元素都可以包含在映射中。其它的元素都将忽略,它们不会进入映射表达式,更不会包含在输出列表中。

>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]>>> [elem for elem in li if len(elem) > 1]       1['mpilgrim', 'foo']>>> [elem for elem in li if elem != "b"]         2['a', 'mpilgrim', 'foo', 'c', 'd', 'd']>>> [elem for elem in li if li.count(elem) == 1] 3['a', 'mpilgrim', 'foo', 'c']
1这里的映射表达式很简单 (只是返回每个元素的值),所以请把注意力集中到过滤器表达式上。由于 Python 会遍历整个列表,它将对每个元素执行过滤器表达式。如果过滤器表达式演算值为真,该元素就会被映射,同时映射表达式的结果将包含在返回的列表中。这里,你过滤掉了所有单字符的字符串,留下了一个由长字符串构成的列表。2这里你过滤掉了一个特定值 b。注意这个过滤器会过滤掉所有的b,因为每次取出b,过滤表达式都将为假。3count 是一个列表方法,返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素,返回一个只包含了在原始列表中有着唯一值拷贝的列表。但并非如此,因为在原始列表中出现两次的值 (在本例中,bd) 被完全剔除了。从一个列表中排除重复值有多种方法,但过滤并不是其中的一种。

Python 中,andor 执行布尔逻辑演算,如你所期待的一样。但是它们并不返回布尔值,而是返回它们实际值;


3.3 and  or

例 4.15. and 介绍

>>> 'a' and 'b'         1'b'>>> '' and 'b'          2''>>> 'a' and 'b' and 'c' 3'c'
1使用 and 时,在布尔环境中从左到右演算表达式的值。0''[](){}None 在布尔环境中为假;其它任何东西都为真。还好,几乎是所有东西。默认情况下,布尔环境中的类实例为真,但是你可以在类中定义特定的方法使得类实例的演算值为假。你将会在第 5 章中了解到类和这些特殊方法。如果布尔环境中的所有值都为真,那么 and 返回最后一个值。在这个例子中,and 演算'a' 的值为真,然后是'b' 的演算值为真,最终返回 'b'2如果布尔环境中的某个值为假,则 and 返回第一个假值。在这个例子中,'' 是第一个假值。3所有值都为真,所以 and 返回最后一个真值,'c'

例 4.16. or 介绍

>>> 'a' or 'b'          1'a'>>> '' or 'b'           2'b'>>> '' or [] or {}      3{}>>> def sidefx():...     print "in sidefx()"...     return 1>>> 'a' or sidefx()     4'a'>>> '' or 'b' or 'd''b'
1使用 or 时,在布尔环境中从左到右演算值,就像 and 一样。如果有一个值为真,or 立刻返回该值。本例中,'a' 是第一个真值。2or 演算 '' 的值为假,然后演算 'b' 的值为真,于是返回 'b'3如果所有的值都为假,or 返回最后一个假值。or 演算'' 的值为假,然后演算[] 的值为假,依次演算 {} 的值为假,最终返回 {}4注意 or 在布尔环境中会一直进行表达式演算直到找到第一个真值,然后就会忽略剩余的比较值。如果某些值具有副作用,这种特性就非常重要了。在这里,函数sidefx 永远都不会被调用,因为or 演算 'a' 的值为真,所以紧接着就立刻返回 'a' 了。

如果你是一名 C 语言黑客,肯定很熟悉bool ?a :b 表达式,如果 bool 为真,表达式演算值为a,否则为 b。基于Pythonandor 的工作方式,你可以完成相同的事情。

>>> a = "">>> b = "second">>> (1 and [a] or [b])[0] 1''
1由于 [a] 是一个非空列表,所以它决不会为假即使a0 或者'' 或者其它假值,列表[a] 也为真,因为它有一个元素

到现在为止,这个技巧可能看上去问题超过了它的价值。毕竟,使用 if 语句可以完成相同的事情,那为什么要经历这些麻烦事呢?哦,在很多情况下,你要在两个常量值中进行选择,由于你知道a 的值总是为真,所以你可以使用这种较为简单的语法而且不用担心。对于使用更为复杂的安全形式,依然有很好的理由要求这样做。例如,在Python 语言的某些情况下if 语句是不允许使用的,比如在lambda 函数中。


3.4 使用 lambda 函数

>>> s = "this   is\na\ttest"  1>>> print sthis   isatest>>> print s.split()           2['this', 'is', 'a', 'test']>>> print " ".join(s.split()) 3'this is a test'
1这是一个多行字符串,通过使用转义字符的定义代替了三重引号。\n 是一个回车,\t 是一个制表符。2不带参数的 split 按照空白进行分割。所以三个空格、一个回车和一个制表符都是一样的。3通过 split 分割字符串你可以将空格统一化;然后再以单个空格作为分隔符用 join 将其重新连接起来。这也就是info 函数将多行doc string 合并成单行所做的事情

那么 info 函数到底用这些 lambda 函数、split 函数和and-or 技巧做了些什么呢?

    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

processFunc 现在是一个函数,但是它到底是哪一个函数还要取决于 collapse 变量。如果 collapse 为真,processFunc(string) 将压缩空白;否则processFunc(string) 将返回未改变的参数。

在一个不很健壮的语言中实现它,像 Visual Basic,你很有可能要创建一个函数,接受一个字符串参数和一个collapse 参数,并使用if 语句确定是否压缩空白,然后再返回相应的值。这种方式是低效的,因为函数可能需要处理每一种可能的情况。每次你调用它,它将不得不在给出你所想要的东西之前,判断是否要压缩空白。在Python 中,你可以将决策逻辑拿到函数外面,而定义一个裁减过的lambda 函数提供确切的 (唯一的) 你想要的。这种方式更为高效、更为优雅,而且很少引起那些令人讨厌 (哦,想到那些参数就头昏) 的错误

3.5 ljust 方法介绍

>>> s = 'buildConnectionString'

>>> s.ljust(30) 1

'buildConnectionString '

>>> s.ljust(20) 2

'buildConnectionString'

1ljust 用空格填充字符串以符合指定的长度。info 函数使用它生成了两列输出并将所有在第二列的doc string 纵向对齐。2如果指定的长度小于字符串的长度,ljust 将简单地返回未变化的字符串。它决不会截断字符串。





原创粉丝点击