天天看点

据廖雪峰python3教程----python学习第八天

函数的参数

定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。

python的函数除了正常的定义必选参数外,还可以使用默认参数,可变参数合关键字参数,

位置参数

定义一个计算x 的平方的函数

1

2

3

4

5

6

<code>&gt;&gt;&gt; </code><code>def</code> <code>power(x):               </code><code>#参数 x 就是一个位置参数</code>

<code>     </code><code>return</code> <code>x</code><code>*</code><code>*</code><code>2</code>

<code>&gt;&gt;&gt; power(</code><code>5</code><code>)</code>

<code>25</code>

<code>&gt;&gt;&gt; power(</code><code>15</code><code>)</code>

<code>225</code>

为了方便我们再定义一个可以计算 x 的任意次的函数

<code>&gt;&gt;&gt; </code><code>def</code> <code>powern(x,n):</code>

<code>     </code><code>return</code> <code>x</code><code>*</code><code>*</code><code>n</code>

<code>&gt;&gt;&gt; powern(</code><code>5</code><code>,</code><code>2</code><code>)</code>

<code>&gt;&gt;&gt; powern(</code><code>2</code><code>,</code><code>3</code><code>)</code>

<code>8</code>

这是powern中的 x,n  都是位置参数,按 x和n 的位置对应的传入参数

默认参数

对于powern(x,n)如果只穿入一个参数

<code>&gt;&gt;&gt; powern(</code><code>5</code><code>)</code>

<code>Traceback (most recent call last):</code>

<code>  </code><code>File</code> <code>"&lt;pyshell#10&gt;"</code><code>, line </code><code>1</code><code>, </code><code>in</code> <code>&lt;module&gt;</code>

<code>      </code><code>powern(</code><code>5</code><code>)</code>

<code>TypeError: powern() missing </code><code>1</code> <code>required positional argument: </code><code>'n'</code>

python会抛出错误提示少一个参数

这时我们可以 设置 默认参数:

<code>&gt;&gt;&gt; </code><code>def</code> <code>powern(x,n</code><code>=</code><code>2</code><code>):          </code><code>#在这里把n=2 设置位默认参数</code>

<code>     </code> 

<code>25</code><code>&gt;&gt;&gt; powern(</code><code>5</code><code>,</code><code>3</code><code>)</code>

<code>125</code>

当只输入一个参数x 时相当于 计算 x 的平方

设置默认函数可以简化函数的调用。设置默认参数时,有有几点需要注意:

1:必选参数在前,默认参数在后。

2:如何设置默认参数。当函数有多个参数时,把变化大的参数放在前面,变化小的参数放在后面。变化小的参数就可以设置为默认参数。

默认参数很有用,但使用不当会掉坑,默认参数有个最大的坑,比如:

先定义一个函数,传入一个list ,添加一个 END 再返回:

<code>&gt;&gt;&gt; </code><code>def</code> <code>add_end(L</code><code>=</code><code>[]):</code>

<code>     </code><code>L.append(</code><code>'END'</code><code>)</code>

<code>     </code><code>return</code> <code>L</code>

调用时,结果似乎不错:

<code>&gt;&gt;&gt; add_end([</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>])</code>

<code>[</code><code>1</code><code>, </code><code>2</code><code>, </code><code>3</code><code>, </code><code>'END'</code><code>]</code>

<code>&gt;&gt;&gt; add_end([</code><code>'x'</code><code>,</code><code>'y'</code><code>,</code><code>'z'</code><code>])</code>

<code>[</code><code>'x'</code><code>, </code><code>'y'</code><code>, </code><code>'z'</code><code>, </code><code>'END'</code><code>]</code>

使用默认参数是,一开始结果也不错:

<code>&gt;&gt;&gt; add_end()</code>

<code>[</code><code>'END'</code><code>]</code>

但是,再次调用add_end()时,结果就不对了:

