python之函数总结

目录

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

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

2.1闭包相关介绍

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

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

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

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

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

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


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

用 None 这个返回值来表示特殊意义的函数,很容易使调用者犯错,因为 None0 以及空字符串之类的值,在表达式里都会评估为 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.了解如何在闭包里使用外围作用域中的变量

2.1闭包相关介绍

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

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 异常。

2.2获取闭包内的数据 —— 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):
    # ...

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

 

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值