美文网首页
python-12 小技巧

python-12 小技巧

作者: 巴巴11 | 来源:发表于2020-04-13 22:50 被阅读0次

    条件表达式

    if x > 0:
        y = math.log(x)
    else:
        y = float('nan')
    
    y = math.log(x) if x > 0 else float('nan')
    
    def factorial(n):
        if n == 0:
            return 1
        else:
            return n * factorial(n-1)
    def factorial(n):
        return 1 if n == 0 else n * factorial(n-1)
    
    
    条件表达式的另一个用处是处理可选参数。
    def __init__(self, name, contents=None):
        self.name = name
        if contents == None:
            contents = []
        self.pouch_contents = contents
    我们可以像这样重写:
    def __init__(self, name, contents=None):
        self.name = name
        self.pouch_contents = [] if contents == None else contents
    

    列表推导式

    def capitalize_all(t):
        res = []
        for s in t:
            res.append(s.capitalize())
        return res
    
    def capitalize_all(t):
        return [s.capitalize() for s in t]
    
    方括号操作符表示,我们正在构造一个新列表。方括号中的表达式指定列表中的元素,for 子句表示我们要遍历的序列。
    
    列表推导式的语法有点奇怪,因为此例中的循环变量 s 在定义之前就出现了。
    
    列表推导式也可以用于筛选。例如,这个函数只选择 t 中为大写的元素,并返回一个新列表:
    
    def only_upper(t):
        res = []
        for s in t:
            if s.isupper():
                res.append(s)
        return res
    我们可以使用列表推导式重写这个函数:
    
    def only_upper(t):
        return [s for s in t if s.isupper()]
    列表推导式非常简洁、易读,至少对简单的表达式是这样的。而且通常比对应的 for 循环要更快,有时要快很多。
    
    列表推导式的调试难度更大,因为你不能在循环中添加打印语句。建议只在计算足够简单、第一次就能写出正确代码的前提下使用。
    

    生成器表达式

    生成器表达式与列表推导式类似,但是使用的是圆括号,而不是方括号:
    
    >>> g = (x**2 for x in range(5))
    >>> g
    <generator object <genexpr> at 0x7f4c45a786c0>
    结果是一个表达式对象,该对象知道如何遍历一个值序列。但与列举推导式不同的是,它不会一次性计算出所有的值;而是等待求值请求。内建函数 next 从生成器获取下一个值:
    
    >>> next(g)
    0
    >>> next(g)
    1
    抵达序列的末尾时,next 会抛出 StopIteration 异常。你还可以使用 for 循环遍历这些值:
    
    >>> for val in g:
    ...     print(val)
    4
    9
    16
    生成器对象会记录其在序列中的位置,因此 for 循环是从 next 结束的地方开始的。一旦生成器被消耗完,它会抛出 StopException 。
    
    >>> next(g)
    StopIteration
    生成器表达式常与 sum 、max 和 min 等函数一起使用:
    
    >>> sum(x**2 for x in range(5))
    30
    

    any 和 all

    Python提供了一个内建函数 `any`,它接受一个布尔值序列,如果其中有任意一个值为 `True` 则返回 `True` 。它也适用于列表:
    >>> any([False, False, True])
    True
    
    
    但是它通常用于生成器表达式:
    >>> any(letter == 't' for letter in 'monty')
    True
    
    
    上面这个例子不是很有用,因为它的功能和 in 操作符一样。
    可以像这样编写 `avoids` 函数:
    def avoids(word, forbidden):
        return not any(letter in forbidden for letter in word)
    
    
    上面的函数读取来和英语没什么区别:“word avoids forbidden if there are not any forbidden letters in word.”(如果某个词中没有任何禁用字母,那么该词就算避免了使用禁用词。)
    
    将 `any` 与生成器表达式结合使用的效率较高,因为它只要一遇到真值就会终止,所以不会对整个序列进行计算。
    
    Python还提供了另一个内建函数 `all`,如果序列中的每个元素均为 `True` 才会返回 `True` 。
    
    

    集合

    
    
    uses_only 函数:
    def uses_only(word, available):
        for letter in word:
            if letter not in available:
                return False
        return True
    uses_only 检查 word 中的所有字符也在 available 中。我们可以像这样重写该函数:
    def uses_only(word, available):
        return set(word) <= set(available)
    操作符 <= 检查某个集合是否是另一个集合的子集或本身,包括了二者相等的可能性。如果 word 中所有的字符都出现在 available 中,则返回 True 。
    

    计数器

    计数器(Counter)类似集合,区别在于如果某个元素出现次数超过一次,计数器就会记录其出现次数。
    
    计数器定义在叫做 collections 的标准模块中,因此你必须首先导入该模块。你可以通过字符串、列表或任何支持迭代的数据结构来初始化计数器:
    
    >>> from collections import Counter
    >>> count = Counter('parrot')
    >>> count
    Counter({'r': 2, 't': 1, 'o': 1, 'p': 1, 'a': 1})
    计数器的行为与字典有很多相似的地方:它们将每个键映射至其出现的次数。与字典一样,键必须是可哈希的。
    
    与字典不同的是,如果你访问一个没有出现过的元素,计数器不会抛出异常,而只是返回 0 :
    
    >>> count['d']
    0
    
    如果两个单词是变位词,那么它们会包含相同的字符,而且字符的计数也相同,因此它们的计数器也是等价的。
    
    计数器提供了执行类似集合操作的方法和操作符,包括集合添加、差集、并集和交集。另外,还提供了一个通常非常有用的方法 most_common ,返回一个由值-频率对组成的列表,按照频率高低排序:
    
    >>> count = Counter('parrot')
    >>> for val, freq in count.most_common(3):
    ...     print(val, freq)
    r 2
    p 1
    a 1
    
    

    defaultdict

    collections 模块中还提供了一个 defaultdict ,它类似字典,但是如果你访问一个不存在的键,它会临时生成一个新值。
    
    在创建 defaultdict 时,你提供一个用于创建新值的函数。这个用于创建对象的函数有时也被称为 工厂 。用于创建列表、集合和其他类型的内建函数也可以用作工厂:
    
    >>> from collections import defaultdict
    >>> d = defaultdict(list)
    请注意,这里的实参是 list ,它是一个类对象,而不是 list() ,后者是一个新列表。你提供的函数只有在访问不存在的键时,才会被调用。
    
    >>> t = d['new key']
    >>> t
    []
    新列表 t 也被添加至字典中。因此如果我们修改 t ,改动也会出现在 d 中。
    
    >>> t.append('new value')
    >>> d
    defaultdict(<class 'list'>, {'new key': ['new value']})
    如果你要创建一个列表组成的字典,通常你可以使用 defaultdict 来简化代码。
    

    命名元组

    当你像下面这样定义类时,你通常先开始定义 init 和 str 方法:
    
    class Point:
    
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
    
        def __str__(self):
            return '(%g, %g)' % (self.x, self.y)
    但是编写了这么多代码,却只传递了很少的信息。Python提供了一个更简洁的实现方式:
    
    from collections import namedtuple
    Point = namedtuple('Point', ['x', 'y'])
    第一个实参是你希望创建的类的名称。第二个实参是 Point 对象应该具备的属性列表,以字符串的形式指定。 namedtuple 的返回值是一个类对象:
    
    >>> Point
    <class '__main__.Point'>
    这里的 Point 自动提供了像 __init__ 和 __str__ 这样的方法,你没有必须再自己编写。
    
    如果想创建一个 Point 对象,你可以将 Point 类当作函数使用:
    
    >>> p = Point(1, 2)
    >>> p
    Point(x=1, y=2)
    init 方法将实参赋值给你提供的属性。str 方法打印 Point 对象的字符串呈现及其属性。
    
    你可以通过名称访问命令元组的元素:
    
    >>> p.x, p.y
    (1, 2)
    但是你也可以把命名元组当作元组使用:
    
    >>> p[0], p[1]
    (1, 2)
    
    >>> x, y = p
    >>> x, y
    (1, 2)
    命名元组是定义简单类的一种便捷方式。缺点是这些简单类不会一成不变。之后你可能会发现想要给命名元组添加更多的方法。在这种情况下,你可以定义一个继承自命名元组的新类:
    
    class Pointier(Point):
        # add more methods here
    或者使用传统的类定义方式。
    

    汇集关键字实参

    在可变长度参数元组中,我们学习了如何编写一个将实参汇集到元组的函数:
    def printall(*args):
        print(args)
    
    你可以使用任意数量的位置实参(即不带关键字的参数)调用该函数:
    >>> printall(1, 2.0, '3')
    (1, 2.0, '3')
    
    不过 `*` 星号操作符无法汇集关键字参数:
    >>> printall(1, 2.0, third='3')
    TypeError: printall() got an unexpected keyword argument 'third'
    
    如果要汇集关键字参数,你可以使用 `**` 双星号操作符:
    >def printall(*args, **kwargs):
        print(args, kwargs)
    
    可以给关键字汇集形参取任意的名称,但是 `kwargs` 是常用名。上面函数的结果是一个将关键字映射至值的字典:
    >>> printall(1, 2.0, third='3')
    (1, 2.0) {'third': '3'}
    
    如果你有一个有关键字和值组成的字典,可以使用分散操作符(scatter operator) `**` 调用函数:
    >>> d = dict(x=1, y=2)
    >>> Point(**d)
    Point(x=1, y=2)
    
    如果没有分散操作符,函数会将 `d` 视为一个位置实参,因此会将 `d` 赋值给 `x` 并报错,因为没有给 `y` 赋值:
    >>> d = dict(x=1, y=2)
    >>> Point(d)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: __new__() missing 1 required positional argument: 'y'
    
    在处理有大量形参的函数时,通常可以创建指定了常用选项的字典,并将其传入函数。
    

    相关文章

      网友评论

          本文标题:python-12 小技巧

          本文链接:https://www.haomeiwen.com/subject/rpwomhtx.html