<code>[</code><code>'END'</code><code>, </code><code>'END'</code><code>]</code>

<code>[</code><code>'END'</code><code>, </code><code>'END'</code><code>, </code><code>'END'</code><code>]</code>

函数似乎“记住了”上次添加了‘end’的list

为什么呢:

python在定义的时候,默认参数L的值就被计算出来,即[ ] ,因为默认参数L也是一个变量,它指向对象 

[ ]  ,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不在是定义的 [ ] 了。

所以,定义默认参数要牢记一点:默认参数必须指向不变的对象。!!

要修改上面的例子,我们可以用 None 这个 不变对象来实现:

<code>&gt;&gt;&gt; </code><code>def</code> <code>add_end(L</code><code>=</code><code>None</code><code>):</code>

<code>     </code><code>if</code> <code>L </code><code>is</code> <code>None</code><code>:</code>

<code>        </code><code>L</code><code>=</code> <code>[]</code>

这用我们在调用就不会出错了:

在做一下对比:

7

8

9

10

<code>    </code><code>if</code> <code>L </code><code>is</code> <code>None</code><code>:</code>

<code>        </code><code>L</code><code>=</code><code>[]</code>

<code>    </code><code>L.append(</code><code>'END'</code><code>)</code>

<code>    </code><code>return</code> <code>L    </code>

<code>    </code> 

<code>&gt;&gt;&gt; add_end()             </code>

可变参数

可变参数就是传入参数的个数是可变的,可以是任意个。

比如:给定一组数字a,b,c........,计算 a2 + b2+ c2 + ……。

要定义出这个函数,我们必须确定输入的参数。由于参数个数是不确定的,我们首先想到可以吧a,b,c,.......。作为一个list或tuple 传进去,这样函数可定义为:

<code>&gt;&gt;&gt; </code><code>def</code> <code>calc(number):</code>

<code>     </code><code>sum</code><code>=</code><code>0</code>

<code>     </code><code>for</code> <code>n </code><code>in</code> <code>number:</code>

<code>       </code><code>sum</code><code>=</code><code>sum</code><code>+</code><code>n</code><code>*</code><code>*</code><code>2</code>

<code>     </code><code>return</code> <code>sum</code>

但是在调用的时候,需要先组装出一个list或tuple:

<code>&gt;&gt;&gt; calc([</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>])</code>

<code>14</code>

<code>&gt;&gt;&gt; calc([</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>,</code><code>4</code><code>])</code>

<code>30</code>

如果利用可变参数,调用函数的方式可以简化:

<code>&gt;&gt;&gt; calc(</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>)</code>

<code>&gt;&gt;&gt; calc(</code><code>0</code><code>)</code>

<code>0</code>

所以我们需要把函数改变为可变参数:

<code>&gt;&gt;&gt; </code><code>def</code> <code>calc(</code><code>*</code><code>number):</code>

<code>     </code><code>sum</code><code>=</code><code>0</code>     

<code>     </code><code>for</code> <code>n </code><code>in</code> <code>number:   </code>

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数的内部,参数 number 接受到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数。

<code>&gt;&gt;&gt; calc()</code>

如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

<code>&gt;&gt;&gt; nums</code><code>=</code><code>[</code><code>1</code><code>,</code><code>2</code><code>,</code><code>3</code><code>]</code>

<code>&gt;&gt;&gt; calc(nums[</code><code>0</code><code>],nums[</code><code>1</code><code>],nums[</code><code>2</code><code>])</code>

这种方法太繁琐,所以 python 允许在list或tuple的元素前面加一个*号,把list或tuple的元素变成可变参数传进去:

<code>&gt;&gt;&gt; calc(</code><code>*</code><code>nums)</code>

*num表示把num这个list的所有元素作为可变参数穿进去。这种写法相当有用,而且很常见。

关键字参数

可变参数允许你传入0或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个参数或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

