练习19--函数和变量

一  函数的调用

  • 定义一个函数只给了函数一个名称,指定了函数里包含的参数,和代码块结构。
  • 这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python提示符执行。
  • 调用方法: 函数名(传入的参数)
  • 报错原因:
    • 调用函数的时候,如果传入的参数数量不对,会报TypeError的错误,abs()有且仅有1个参数,但给出了两个:
    • 如果传入的参数数量是对的,但参数类型不能被函数所接受,也会报TypeError的错误,并且给出错误信息:str是错误的参数类型:
二  函数的参数及参数传递https://www.cnblogs.com/linupython/p/6609217.html
定义函数的目的是便于在程序的其他地方调用,而对于很多函数或执行逻辑来讲,不同的输入往往会导致截然不同的输出,因此函数是需要能接收输入的参数的。
1 函数中的参数分类:
  • 形参:即形式参数,在定义函数时引入的参数,只有在函数被调用时才会存在并为其分配内存空间
  • :调用函数时实际传入的参数,即执行函数定义的逻辑时给定的输入,占用内存空间。调用函数时实参的值会根据一定的规则传递给形参来执行函数中定义的逻辑过程。

2 参数传递

  • 位置参数传入:位置参数传入是一种最简单的参数传入方式,传入是实参与形参的相对位置一对一对应。
    • 注意:位置参数传入时实参的个数与形参的个数必须严格一致,多一个或少一个都会报错
  • 关键字参数传入:在调用函数传入参数时,直接使用形参的名字对其进行赋值。传入实参的顺序与形参定义的顺序可以不一致,传入时通过参数的名字来对号入座(相对位置已经失效)。
    • 如果把位置参数和关键字参数混合使用,会按照位置参数调用来进行处理,或者说各自为政,互不干扰,但前提是位置参数不能放在关键字参数后面
  • 默认参数传入 :在定义函数时还可以直接对引入的形参进行赋值来作为参数的默认值。
    • 这种情况下在调用函数时是否需要传入实参已经不重要了,如果不传入实参则使用则使用对应形参的默认值,否则则传入实参执行函数(覆盖参数的默认值)。
    • 默认参数传入方式接收位置调用和关键字调用,主要用于以下场景:
      • 为软件的安装预设默认安装路径
      • 设定某些应用的默认参数,如数据的默认连接端口为3306
  • 参数组参数传入 :参数组参数传入用于传递非固定长度的参数,实参会被转换为元组或字典传递给形参。
    • 在定义函数的形参时,如果形参以一个星号*开头然后接上其它的有效字符串,并且调用函数时实参以位置参数方式传入,实参会被转换为元组执行函数。
      • def func1(*args):     
                 …                  #省略代码块
                 return#省略return的值
             a = func1(x, y, z) #x,y,z表示实参
      • 如果通过参数组方式传入参数,并且想以元组方式传入,实参必须以位置参数方式传入,否则直接报错
    • 在定义函数的形参时,如果形参以两个星号**开头然后接上其它的有效字符串,并且调用函数时实参以关键字参数方式传入,实参会被转换为字典执行函数。
      •   def func2(**args):   
                 …                  #省略代码块
                 return#省略return的值
             a = func1(x=1, y=2, z=3) #x,y,z表示实参
      • 一旦形参定义为两个星号开头的格式,那么实参就只能是以关键字参数方式传入(只有关键字参数传入才符合字典的key-value特征): 
      • 参数组参数传入方式也可以与其他形式的参数传入方式混合使用,此时,参数组传入的参数需要尽量放在后面,位置调用参数也不能跟在关键字参数后面。
  • 混合参数传入:混合参数传入即将上述的几种参数传入方式混合使用,此时位置调用不在遵循位置的严格对应关系,或者说传入参数的方式更符合上述哪种传入方式就按照哪种方式来传入参数。

三 函数作用域

1 定义:作用域是指对某一变量和方法具有访问权限的代码空间

2 根据作用域对函数内部的变量分类:

  • 全局变量:在函数外部(子程序)定义定义后在程序的全局范围内均有效且可被访问到,即它的作用域是程序全局
  • 局部变量在函数内部定义,仅在函数内部效且可被访问到,即作用域是函数内部,除非通过global关键字将变量的作用域修改为全局。
  • 总结:全局变量和局部变量各自的作用域决定了默认情况下在函数内部可任意调用访问全局变量,但反之在函数外部范围内不可调用访问在该函数内部定义的局部变量,除非在函数内部定义局部变量时加上global关键字。

3 全局变量和局部变量间转换和被对方调用的具体规则

  • 默认情况下可在函数内部调用全局变量并对其重新定义后赋值(注意不包括增删改等修改操作但该值仅在函数内部有效,不影响函数外部该全局变量的属性和值即局部变量和全局变量的属性不变,在函数(子程序)内部局部变量生效,函数外部全局变量生效,唯一的联系是全局变量和局部变量共用了一个变量名称,但本质上是两码事。
  • 函数内部定义局部变量时,可通过global关键字将变量的作用域提升扩大到全局范围,即把局部变量转换为全局变量。但建议尽量避免使用global,原因是一旦使用,对稍微复杂些的程序而言会引起变量的混乱,给程序调试带来干扰。
  • 字符串、整数数据类型在函数内部修改(重新赋值)不覆盖全局变量的值,除此之外复杂的数据类型局部(如列表、字典、集合)变量的修改(请一定注意是修改,增删改等操作,不包括重新定义后赋值)会覆盖全局变量的值,具体原因还有待深究。

四 代码及执行结果

1 代码文件ex19.py:

# 在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数
# 定义一个函数:cheeses_and_crackers,函数的功能是打印四条语句,该函数有两个形式参数:cheese_count,boxes_of_crackers
def cheeses_and_crackers(cheese_count,boxes_of_crackers):
    print(f"You have {cheese_count} cheeses!")
    print(f"You have {boxes_of_crackers} boxes of crackers!")
    print("Man that's enough for a party!")
    print("Get a blanket.\n")

# 打印提示信息,并调用刚才定义的函数cheeses_and_crackers,此时的实际参数是数字
print("We can just give the function numbers directly:")
cheeses_and_crackers(20,30)

#定义两个变量amount_of_cheese,amount_of_crackers,在函数调用过程中把这两个变量当作实参
print("OR, we can use variables from our script:")
amount_of_cheese = 10
amount_of_crackers = 50
cheeses_and_crackers(amount_of_cheese,amount_of_crackers)

# 函数调用过程中实参也可以是表达式,该表达中只有数字
print("We can even do math inside too:")
cheeses_and_crackers(10 + 20,5 + 6)

# 函数调用过程中实参也可以是表达式,该表达中可以包括变量
print("And we can combine the two,variables and math:")
cheeses_and_crackers(amount_of_cheese + 100,amount_of_crackers + 1000)

这个练习展示了我们可以给函数 cheese_and_crackers 赋值的几种不同的方式,我们可以直接给它数字,或者变量,亦或是数学运算,甚至是数学运算和变量的结合。

从某种程度上说,函数的参数有点类似于我们给变量赋值时的 = 符号 。事实上,如果你可以用 = 来定义一个东西,你就可以把它作为参数赋给函数。

2 执行结果

PS E:\3_work\4_python\2_code_python\02_LearnPythonTheHardWay> python ex19.py
We can just give the function numbers directly:
You have 20 cheeses!
You have 30 boxes of crackers!
Man that's enough for a party!
Get a blanket.

OR, we can use variables from our script:
You have 10 cheeses!
You have 50 boxes of crackers!
Man that's enough for a party!
Get a blanket.

We can even do math inside too:
You have 30 cheeses!
You have 11 boxes of crackers!
Man that's enough for a party!
Get a blanket.

And we can combine the two,variables and math:
You have 110 cheeses!
You have 1050 boxes of crackers!
Man that's enough for a party!
Get a blanket.

五 一些问题

1 运行一个函数怎么可能有 10种不同的方式? 爱信不信,理论上讲,任何函数都有无数种调用方式。看看你对于函数、变量以及用户输入的创造力有多强2 有没有什么方法能分析函数是如何运行的,以帮助我更好地理解它? 有很多方法,但是你先试试给每行加注释这种方式。其他方法包括大声把代码读出来,或者把代码打印出来然后在上面画图,来展示它是怎么运行的。

3 如果我想问用户关于 cheese 和和 crackers 的数字呢?你需要用 int() 来把你通过 input() 获取的内容转化成数值。

4 在函数中创建 amount_of_cheese 这个变量会改变 cheese_count 这个变量吗? 不会的,这些变量是相互独立并存在于函数之外的。它们之后会传递给函数,而且是“暂时版”,只是为了让函数运行。当函数退出之后,这些暂时的变量就会消失,其他一切正常运行。接着往下学,你会慢慢明白的。

5 像 amount_of_cheese 这样的全局变量( global variables )跟函数变量同名的话是不是不太好?是的,如果这样的话,你就不知道你说的到底是哪个变量了。不过你有时候可能不得不用同样的名字,或者你可能不小心同名了,不管怎么样,尽量避免这种情况。

6 一个函数里包含的参数有数量限制吗? 这取决于 Python 的版本以及你的电脑,但是这个数量其实相当大。实践中一个函数包含 5 个参数为宜,再多就比较难用了。

7 你能在一个函数里面调用一个函数吗? 可以,在之后的练习里你会创建一个小游戏,到时候就会用到这个。

posted @ 2020-07-04 22:10  洛兰123  阅读(139)  评论(0编辑  收藏  举报