编写高质量代码--改善python程序的建议(六)续

建议三十:记住函数传参既不是传值也不是传引用
以往关于python中函数传参数有三种观点:

  • 传值

  • 传引用

  • 可变对象传引用,不可变对象传值

这些理解都是有些偏差的,python中的赋值与我们所理解的C/C++等语言的赋值的意思并不一样。以如下语句为例来看C/C++和python是如何运作的

a = 5, b= a, b = 7

C/C++中当执行b=a的时候,在内存中申请一块内存并将a的值复制到该内存中,当执行b=7之后是将b对应的值从5修改到7
python中赋值并不是复制,b=a操作使得ba引用同一对象,而b=7则是将b指向对象7
因此,对于python函数参数既不是传值也不是传引用,应该是传对象或者说传对象的引用。函数参数在传递的过程中将整个对象传入,对可变对象的修改在函数外部以及内部都可见,调用者和被调用者之间共享这个对象,而对于不可变对象,由于并不能真正被修改,因此,修改往往是通过生成一个新对象然后赋值来实现的。


建议三十一:慎用变长参数
python支持可变长度的参数列表,可以通过在函数定义的时候使用*args和**kwargs这两个特殊语法来实现。
使用args来实现可变参数列表:args用于接收一个包装为元组形式的参数列表来传递非关键字参数,参数个数可以任意:

def sumf(*args):
    res = 0
    for x in args[:]:
        res += x
    return res

print sumf(2,3,4)
print sumf(1,2,3,4,5)

使用**kwargs接收字典形式的关键字参数列表,其中字典的键值分别表示不可变参数的参数名和值:

def category_table(**kwargs):
    for name, value in kwargs.items():
        print '{0} is a kind of {1}'.format(name, value)

category_table(apple = 'fruit', carrot = 'vegetable')

当普通参数,默认参数,和上述两种参数同时存在的时候,会优先给普通参数和默认参数赋值,为什么要慎用可变长参数呢?

  • 使用过于灵活,是代码不够清晰

  • 如果一个函数的参数列表很长,虽然可以通过使用*args和**kwargs来简化函数的定义,但通常意味着这个函数可以有更好的实现方式,应该被重构。

  • 可变长参数适合在下列情况下使用:

  • 为函数添加一个装饰器

  • 如果参数的数目不确定,可以考虑使用变长参数

  • 用来实现函数的多态或者在继承情况下子类需要调用父类的某些方法的时候

你可能感兴趣的:(python)