<code>&gt;&gt;&gt; </code><code>def</code> <code>person(name,age,</code><code>*</code><code>*</code><code>kw):</code>

<code>     </code><code>print</code><code>(</code><code>'name:'</code><code>,name,</code><code>'age:'</code><code>,age,</code><code>'other:'</code><code>,kw)</code>

函数person除了必选参数 name 和 age 外,还接受关键字参数 kw 。在调用该函数是,可以之传入必选参数:

<code>&gt;&gt;&gt; person(</code><code>'Michael'</code><code>,</code><code>30</code><code>)</code>

<code>name: Michael age: </code><code>30</code> <code>other: {}</code>

<code>&gt;&gt;&gt; person(</code><code>'Bob'</code><code>,</code><code>35</code><code>,city</code><code>=</code><code>'BeiJing'</code><code>)</code>

<code>name: Bob age: </code><code>35</code> <code>other: {</code><code>'city'</code><code>: </code><code>'BeiJing'</code><code>}</code>

<code>&gt;&gt;&gt; person(</code><code>'xiaoming'</code><code>,</code><code>19</code><code>,gender</code><code>=</code><code>'M'</code><code>,job</code><code>=</code><code>'Enginerr'</code><code>)</code>

<code>name: xiaoming age: </code><code>19</code> <code>other: {</code><code>'gender'</code><code>: </code><code>'M'</code><code>, </code><code>'job'</code><code>: </code><code>'Enginerr'</code><code>}</code>

关键字参数有什么用?它可以扩展函数的功能。比如,在<code>person</code>函数里,我们保证能接收到<code>name</code>和<code>age</code>这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

和可变关键字类似,也可以先组装出一个dict,然后,吧该dict转换为关键字参数传进去:

<code>&gt;&gt;&gt; exter</code><code>=</code><code>{</code><code>'city'</code><code>:</code><code>'BeiJing'</code><code>,</code><code>'Job'</code><code>:</code><code>'Engineer'</code><code>}</code>

<code>&gt;&gt;&gt; person(</code><code>'Jack'</code><code>,</code><code>24</code><code>,city</code><code>=</code><code>exter[</code><code>'city'</code><code>],job</code><code>=</code><code>exter[</code><code>'Job'</code><code>])</code>

<code>name: Jack age: </code><code>24</code> <code>other: {</code><code>'job'</code><code>: </code><code>'Engineer'</code><code>, </code><code>'city'</code><code>: </code><code>'BeiJing'</code><code>}</code>

当然,上面复杂的调用可以用简化的写法:

<code>&gt;&gt;&gt; person(</code><code>'Jack'</code><code>,</code><code>24</code><code>,</code><code>*</code><code>*</code><code>exter)</code>

<code>name: Jack age: </code><code>24</code> <code>other: {</code><code>'Job'</code><code>: </code><code>'Engineer'</code><code>, </code><code>'city'</code><code>: </code><code>'BeiJing'</code><code>}</code>

<code>**extra</code>表示把<code>extra</code>这个dict的所有key-value用关键字参数传入到函数的<code>**kw</code>参数,<code>kw</code>将获得一个dict,注意<code>kw</code>获得的dict是<code>extra</code>的一份拷贝,对<code>kw</code>的改动不会影响到函数外的<code>extra</code>。

命名字关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部用过 kw 检查

<code>     </code><code>if</code> <code>'city'</code> <code>in</code> <code>kw:          </code><code>#city有参数</code>

<code>       </code><code>pass</code>  

<code>      </code><code>if</code> <code>'job'</code> <code>in</code> <code>kw:          </code><code>#有job参数  </code>

<code>         </code><code>pass</code>

<code>     </code><code>print</code><code>(</code><code>'name:'</code><code>,name,</code><code>'age'</code><code>,age,</code><code>'other:'</code><code>,kw)</code>

但是任可以传入不受限制的关键字参数:

