1. 可变参数

介绍下 python 中常见的 *args 和 **kwargs 可变参数。

1.1 位置变量参数(*args)

一个函数接受任意数量的参数,称为使用可变参数,例如:

def f(x, *args):
    ...
    
# 函数调用
f(1,2,3,4,5)

#额外的参数作为元组传递。
def f(x, *args):
    # x -> 1
    # args -> (2,3,4,5)

1.2 关键字变量参数(**kwargs)

一个函数也可以接受任意数量的关键字参数。例如:

def f(x, y, **kwargs):
    ...

#函数调用
f(2, 3, flag=True, mode='fast', header='debug')

#额外的关键字在字典中传递。
def f(x, y, **kwargs):
    # x -> 2
    # y -> 3
    # kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }

1.3 结合两者

函数还可以接受任意数量的变量关键字和非关键字参数。

def f(*args, **kwargs):
    ...

#函数调用。
f(2, 3, flag=True, mode='fast', header='debug')

def f(*args, **kwargs):
    # args = (2, 3)
    # kwargs -> { 'flag': True, 'mode': 'fast', 'header': 'debug' }
    ...

1.4 扩展可变参数

元组扩展可变参数

numbers = (2,3,4)
f(1, *numbers)      # Same as f(1,2,3,4)

字典扩展可变参数

options = {
    'color' : 'red',
    'delimiter' : ',',
    'width' : 400
}
f(data, **options)
# Same as f(data, color='red', delimiter=',', width=400)

2. 回调函数与匿名函数

sort()的列表排序

s = [10,1,7,3]
s.sort() # s = [1,3,7,10]
s.sort(reverse=True) # s = [10,7,3,1]

sort()的字典排序

[{'name': 'AA', 'price': 32.2, 'shares': 100},
{'name': 'IBM', 'price': 91.1, 'shares': 50},
{'name': 'CAT', 'price': 83.44, 'shares': 150},
{'name': 'MSFT', 'price': 51.23, 'shares': 200},
{'name': 'GE', 'price': 40.37, 'shares': 95},
{'name': 'MSFT', 'price': 65.1, 'shares': 50},
{'name': 'IBM', 'price': 70.44, 'shares': 100}]

#使用 key 回调函数排序
def stock_name(s):
    return s['name']

portfolio.sort(key=stock_name)

[
  {'name': 'AA', 'price': 32.2, 'shares': 100},
  {'name': 'CAT', 'price': 83.44, 'shares': 150},
  {'name': 'GE', 'price': 40.37, 'shares': 95},
  {'name': 'IBM', 'price': 91.1, 'shares': 50},
  {'name': 'IBM', 'price': 70.44, 'shares': 100},
  {'name': 'MSFT', 'price': 51.23, 'shares': 200},
  {'name': 'MSFT', 'price': 65.1, 'shares': 50}
]

匿名函数 Lambda

Lambda 允许直接在调用中定义一个特殊的处理函数。

  • lambda 只允许使用一个表达式。
  • 没有声明语句 if, while 等
  • 通常与 sort 函数使用。

使用匿名函数代替以上回调函数,语法更加简短。

portfolio.sort(key=lambda s: s['name'])

3. Returning 函数

返回函数是在一个函数中返回另外一个函数。

例如:

def add(x, y):
    def do_add():
        print('Adding', x, y)
        return x + y
    return do_add

>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
Adding 3 4
7

3.1 局部变量

内部函数引用外部函数定义的局部变量。

def add(x, y):
    def do_add():
        # `x` and `y` are defined above `add(x, y)`
        print('Adding', x, y)
        return x + y
    return do_add

3.2 闭包

当一个内部函数作为结果返回时,该内部函数称为闭包(closure)。

def add(x, y):
    # `do_add` is a closure
    def do_add():
        print('Adding', x, y)
        return x + y
    return do_add

闭包也可以用作避免过多代码重复(使用函数生成代码)。

闭包的使用:

  • 在回调函数中使用
  • 延迟评估
  • 装饰器中

延迟评估

def add(x, y):
    def do_add():
        print(f'Adding {x} + {y} -> {x+y}')
    return do_add

def after(seconds, func):
    import time
    time.sleep(seconds)
    func()

# after执行稍后提供的函数
after(30, add(2, 3))
# `do_add` has the references x -> 2 and y -> 3

4. 装饰器

装饰器的功能可以理解为,去除函数中重复的输出部分,常用于日志记录部分。

创建一个装饰器,使函数添加日志记录功能。

def logged(func):
    def wrapper(*args, **kwargs):
        print('Calling', func.__name__)
        return func(*args, **kwargs)
    return wrapper

def add(x, y):
    return x + y

logged_add = logged(add)

>>> logged_add(3, 4) # logged()函数创建装饰器并将其作为结果返回
Calling add   # 输出结果,并使用装饰器的功能。
7

以上模仿了装饰器的调用过程,但实际应用中,使用特殊的装饰器语法调用即可。

装饰器语法:

def logged(func):
    def wrapper(*args, **kwargs):
        print('Calling', func.__name__)
        return func(*args, **kwargs)
    return wrapper

@logged # 装饰器语法
def add(x, y):
    return x + y



>>> add(3, 4) 

Calling add   # 输出结果,并使用装饰器的功能。
7

5. 装饰方法

5.1 预定义的装饰器

预定义的装饰器用于在类定义中指定特殊类型的方法。

静态方法

@staticmethod 用于定义所谓的静态类方法(来自 C++/Java)。

静态方法是一个函数,它是类的一部分,但它不对实例进行操作。

class Foo(object):
    @staticmethod
    def bar(x):
        print('x =', x)

>>> Foo.bar(2) 
x=2

静态方法有时用于实现类的内部支持代码。例如,帮助管理已创建实例的代码(内存管理、系统资源、持久性、锁定等)。

类方法
@classmethod用于定义类方法。

类方法是接收类对象作为第一个参数的方法。

类方法最常被用作定义替代构造函数的工具。

class Foo:
    def bar(self):
        print(self)

    @classmethod
    def spam(cls):
        print(cls)

>>> f = Foo()
>>> f.bar()
<__main__.Foo object at 0x971690>   # The instance `f`
>>> Foo.spam()
<class '__main__.Foo'>              # The class `Foo`
>>>
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