Loading

Python一些小技巧

Python一些小技巧

python上手简单,但有很多“语法糖”或者说很细微但对编程很有用的细节,下面整理如下:

P.S. 本书内容来自《写给程序员的Python教程》

What is 语法糖

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

善用help()模块

help(函数名)可以让我们取得该函数的基本用途,是一个很重要的模块工具。

在编写时要写好docstrings

def function1():
    """一句话描述
    
    Args:
    	参数名:参数解释
    Returns:
    	返回值
    Raises:
    	可能返回的错误
    """

之所以要编写好docstrings,在调用help(函数名)时会一起显示出来

注意文件编码

可以利用字符串的decodeencode来进行编码

现有一字符串str_o

str_o = str_o.encode('utf-8')
str_o = str_o.decode('gbk')

这样的操作可以解决大量编码问题

模块化编程

在导入一个模块时,如果模块中的某些语句没有封装成函数,那么就会被在导入的同时执行,有解决方案如下:

将函数封装

def function_name():
    pass

将主函数加以限制,这时只有当该模块为主函数(运行的入口函数)时,代码才会被运行

if __name__ == '__main__':
    pass

默认参数值

def function2(a, b=2):
    print(a)
    print(b)

如果是默认参数,那要放在a后面

异常

基本语法

try:
    pass
except 错误类型:
    pass

其中错误类型既可以是一个,又可以是一个可迭代对象

raise
raise ValueError()

无参数的raise会简单地重抛当前正在处理的异常

或者是直接抛出一个异常对象

demo:

import sys
import math
def sqrt_new(x):
    if x < 0:
        raise ValueError("Canot compute negative ")
    return math.sqrt(x)
def main():
    try:
        print(sqrt_new(9))
        print(sqrt_new(-1))
    except ValueError as e:
        print(e, file=sys.stderr)

main()

这种方法只是用来说明raise的用法,并不是真正使用

真正使用的原则是先等程序犯错误,然后才进行相应的应对处理

finally的使用

try:
    ...
except:
    ...
finally:
    ...

有时,无论成不成功,都要最后“回复现场”,此时finally就显得很重要

迭代器和生成器

对于一个可迭代对象,可以通过初始化迭代器来访问

iterable = ['Spring', 'Summer', 'Autumn', 'Winter']
iterator = iter(iterable)

此时

next(iterator)
# Spring
next(iterator)
# Summer
next(iterator)
# Autumn
next(iterator)
# Winter
next(iterator)
# StopIteration Error

每一次调用next(),都会出现列表中的一项,在最后会出现如下的错误

生成器是一类特殊的迭代器,其重点是yield关键词,遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行(第一次是从头开始运行)。

例子:如下是一个生成斐波那契数列的生成器的例子

def range2(m, n):
    i = m
    while i < n:
        yield i
        i = i + 1   

上面就是重写了一下range函数

>>> def fibonacci(n): # 生成器函数 - 斐波那契
...     a, b, counter = 0, 1, 0
...     while True:
...         if (counter > n):
...             return
...         yield a
...         a, b = b, a + b
...         counter += 1
...
>>>
>>> f = fibonacci(10)
>>> next(f)
0
>>> next(f)
1
>>> next(f)
1
>>> next(f)
2
>>> next(f)
3
>>> next(f)
5
>>> next(f)
8
>>> next(f)
13
>>> next(f)
21
>>> next(f)
34
>>> next(f)
55
>>> next(f)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

为什么要用迭代器?

  1. 低内存消耗
sum(x*x for x in range(1, 10000001))

所需的时间,所用的内存都要远小于用列表进行同样的操作

个人感受:

只有访问时才计算出所需的值,大量减少了"闲置时间"

any和all

用于可迭代的布尔函数

any相当与把序列中的元素全部并,all为全部交

any([False ,False, True])
#True
all([False, False, True])
# False

对文件的读写

f = open('test.txt', mode = 'a', encoding='utf-8')

open函数有三个重要的参数

部分读取文件的技巧

f.readline()

可以读取一行,在文件太大时可以利用这个来

f.readlines()

生成一个由行组成的列表

with open(...) as f:
    ...

这是一个必要的文件,在你不确定时用with可以避免错误,实际上的with函数十分复杂,需要大量的同类代码块才能替代,所以说用with是必要的。

利用Python库进行单元测试

unitest由三个主要部分组成:

测试用例

将一组相关的测试方法组合在一起

固件

装配:确保在测试运行之前测试环境处于预期状态

拆卸:在测试运行后清理环境,通常是释放资源

断言

测试方法内部的特定检查

demo:

如果要测试一个analyze函数,可以这样编写代码

# text_analyzer.py

import unittest

class TextAnalysisTests(unittest.TestCase):
    
    def test_function_runs(self):
        analyze()
    
    
if __name__ == '__main__':
    unittest.main()

得到这样的结果

E
======================================================================
ERROR: test_function_runs (__main__.TextAnalysisTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\笑云博文\Desktop\fff.py", line 6, in test_function_runs
    analyze()
NameError: name 'analyze' is not defined

----------------------------------------------------------------------
Ran 1 test in 0.006s

FAILED (errors=1)

若加上定义,则变成

.
----------------------------------------------------------------------
Ran 1 test in 0.008s

OK

固件相当于文件的试验品,但这些试验样例在测试结束后就没用了,这时要使用setUp和tearDown来进行

断言

断言包含判断结果正确性的断言和判断错误正确性的断言,注意下面的代码

import unittest
import os

class TextAnalysisTests(unittest.TestCase):

    
    def test_function_runs(self):    # 这里是检测是否能正常运行
        analyze(self.filename)

    def test_content(self):    # 这里是检查内容是否一致
        self.assertEqual(analyze(self.filename), 'lalal')

    def test_error(self):
        with self.assertRaises(IOError):   #注意这里with代码的用法
            analyze('ddd')
    
    def setUp(self):
        self.filename = 'eee.txt'
        with open(self.filename, 'w') as f:
            f.write('lalala')

    def tearDown(self):
        try:
            os.remove(self.filename)
        except OSERROR:
            pass
        
def analyze(filename):
    string_test = ''
    with open(filename, 'r') as f:
        string_test = f.readline()
    return string_test
        

if __name__ == '__main__':
    unittest.main()

结果如下所示:

F..
======================================================================
FAIL: test_content (__main__.TextAnalysisTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\笑云博文\Desktop\fff.py", line 11, in test_content
    self.assertEqual(analyze(self.filename), 'lalal')
AssertionError: 'lalala' != 'lalal'
- lalala
?      -
+ lalal


----------------------------------------------------------------------
Ran 3 tests in 0.012s

FAILED (failures=1)

这是常用的驱动脚本

posted @ 2021-06-01 15:02  笑云博文  阅读(96)  评论(0)    收藏  举报