<code>&gt;&gt;&gt; person(</code><code>'jack'</code><code>,</code><code>24</code><code>,city</code><code>=</code><code>'beijing'</code><code>,addr</code><code>=</code><code>'chaoyang'</code><code>,zipcode</code><code>=</code><code>123456</code><code>)</code>

<code>name: jack age </code><code>24</code> <code>other: {</code><code>'zipcode'</code><code>: </code><code>123456</code><code>, </code><code>'addr'</code><code>: </code><code>'chaoyang'</code><code>, </code><code>'city'</code><code>: </code><code>'beijing'</code><code>}</code>

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收<code>city</code>和<code>job</code>作为关键字参数。这种方式定义的函数如下:

<code>&gt;&gt;&gt; </code><code>def</code> <code>person(name,age,</code><code>*</code><code>,city,job):</code>

<code>     </code><code>print</code><code>(name,age,city,job)</code>

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。

<code>&gt;&gt;&gt; person(</code><code>'jack'</code><code>,</code><code>24</code><code>,city</code><code>=</code><code>'beijing'</code><code>,job</code><code>=</code><code>'engineer'</code><code>)</code>

<code>jack </code><code>24</code> <code>beijing engineer</code>

命名关键字参数传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

<code>&gt;&gt;&gt; person(</code><code>'jack'</code><code>,</code><code>24</code><code>,</code><code>'beijing'</code><code>,</code><code>'engineer'</code><code>)</code>

<code>  </code><code>File</code> <code>"&lt;pyshell#85&gt;"</code><code>, line </code><code>1</code><code>, </code><code>in</code> <code>&lt;module&gt;</code>

<code>      </code><code>person(</code><code>'jack'</code><code>,</code><code>24</code><code>,</code><code>'beijing'</code><code>,</code><code>'engineer'</code><code>)</code>

<code>TypeError: person() takes </code><code>2</code> <code>positional arguments but </code><code>4</code> <code>were given</code>

由于调用时缺少参数名<code>city</code>和<code>job</code>,Python解释器把这4个参数均视为位置参数,但<code>person()</code>函数仅接受2个位置参数。

命名关键字参数可以有缺省值,从而简化调用:

<code>&gt;&gt;&gt; </code><code>def</code> <code>person(name,age,</code><code>*</code><code>,city</code><code>=</code><code>'BeiJing'</code><code>,job):</code>

由于命名关键字参数<code>city</code>具有默认值,调用时,可不传入<code>city</code>参数:

<code>&gt;&gt;&gt; person(</code><code>'Jack'</code><code>,</code><code>24</code><code>,job</code><code>=</code><code>'Engineer'</code><code>)</code>

<code>Jack </code><code>24</code> <code>BeiJing Engineer</code>

使用命名关键字参数时,要特别注意,<code>*</code>不是参数,而是特殊分隔符。如果缺少<code>*</code>,Python解释器将无法识别位置参数和命名关键字参数:

<code>&gt;&gt;&gt; </code><code>def</code> <code>person(name,age,city,job):</code>

<code>     </code><code>#缺少 *, city 和job 被视为位置参数</code>

<code>     </code><code>pass</code>

参数组合

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

比如定义一个函数,包含上述若干种参数:

<code>def</code> <code>f1(a, b, c</code><code>=</code><code>0</code><code>, </code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kw):</code>

<code>    </code><code>print</code><code>(</code><code>'a ='</code><code>, a, </code><code>'b ='</code><code>, b, </code><code>'c ='</code><code>, c, </code><code>'args ='</code><code>, args, </code><code>'kw ='</code><code>, kw)</code>

<code>def</code> <code>f2(a, b, c</code><code>=</code><code>0</code><code>, </code><code>*</code><code>, d, </code><code>*</code><code>*</code><code>kw):</code>

