一、动态参数

def func(a,b,c,d,e,f,g):
    pass
func(1,2,3,4,5,6,7)

如果加30个参数呢?
有没有万能的参数,可以代表一切参数呢?

*args 动态参数,万能参数
agrs接收的就是实参对应的所有位置参数,并将其放在元组中
它不会接收关键字参数

def func(*args):
    pass
func(1,2,3,4,5,6,7)

打印返回值

def func(*args):
    print(args)
func(1,2,3,4,5,6,7)

执行输出:
(1, 2, 3, 4, 5, 6, 7)

结果是一个元组

二、形参对应顺序

def func(*args,a,b,c,d,e='sex'):
    print(args,a,b,c,d,e)
func(1,2,3,4,5)

执行报错,因为*args接收了所有实参,所以缺少了b,c,d参数

TypeError: func() missing 4 required keyword-only arguments: 'a', 'b', 'c', and 'd'

修改正确的位置

def func(a,b,c,d,*args,e='sex'):
    print(a,b,c,d,args,e)
func(1,2,3,4,5,6,7,8,e='女')

执行输出:

1 2 3 4 (5, 6, 7, 8) 女

 

形参对应顺序:

位置参数,*args,默认参数

 

*args参数,可以不传,默认为空()

def func(a,b,c,d,*args,e='sex'):
    print(a,b,c,d,args,e)
func(1,2,3,4,e='女')

执行输出:

1 2 3 4 () 女

 

*args 名字可以改的,但是约定成熟使用*args

 

**kwargs也是动态参数,和*args 不同的是,它只接收关键字参数

**kwargs 动态传参,他将所有的关键字参数(未定义的)放到一个字典中。

def func(a,b,c,**kwargs):
    print(kwargs)
func(1,2,r=4,b1=5,c1=6,c=7)

执行输出:

{'r': 4, 'c1': 6, 'b1': 5}

执行没有报错,是因为函数接收参数后,它会从左边到右找,最后找到了c

c=7参数,在a,b,c里面已经定义好了,所以在输出的字典中,并未出现。

因为kwargs返回的是未定义的关键字参数。

 

**kwargs正确的位置

def func(a,b,c,d,*args,e='男',**kwargs):
    print(a,b,c,d,args,e,kwargs)
func(1,2,3,4,5,6,7,v=3,m=7,h=9,e='女')

执行输出:

1 2 3 4 (5, 6, 7) 女 {'v': 3, 'h': 9, 'm': 7}

 

最终所有参数顺序:位置参数,*args,默认参数,**kwargs

如果函数含有多个未知参数,一般使用如下格式:

def func1(*args,**kwargs):
    pass
func1()

它能接收所有的参数

比如len()源码

def len(*args, **kwargs): # real signature unknown
    """ Return the number of items in a container. """
    pass

源码千万别不要修改

 

三、 * 魔法运用

有如下函数

def func(*args):
    print(args)
l1 = [1,2,30]
l2 = [1,2,33,21,45,66]

需要将2个列表的所有元素赋值给args,如何去做?

这个时候,需要用到*

def func(*args):
    print(args)
l1 = [1,2,30]
l2 = [1,2,33,21,45,66]
func(*l1)
func(*l1,*l2)

执行输出:

(1, 2, 30)
(1, 2, 30, 1, 2, 33, 21, 45, 66)

 

传两个字典给**kwargs

def func(**kwargs):
    print(kwargs)
dic1 = {'name':'jack','age':22}
dic2 = {'name1':'rose','age1':21}
func(**dic1,**dic2)

执行输出:

{'name': 'jack', 'age': 22, 'name1': 'rose', 'age1': 21}

 

**kwargs只限于字典类型

 在函数的调用执行时,
   *可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args。
   **字典,代表打散,将所有键值对放到一个kwargs字典里。

def func(*args,**kwargs):
    print(args,kwargs)
dic1 = {'name':'jack','age':22}
dic2 = {'name1':'rose','age1':21}
func(*[1,2,3,4],*'asdk',**dic1,**dic2)

执行输出:

(1, 2, 3, 4, 'a', 's', 'd', 'k') {'age1': 21, 'name': 'jack', 'age': 22, 'name1': 'rose'}

 

 四、命名空间和作用域

a = 4
b = 3
c = [1,2,3,4]
c1 = {'name':'alex'}

def func1():
    name = '老男孩'
    print(name)
func1()

当执行函数的时候,他会在内存中开辟一个临时名称空间,存放函数体内的所有变量与值的关系,
随着函数的执行完毕,临时空间自动关闭。
input(),print(),len 内置函数

 

函数里面的变量,在函数外面能直接引用么?

def func1():
    m = 1
    print(m)

print(m)  # 这行报的错

执行报错:
NameError: name 'm' is not defined


上面为什么会报错呢?现在我们来分析一下python内部的原理是怎么样:
  我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。
  等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间
在函数的运行中开辟的临时的空间叫做局部命名空间

 

python之禅

import this

  执行输出:

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
View Code

相关文章: