python之函数总结

1.尽量用异常来表示特殊情况,而不要返回 None

用 None 这个返回值来表示特殊意义的函数,很容易使调用者犯错,因为 None 和 0 以及空字符串之类的值,在表达式里都会评估为 False。

函数在遇到特殊情况时,应该抛出异常,而不要返回 None 。调用者在看到该函数的文档中所描述的异常之后,应该就会编写相应的代码来处理它们了。

def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError as e:
        raise ValueError('Invalid inputs') from e  # 抛出异常

x, y = 5, 2
try:
    result = divide(x, y)
except ValueError:
    print('Invalid inputs')
else:
    print('Result is %.lf' % result)

 

2.了解如何在闭包里使用外围作用域中的变量

闭包相关介绍

我们可以将闭包理解为一种特殊的函数,这种函数由两个函数的嵌套组成,且称之为外函数和内函数,外函数返回值是内函数的引用,此时就构成了闭包。

def 外层函数(参数):
    def 内层函数():
        print("内层函数执行", 参数)

    return 内层函数


内层函数的引用 = 外层函数("传入参数")
内层函数的引用()

参考:https://blog.csdn.net/weixin_44141532/article/details/87116038

1)python比较两个元组:首先比较各元组中下标为0(第一个)的对应元素,如果相等,再比较下标为1的对应元素...列表比较也类似。

2)在表达式中引用变量时,Python解释器将按如下顺序遍历各作用域,以解析该引用:

  1. 当前函数的作用域。
  2. 任何外围作用域(如:包含当前函数的其他函数)。
  3. 包含当前代码的那个模块的作用域(即全局作用域,global scope)。
  4. 内置作用域(即包含 len str 函数的那个作用域)。

如果上面这些地方都没有定义过与名称相符的变量,就抛出 NameError 异常。

获取闭包内的数据 —— nonlocal语句

nonlocal 变量名

变量名

nonlocal:在闭包内给变量赋值,会在上层作用域中查找该变量,在闭包内修改的其实是闭包外那个作用域的变量。nonlocal的唯一限制在于,它不能延申到模块级别。除了那种简单的函数,尽量不要用 nonlocal 语句,应该将相关状态封装成辅助类,也可以利用上面的变量搜寻规则,将变量改为列表类型: 变量名[0] = ?(字典,集合,某个类的实例也类似)。

global:用来表示对该变量的赋值操作,将会直接修改模块作用域里那个变量。

 

3. 考虑用生成器来改写直接返回列表的函数

生成器(generator)是使用 yield 表达式的函数调用生成函数时,它并不会真正的运行,而是会返回迭代器。每次在这个迭代器上面调用内置的 next 函数时,迭代器会把生成器推进到下一个 yield 表达式那里。生成器传给yield的每一个值,都会由迭代器返回给调用者。

例,查出字符串中每个词的首字母在整个字符串里的位置。

def index_file(handle):
    offset = 0
    # 从文件里依次读入各行内容
    for line in handle:
        if line:
            yield offset
        # 逐行处理每个单词
        for letter in line:
            offset += 1  # 指向letter后一个地址
            if letter == ' ':
                yield offest 
with open('filepath', 'r') as f:
    it = index_file(f)
    results = islice(it, 0 , 3)  # 迭代前三个
    print(list(result))

islice(iterable, [start, ] stop [, step]):
创建一个迭代器: iterable[start : stop : step],跳过前start个项,迭代在stop所指定的位置停止,step指定用于跳过项的步幅。迭代认将从0开始,步幅认1。

注意:迭代器只能使用一轮次。

办法:1)将迭代器复制一份列表;2)通过参数来接受另外一个函数;3)新编一种实现迭代器协议的容器类(python容器

 

4.用数量可变的位置参数减少视觉杂讯

*arg: 适用于能够确定输入的参数个数比较少时,需要把很多变量或变量名一起传给某个函数的场合。

 

5.用关键字参数来表达可选的行为

  关键字参数:1)明确参数的含义; 2)在函数定义时提供认值; 3)提供一种扩充函数参数的有效方式,使得扩充之后的函数依然能够与原有的那些调用代码相兼容。

注意:可选的关键字参数,总是应该以关键字形式来指定,而不是以位置参数的形式来指定。

 

6.用 None 和文档字符串来描述具有动态认值的参数

例子:

def log(message, when=datetime.Now()):
    print('%s: %s' % (when, message))

log('Hi there!')
sleep(0.1)
log('Hi again!')

两条消息的时间戳是一样的,这是因为 datetime.Now() 只执行了一次,也就是它只在函数定义的时候执行了一次。参数的认值,会在每个模块加载进来的时候求出,而很多模块都是在程序启动时加载的。包括这段代码的模块一旦加载进来,参数的认值就固定不变了,程序不会再次执行 datetime.Now()。

应该把认值设为 None,并在文档字符串里面把 None 所对应的实际行为描述出来。

def log(message, when=None):
    """记录时间。
    
    Args:
        message:打印的消息。
        when:时间为 when 打印消息message,认为 present time。
    """
    when = datetime.Now() if when is None else when
    print('%s: %s' % (when, message))

7.用只能以关键字形式指定的参数来确保代码清晰

以下函数参数列表里的 * 号,标志着位置参数就此终结,之后的那些参数,都只能以关键字形式来指定。

def safe_division_c(number, divisor, *, ignore_overflow=False, ignore_zero_division=False):
    # ...

这样就不能用位置参数的形式来指定关键字参数了,关键字参数不指定会采取认值。对于接受多个布尔标志的函数,更应该这样做。

相关文章

功能概要:(目前已实现功能)公共展示部分:1.网站首页展示...
大体上把Python中的数据类型分为如下几类: Number(数字) ...
开发之前第一步,就是构造整个的项目结构。这就好比作一幅画...
源码编译方式安装Apache首先下载Apache源码压缩包,地址为ht...
前面说完了此项目的创建及数据模型设计的过程。如果未看过,...
python中常用的写爬虫的库有urllib2、requests,对于大多数比...