<code>    </code><code>print</code><code>(</code><code>'a ='</code><code>, a, </code><code>'b ='</code><code>, b, </code><code>'c ='</code><code>, c, </code><code>'d ='</code><code>, d, </code><code>'kw ='</code><code>, kw)</code>

在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。

<code>&gt;&gt;&gt; f1(</code><code>1</code><code>, </code><code>2</code><code>)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>0</code> <code>args </code><code>=</code> <code>() kw </code><code>=</code> <code>{}</code>

<code>&gt;&gt;&gt; f1(</code><code>1</code><code>, </code><code>2</code><code>, c</code><code>=</code><code>3</code><code>)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>3</code> <code>args </code><code>=</code> <code>() kw </code><code>=</code> <code>{}</code>

<code>&gt;&gt;&gt; f1(</code><code>1</code><code>, </code><code>2</code><code>, </code><code>3</code><code>, </code><code>'a'</code><code>, </code><code>'b'</code><code>)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>3</code> <code>args </code><code>=</code> <code>(</code><code>'a'</code><code>, </code><code>'b'</code><code>) kw </code><code>=</code> <code>{}</code>

<code>&gt;&gt;&gt; f1(</code><code>1</code><code>, </code><code>2</code><code>, </code><code>3</code><code>, </code><code>'a'</code><code>, </code><code>'b'</code><code>, x</code><code>=</code><code>99</code><code>)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>3</code> <code>args </code><code>=</code> <code>(</code><code>'a'</code><code>, </code><code>'b'</code><code>) kw </code><code>=</code> <code>{</code><code>'x'</code><code>: </code><code>99</code><code>}</code>

<code>&gt;&gt;&gt; f2(</code><code>1</code><code>, </code><code>2</code><code>, d</code><code>=</code><code>99</code><code>, ext</code><code>=</code><code>None</code><code>)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>0</code> <code>d </code><code>=</code> <code>99</code> <code>kw </code><code>=</code> <code>{</code><code>'ext'</code><code>: </code><code>None</code><code>}</code>

最神奇的是通过一个tuple和dict,你也可以调用上述函数:

<code>&gt;&gt;&gt; args </code><code>=</code> <code>(</code><code>1</code><code>, </code><code>2</code><code>, </code><code>3</code><code>, </code><code>4</code><code>)</code>

<code>&gt;&gt;&gt; kw </code><code>=</code> <code>{</code><code>'d'</code><code>: </code><code>99</code><code>, </code><code>'x'</code><code>: </code><code>'#'</code><code>}</code>

<code>&gt;&gt;&gt; f1(</code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kw)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>3</code> <code>args </code><code>=</code> <code>(</code><code>4</code><code>,) kw </code><code>=</code> <code>{</code><code>'d'</code><code>: </code><code>99</code><code>, </code><code>'x'</code><code>: </code><code>'#'</code><code>}</code>

<code>&gt;&gt;&gt; args </code><code>=</code> <code>(</code><code>1</code><code>, </code><code>2</code><code>, </code><code>3</code><code>)</code>

<code>&gt;&gt;&gt; kw </code><code>=</code> <code>{</code><code>'d'</code><code>: </code><code>88</code><code>, </code><code>'x'</code><code>: </code><code>'#'</code><code>}</code>

<code>&gt;&gt;&gt; f2(</code><code>*</code><code>args, </code><code>*</code><code>*</code><code>kw)</code>

<code>a </code><code>=</code> <code>1</code> <code>b </code><code>=</code> <code>2</code> <code>c </code><code>=</code> <code>3</code> <code>d </code><code>=</code> <code>88</code> <code>kw </code><code>=</code> <code>{</code><code>'x'</code><code>: </code><code>'#'</code><code>}</code>

所以,对于任意函数,都可以通过类似<code>func(*args, **kw)</code>的形式调用它,无论它的参数是如何定义的。

本文转自 nw01f 51CTO博客,原文链接:http://blog.51cto.com/dearch/1760470,如需转载请自行联系原作者