Python 的函数和装饰器
0

1. 函数返回值

函数没有return ...语句或return语句为空,则默认返回None
可以有多个返回值return a, b, c,其实是返回多个值组成的一个元组。

def func1():
    pass
def func2():
    return
def func3():
    return 1, 2, 3
print(func1())
print(func2())
print(func3())

输出结果为:

None
None
(1, 2, 3)

2. 函数参数

位置参数
按照位置顺序传参。

默认参数
有默认值的参数,其必须放在必选参数的后边;
参数默认值必须为不可变对象!!!坑子如下:

def func(lst = []):
  lst.append('xyz')
  return lst
lst1 = [1, 2, 3]
print(func(lst1)) # 符合预期
print(func(lst1)) # 符合预期
print(func()) # 貌似符合预期
print(func()) # what the fuck?
print(func()) # fuckkkkk!

输出结果为:

[1, 2, 3, 'xyz']
[1, 2, 3, 'xyz', 'xyz']
['xyz']
['xyz', 'xyz']
['xyz', 'xyz', 'xyz']

原因:默认参数lst的值在函数定义的时候就被计算出来了,即[],由于lst是可变的,每次调用如果改变了它的内容,则在下次调用时,其内容就不是函数定义时的[]了,而是上一次调用时被改变为的内容。
解决办法:

def func(lst = None):
  if lst == None:
    lst = []
    lst.append('xyz')
  return lst
print(func()) # 貌似符合预期
print(func()) # what the fuck?
print(func()) # fuckkkkk!

输出结果为:

['xyz']
['xyz']
['xyz']

可变参数
允许传入任意多个参数,在函数内部将多个参数组装为一个元组。

def func(a, b, *args):
  print(a, b, args)
func(11, 22, 33, 44)

输出结果为:

11 22 (33, 44)

关键字参数
允许传入任意多个包含参数名的参数,在函数内部将多个包含参数名的参数组装为一个字典。

def func(a, b, *args, **keyargs):
  print(a, b, args, keyargs)
func(11, 22, 33, 44, arg1=55, arg2=66)

输出结果为:

11 22 (33, 44) {'arg1': 55, 'arg2': 66}

命名关键字参数
限制关键字参数的名字,同时可以提供默认值。

def func(a, b, *, k1, k2, **keyargs):
  print(a, b, k1, k2, keyargs)
func(11, 22, k1=333, k2=444, arg1=55, arg2=66)

输出结果为:

11 22 333 444 {'arg1': 55, 'arg2': 66}

各种类型参数的组合使用
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数、关键字参数。

3. 作用域

在Python中,当引用一个变量的时候,对这个变量的搜索是按找本地作用域(Local)、嵌套作用域(Enclosing function locals)、全局作用域(Global)、内置作用域(builtins模块)的顺序进行的。 然而当在一个函数内部为一个变量赋值(而不是在一个表达式中对其进行引用)时,并不是按照上面所说的规则来首先找到变量,之后为该变量赋值,而是创建或改变本地作用域的变量名,除非它已经在那个函数中被声明为global<全局变量> 或 nonlocal<外层(非全局)变量>。

a = "I am global a"
b = "I am global b"
c = "I am global c"
d = "I am global d"
e = "I am global e"
f = "I am global f"
def func1():
    print("f1 ---- ", a) # f1 ----  I am global a
def func2():
    b = "I am local b"
    print("f2 ---- ", b) # f2 ----  I am local b
def func3():
    global c
    c = "I am local c"
    print("f3 ---- ", c) # f3 ----  I am local c
def func4():
    d = "I am nonlocal d"
    def infunc4():
        d = "I am local d"
        print("inf4 ---- ", d) # inf4 ----  I am local d
    infunc4()
    print("f4 ---- ", d) # f4 ----  I am nonlocal d
def func5():
    e = "I am nonlocal e"
    def infunc5():
        nonlocal e
        e = "I am local e"
        print("inf5 ---- ", e) # inf5 ----  I am local e
    infunc5()
    print("f5 ---- ", e) # f5 ----  I am local e
def func6():
    f = "I am nonlocal f"
    def infunc6():
        global f
        f = "I am local f"
        print("inf6 ---- ", f) # inf6 ----  I am local f
    infunc6()
    print("f6 ---- ", f) # f6 ----  I am nonlocal f
func1()
print("g1 ---- ", a) # g1 ----  I am global a
func2()
print("g2 ---- ", b) # g2 ----  I am global b
func3()
print("g3 ---- ", c) # g3 ----  I am local c
func4()
print("g4 ---- ", d) # g4 ----  I am global d
func5()
print("g5 ---- ", e) # g5 ----  I am global e
func6()
print("g6 ---- ", f) # g6 ----  I am local f

4. 高阶函数

一个函数可以接收另一个函数作为参数;
内建的高阶函数:map()reduce()filter()sorted() 等。

lst = [("aaa", 3), ("bb", 2), ("c", 1)]
print(sorted(lst))
print(sorted(lst, key=lambda x:x[0]))
print(sorted(lst, key=lambda x:x[1]))
print(sorted(lst, key=lambda x:x[1], reverse=True))

输出结果为:

[('aaa', 3), ('bb', 2), ('c', 1)]
[('aaa', 3), ('bb', 2), ('c', 1)]
[('c', 1), ('bb', 2), ('aaa', 3)]
[('aaa', 3), ('bb', 2), ('c', 1)]

5. 闭包

一个函数内部可以定义另一个函数;
函数的返回值可以是一个函数;
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

6. 匿名函数

lambda x: x * x,关键字lambda表示匿名函数,冒号前为函数参数,冒号后为一个表达式,这个表达式的值即为函数的返回值。

7. 装饰器 decorator

概念
装饰器就是一个返回函数的高阶函数,用于在不改变函数定义的情况下增强函数功能。

def log(f):
  def wrapper(*args, **kwargs):
    print('call function', f.__name__)
    return f(*args, **kwargs)
  return wrapper
@log
def func1():
  print('I an func1.')
func1()

输出结果为:

call function func1
I an func1.

在函数func1前加上@log就相当于执行了 func1 = log(func1)
带参数的装饰器

def log(text):
    def decorator(f):
        def wrapper(*args, **kwargs):
            print(text + 'call function', f.__name__)
            return f(*args, **kwargs)
        return wrapper
    return decorator
@log("renzj")
def func1():
    print('I an func1.')
func1()

输出结果为:

renzjcall function func1
I an func1.

在函数func1前加上@log("renzj")就相当于执行了 func1 = log("renzj")(func1)

8. 偏函数

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数(设置默认值),从而使其在调用时更简单。

print(int('111', base=16))
import functools
int16 = functools.partial(int, base=16)
print(int16('111'))

输出结果为:

273
273

讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!