master
/ 4.2 函数的参数传递.ipynb

4.2 函数的参数传递.ipynb @master

341084b
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
341084b
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
 
 
 
 
 
 
 
 
 
 
 
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
d487d71
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d487d71
 
 
341084b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "# 4.3 函数的参数传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "当函数定义里有多个参数时,其参数的传递形式主要有以下五种:<font color=Red>__位置传递__</font><font color=Red>__关键字__</font><font color=Red>__默认值传递__</font><font color=Red>__包裹传递__</font><font color=Red>__解包裹传递__</font>。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "Python 中一切皆为<font color=Red>__对象__</font>,数字是对象,列表是对象,函数也是对象。而变量是对象的一个<font color=Red>__引用__</font>,对象的操作都是通过引用来完成的。\n",
    "\n",
    "函数调用过程中,<font color=Red>__传递的是对象__</font>。参数的传递本质上是名字到对象的<font color=Red>__绑定过程__</font>。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "默认情况下,参数可以按位置或显式关键字传递给 Python 函数。为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置、按位置或关键字,还是仅按关键字传递。\r\n",
    "\r\n",
    "函数定义如下:下:下:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):\n",
    "      -----------    ----------     ----------\n",
    "        |              |                 |\n",
    "        |        位置或关键字参数          |\n",
    "        |                                - 仅关键字参数\n",
    "         -- 仅位置参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "/ 和 * 是可选的。这些符号表明形参如何把参数值传递给函数:位置、位置或关键字、关键字。  \n",
    "关键字形参也叫作命名形参。函数定义中未使用 / 和 * 时,参数可以按位置或关键字传递给函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "## 4.3.1 位置传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "位置固定,参数传递时按照形式参数<font color=Red>__定义的顺序__</font>提供实际参数。\n",
    "其优点是使用方便,缺点是当参数数目较多时,参数对应容易混淆。且要求传入参数的数量必须和定义函数时参数的数量相同。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "仅限位置 时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 / (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /,则表示没有仅限位置形参。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby):\n",
    "    '''接收三个字符串作为参数,返回一个进行自我介绍的字符串'''\n",
    "    return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby) \n",
    "\n",
    "\n",
    "n,c,h = input().split()  # 根据空格切分输入字符串,分别赋值给n,c,h \n",
    "print(fun(n,c,h))       # 根据实参变量n,c,h的顺序传递参数或值给形参name, city, hobby"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "调用fun()函数时,将实际参数n、c、h这三个字符串对象按顺序赋值给形式参数name、city、hobby,或者说将三个变量标签name、city、hobby按出现的顺序分别贴在\"夏琦\"、\"武汉\"、\"羽毛球\"这三个字符串对象上。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "在定义fun()函数时,参数name、city、hobby尚未绑定对象,没有值。\n",
    "\n",
    "只有经过函数调用,才会把调用时的参数值赋值给形式参数,函数体中的变量才有了值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "## 4.3.2 关键字传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "关键字传递是指,在函数调用时<font color=Red>__提供__</font>实际参数所对应的<font color=Red>__形式参数__</font>的名称,根据<font color=Red>__参数名称来传递参数__</font>。\n",
    "\n",
    "关键字并不需要遵守位置的对应关系。其优点是明确标示实际参数和形式参数的对应关系,参数的书写顺序更灵活。缺点是增加了函数调用时的代码书写量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby):\n",
    "    return '我的名字是{},来自{},我的爱好是{}'.format(name, city, hobby) \n",
    "\n",
    "\n",
    "n,c,h = input().split()  # 切分字符串,分别赋值给n,c,h \n",
    "print(fun(hobby = h, city = c,name = n))      # 根据关键字name, city, hobby来传递参数,关键字传递时顺序无关 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "位置传递和关键字传递<font color=Red>__可以混用__</font>。但要注意的是,混用时,按<font color=Red>__位置传递__</font>的参数要出现在按<font color=Red>__关键字传递__</font>的参数<font color=Red>__之前__</font>。否则,编译器无法明确知道除关键字以外的参数出现的顺序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby):\n",
    "    return '我的名字是{},来自{},我的爱好是{}'.format(name, city, hobby)\n",
    "\n",
    "n,c,h = input().split()   # 切分字符串,分别赋值给n,c,h\n",
    "print(fun(n, hobby = h, city = c))      # 位置参数n出现在关键字参数h和c之前 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "在定义函数时,我们可以在参数列表中用“/”设置强制位置参数(positional-only arguments)。用“*”设置命名关键字参数。  \n",
    "所谓强制位置参数,就是调用函数时只能按照参数位置来接收参数值的参数;而命名关键字参数只能通过“参数名=参数值”的方式来传递和接收参数,大家可以看看下面的例子。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby, /):  # /前面的参数是强制位置参数\n",
    "    \"\"\"接收三个字符串作为位置参数,返回一个进行自我介绍的字符串\"\"\"\n",
    "    return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)\n",
    "\n",
    "\n",
    "print(fun('夏琦', '武汉', '羽毛球'))  # 可以按位置传递参数\n",
    "# 输出 我的名字是夏琦,来自武汉,我的爱好是羽毛球。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby, /):  # /前面的参数是强制位置参数\n",
    "    \"\"\"接收三个字符串作为位置参数,返回一个进行自我介绍的字符串\"\"\"\n",
    "    return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)\n",
    "\n",
    "\n",
    "# 下面的代码会产生TypeError错误,错误信息提示“强制位置参数是不允许给出参数名的”\n",
    "# TypeError: fun() got some positional-only arguments passed as keyword arguments: 'city, hobby'\n",
    "n, c, h = '夏琦', '武汉', '羽毛球'\n",
    "print(fun(n, hobby=h, city=c))  # 传入一个位置参数和两个关键字参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, *, city, hobby):  # *后面的参数是强制关键字参数\n",
    "    \"\"\"接收三个字符串,一个位置参数两个关键字参数,返回一个进行自我介绍的字符串\"\"\"\n",
    "    return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)\n",
    "\n",
    "\n",
    "n, c, h = '夏琦', '武汉', '羽毛球'\n",
    "print(fun(n, hobby=h, city=c))  # 传入一个位置参数和两个关键字参数\n",
    "# 输出 我的名字是夏琦,来自武汉,我的爱好是羽毛球。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, *, city, hobby):  # *后面的参数是强制关键字参数\n",
    "    \"\"\"接收三个字符串,一个位置参数两个关键字参数,返回一个进行自我介绍的字符串\"\"\"\n",
    "    return '我的名字是{},来自{},我的爱好是{}。 '.format(name, city, hobby)\n",
    "\n",
    "\n",
    "# 下面的代码会产生TypeError错误,错误信息提示“函数只能接收一个位置参数,但传递了3个位置参数”\n",
    "# TypeError: fun() takes 1 positional argument but 3 were given\n",
    "print(fun('夏琦', '武汉', '羽毛球'))  # 传入三个位置参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "## 4.3.3 默认值传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "在定义函数的时候,使用形如city='武汉'的方式,可以给形式参数赋予<font color=Red>_默认值(default)__</font>。在函数调用时,如果该参数得到传入值,按传入值进行计算,否则使用默认值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby='唱歌'):\n",
    "    return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)\n",
    "\n",
    "n,c = input().split()   # 切分字符串,分别赋值给n,c,例如输入:夏琪 武汉\n",
    "print(fun(n, c))        # 默认值参数可以不传值 \n",
    "# 输出: 我的名字是夏琪,来自武汉,我的爱好是唱歌。\n",
    "\n",
    "print(fun(n, c, '游泳')) # 传值时,默认值会被传入的值替换 \n",
    "# 输出: 我的名字是夏琪,来自武汉,我的爱好是游泳。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "可以用列表存储输入,再用星号*解包传递给函数,可做到传递任意数量的参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(name, city, hobby='唱歌'):\n",
    "    return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)\n",
    "\n",
    "ls = input().split()   # 切分字符串得到列表,例如输入:夏琪 武汉,得到['夏琪', '武汉']\n",
    "print(fun(*ls))        # ['夏琪', '武汉']解包为:'夏琪', '武汉'\n",
    "# 输出: 我的名字是夏琪,来自武汉,我的爱好是唱歌。\n",
    "\n",
    "\n",
    "ls = input().split()   # 切分字符串得到列表,例如输入:夏琪 武汉 游泳,得到['夏琪', '武汉', '游泳']\n",
    "print(fun(*ls))        # ['夏琪', '武汉', '游泳']解包为:'夏琪', '武汉', '游泳'\n",
    "# 输出: 我的名字是夏琪,来自武汉,我的爱好是游泳。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "需要注意的是,<font color=Red>__默认值参数__</font>必须放在必选参数<font color=Red>__之后__</font>。当函数的参数有多个时,默认值参数必须在后面,非默认值参数在前面。\n",
    "\n",
    "也就是说,<font color=Red>__一旦__</font>出现了带默认值的参数,<font color=Red>__后面的其他参数都必须带默认值了__</font>。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun( city,name='夏琪', hobby='唱歌'):    #语法错误,city 是非默认值参数,出现在默认值参数hobby的前面了\n",
    "    return '我的名字是{},来自{},我的爱好是{}。'.format(name, city, hobby)\n",
    "\n",
    "\n",
    "n,c,h = input().split()  # 切分字符串,分别赋值给n,c,h \n",
    "print(fun(n,c,h))        # 调用函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "<font face='楷体' color='red' size=5> 练一练 </font>\n",
    "\n",
    "利用Python中支持默认值参数的特性,修改上一节里定义的幂函数power(x,n),使其默认计算x的平方。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#修改后的power(x,n)函数\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "需要注意的是,默认值参数可以指向不可变对象,如整型(int)、字符串(string)、浮点型(float)、元组(tuple)等,不能指向字典(dict)和列表(list)等可变对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(x, ls = []):   # 这里默认参数ls指向了空列表,列表是可变对象\n",
    "    ls.append(x)       # 在列表ls的末尾追加一个元素\n",
    "    return ls          # 返回ls\n",
    "\n",
    "print(fun(1))  # 第一次调用,输出 [1] \n",
    "print(fun(3))  # 第二次调用,输出 [1, 3] \n",
    "print(fun(5))  # 第三次调用,输出 [1, 3, 5] "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "按函数调用规则,每次函数调用时,形参都会被重新赋值。即在三次调用中,形参x分别被赋值为1,3,5,带缺省值的形参ls每次应该被重新赋值为空列表。\n",
    "\n",
    "但程序的运行结果表明,在多次调用过程中,<font color=Red>__ls并没有被重新赋值为空列表__</font>,导致ls中的元素累积下来。\n",
    "分析其原因,ls是可变对象,在函数定义时被创建,<font color=Red>__其后所有函数调用都引用这个列表对象__</font>。Python规定参数传递都是传递的引用,也就是传递给函数的是原变量实际所指向的内存空间。而append()方法并不会改变列表的内存空间,也就是说不会重新创建列表对象,只是向其中增加元素。所以每次调用该函数时,一直引用函数定义时创建的列表对象ls,<font color=Red>__导致元素累积__</font>。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "如果一定要用这种方法的话,可以做如下修改:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fun(x, ls = None):  # ls为默认值参数,设为不可变对象None\n",
    "    if ls is None:      # 若ls值为None,说明是重新调用,将列表置为空\n",
    "        ls = []\n",
    "    ls.append(x)\n",
    "    return ls \n",
    "\n",
    "\n",
    "print(fun(1))          # 第一次调用,输出 [1] \n",
    "print(fun(3))          # 第二次调用,输出 [3] \n",
    "print(fun(5))          # 第三次调用,输出 [5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "## 4.3.4 包裹传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "包裹传递也称为不定参数传递,用于在定义函数时不能确定函数调用时会传递多少个参数时使用。函数每次调用时,传递的参数数量可以不同。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "1. 当传入参数是位置传递时,所有传入参数被收集打包合并成一个元组,再传递给函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1, 3, 5, 7, 9)\n",
      "25\n",
      "(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)\n",
      "55\n",
      "(1, 2, 'hello', 3.45, 6)\n",
      "12.45\n"
     ]
    }
   ],
   "source": [
    "def add(*number):\n",
    "    \"\"\"接收不确定数量位置传递的参数,合并为一个元组number在函数体内使用\"\"\"\n",
    "    print(number)  # 查看参数类型,元组\n",
    "    result = 0\n",
    "    for i in number:\n",
    "        if type(i) in (int, float):  # 对参数进行了类型检查(数值型的才能求和)\n",
    "            result = result + i\n",
    "    return result\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    print(add(1, 3, 5, 7, 9))\n",
    "    print(add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))\n",
    "    print(add(1, 2, 'hello', 3.45, 6))  # 12.45"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "1. 当传入参数是关键字传递时,所有传入的关键字参数被收集打包合并成一个字典,再传递给函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'a': 1, 'b': 3, 'c': 5}\n",
      "9\n",
      "{'m': 1, 'n': 2, 'o': 3, 'p': 4, 'q': 5, 'i': 6, 'j': 7, 'k': 8}\n",
      "36\n"
     ]
    }
   ],
   "source": [
    "def add(**number):\n",
    "    \"\"\"接收不确定数量的关键字参数,合并为一个字典number在函数体内使用\"\"\"\n",
    "    print(number)\n",
    "    return sum(number.values())\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    print(add(a=1, b=3, c=5))\n",
    "    print(add(m=1, n=2, o=3, p=4, q=5, i=6, j=7, k=8))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "参数列表中的**kwargs可以接收0个或任意多个关键字参数  \n",
    "调用函数时传入的关键字参数会组装成一个字典(参数名是字典中的键,参数值是字典中的值)  \n",
    "如果一个关键字参数都没有传入,那么kwargs会是一个空字典  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def foo(*args, **kwargs):\n",
    "    print(args)\n",
    "    print(kwargs)\n",
    "\n",
    "\n",
    "foo(3, 2.1, True, name='骆昊', age=43, gpa=4.95)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "## 4.3.5 解包裹传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "“\\*”“\\*\\*”也可以以函数调用时使用,此时称为解包裹传递。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add(a, b, c):\n",
    "    \"\"\"接收三个位置传递参数,返回其加和\"\"\"\n",
    "    return a + b + c\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    num1 = (1, 3, 5)\n",
    "    print(add(*num1))\n",
    "    num2 = {'a': 1, 'b': 2, 'c': 3}\n",
    "    print(add(**num2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "inputHidden": false
   },
   "source": [
    "函数调用总是会给形参列表中列出的所有形参赋值,或是用位置参数,或是用关键字参数,或是用默认值。 如果存在 \"*identifier\" 这样的形式,它会被初始化为一个元组来接收任何额外的位置参数,默认为一个空元组。 如果存在 \"**identifier\" 这样的形式,它会被初始化为一个新的有序映射来接收任何额外的关键字参数,默认为一个相同类型的空映射。   \n",
    "在 \"*\" 或 \"*identifier\" 之后的形参都是仅限关键字形参因而只能通过关键字参数传入。   \n",
    "在 \"/\" 之前的形参都是仅限位置形参因而只能通过位置参数传入。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}