Python * args和** kwargs

时间:2020-02-23 14:42:26  来源:igfitidea点击:

Python函数参数

Python允许我们为函数定义三种类型的参数:

  • 形式参数,例如def add(a,b)
  • 使用* args的可变数量的非关键字参数,例如def add(* args)
  • 可变数量的关键字参数或者使用** kwargs命名的参数,例如def add(** kwargs)

有关函数参数的一些重要点。

  • 当定义函数参数时,顺序应为形式参数,后跟* args和** kwargs。

  • 不必使用args和kwargs这两个名称,我们也可以使用其他名称。
    但是,惯例是使用它们。
    这将使您的代码易于阅读和理解。

  • args变量的类型为tuple。
    我们可以将元组作为函数参数传递给args进行映射。

  • kwargs变量的类型为dict。
    因此,我们可以将字典作为参数传递给kwargs。

为什么我们需要* args和** kwargs?

假设我们有一个将两个数字相加的函数:

def add_two_numbers(a, b):
  return a + b

现在我们要扩展它以添加三个数字。
我们不能只更改此功能,因为它可能会在其他地方使用,这将是一个重大突破。
因此,我们引入了另一个函数,将三个数字相加。

def add_three_numbers(a, b, c):
  return a + b + c

你知道我要去其中了吧?由于我们可以为函数指定可变数量的参数,因此我们可以定义一个通用函数来添加数字。

Python * args示例

让我们定义一个通用函数,使用* args变量添加数字。

def add(*args):
  total = 0
  for arg in args:
      total = total + arg
  return total

print(add(1, 2))
print(add(1, 2, 3))
print(add(1, 2, 3, 4))

* args和** kwargs是什么类型?

def zap(*args, **kwargs):
  print(type(args))
  print(type(kwargs))

zap()

输出:

<class 'tuple'>
<class 'dict'>

Python ** kwargs示例

我们定义一个函数来显示** kwargs变量的用法。

def kwargs_processor(**kwargs):
  for k, v in kwargs.items():
      print(f'Key={k} and Value={v}')

kwargs_processor(name='hyman', age=34)
kwargs_processor(country='San Franceco', capital='New Delhi')

输出:

Key=name and Value=hyman
Key=age and Value=34
Key=country and Value=San Franceco
Key=capital and Value=New Delhi

为* args和** kwargs映射传递元组和字典

让我们看看如何将元组值与args和dictionary元素映射到kwargs变量。

t = (10, 30, 60)
print(add(*t))

d = {'name': 'hyman', 'age': 34}
kwargs_processor(**d)

输出:

100
Key=name and Value=hyman
Key=age and Value=34

注意在使用元组将其值映射到args时使用*。
同样,**用于将dict元素映射到kwargs变量。

何时使用* args和** kwargs

您可以在期望可变数量参数的任何函数中使用它们。
但是,它们在两种特定情况下非常有用–模拟函数响应和编写通用装饰函数。

用* args和** kwargs模拟函数响应

假设我们有一个如下定义的API类:

class APIHelper:

  def call_api(self, url, input_json):
      # some complex logic
      return 'complex_response_data'

我们可以创建一个测试模拟器函数并将其映射到API函数以生成测试响应。

class MyTestClass:

  def test_call_api(self, *args, **kwargs):
      return "test_response_data"

# Assign API function to use our test function
APIHelper.call_api = MyTestClass.test_call_api

让我们看看现在使用API函数时会发生什么。

ah = APIHelper()
print(ah.call_api())
print(ah.call_api(1, url='https://www.theitroad.local', input_json={}))
print(ah.call_api(1, 2, url='https://www.theitroad.local'))

输出:

test_response_data
test_response_data
test_response_data

* args和** kwargs的装饰函数

让我们看看如何定义装饰器函数来记录函数变量。

def log_arguments(func):
  def inner(*args, **kwargs):
      print(f'Arguments for args:{args}, kwargs:{kwargs}')
      return func(*args, **kwargs)

  return inner

现在,我们可以将此装饰器函数与任何其他函数一起使用,以将其参数记录到控制台。

@log_arguments
def foo(x, y, z):
  return x + y + z

sum_ints = foo(1, 2, z=5)
print(sum_ints)

@log_arguments
def bar(x, *args, **kwargs):
  total = x
  for arg in args:
      total = total + arg
  for key, value in kwargs.items():
      total = total + value
  return total

sum_ints = bar(1, 2, 3, a=4, b=5)
print(sum_ints)

输出:

Arguments for args:(1, 2), kwargs:{'z': 5}
8
Arguments for args:(1, 2, 3), kwargs:{'a': 4, 'b': 5}
15