day10:函数基础知识

今日内容:
一、定义函数:
  定义函数时发生的事情
  调用函数时发生的事情
二、定义函数的三种方式和使用场景
三、调用函数的三种方式
四、函数参数
    形参
    实参
    可变长系列 * **在形参和实参中的应用
五、函数的返回值
 
 
 
引入:函数就是装代码的容器
在程序中,具备某一功能的‘工具’指的就是函数,‘事先准备工具’的过程即函数的定义,‘拿来就用’即函数的调用。
 
什么是函数?
函数:具备某一功能的工具
事先准备工具的过程----》函数的定义
遇到场景拿来就用-------》函数的调用
 
原则:先定义,后调用
为何要用函数?
1、程序的组织结构不清晰,可读性差
2、代码冗余
3、可维护性,扩展性差
 
如何用函数?
先定义:定义的语法:3种定义方式
后调用:调用的语法:3种调用方式
返回值:3种返回值的形式
 
一、定义函数:相当于造了个工厂,函数名就是地址,参数是原材料,函数体是生产流水线,值是生产出的产品
1、语法:
    def 函数名(参数1,参数2,...):
      ''''''文件描述''''''
      函数体(代码1,代码2,代码3......)
      return 值
 
  1. def: 定义函数的关键字;
  2. 函数名:函数名指向函数内存地址,是对函数体代码的引用。函数的命名应该反映出函数的功能;和变量名要求一样,最好定义为动词
  3. 括号:括号内定义参数,非必要,且无需指定参数的类型;
  4. 冒号:括号后要加冒号,然后在下一行开始缩进编写函数体的代码;
  5. """文档描述""": 描述函数功能,参数介绍等信息的文档,非必要,但是建议加上,从而增强函数的可读性;
  6. 函数体:由语句和表达式组成;
  7. return 值:定义函数的返回值,非必要

追加:

变量名对应的和函数名一样,都是内存地址与名的绑定关系,打印时按原理都会显示内存地址

但是,python只会在运行变量名时会把变量的值给显示出来

 例:
def login():
  print(111)
  print(222)
  x = 10
print(x) --------》值 10
print(login)------》名login的内存地址<function login at 0x000002ABA4B37280>

 

定义函数时,发生的事情:
1、申请内存空间保存函数体代码
2、将上述内存地址绑定给函数名
3、定义函数时不执行函数体代码,只会检查函数体语法
 
调用函数时,发生的事情:
print(func)-------》函数的内存地址
1、通过函数名找到函数的内存地址
2、加()触发函数体代码的运行(python的语法)
 
 
重点!强调!查找名字的顺序/优先级:是以定义阶段为准,与调用位置无关
例:
def func():
  print(111)
  x
  print(222)
=================定义阶段语法没有问题======================
 
func()----------》NameError: name 'x' is not defined
=============但是在调用阶段逻辑问题产生报错================
 
同上:
x = 111
  def func():
  print(x)
  x = 222
=================定义阶段语法没有问题======================
 
func()--------》UnboundLocalError: local variable 'x' referenced before assignment
=============但是在调用阶段,逻辑问题产生报错================
 
二、定义函数的3种定义方式和使用场景
方式一:无参函数,函数体不需要外部传进参数
def func():
  print('头头大')
func()
 
def interactive():
  name = input('username>>>>>:').strip()
  age = input('userage>>>>>:').strip()
  msg = '名字:{} 年龄:{}'.format(name, age)
  print(msg)
interactive()
方式二:有参函数,函数体需要外部传进参数
def add(x,y):
res = x + y
print(res)
add(10,20)
add(1,2)
 
def add(x, y): -----------》参数----》原材料
res = x + y
return res ------------》返回值--》产品
res = add(20, 30)
print(res)
 
方式三:空函数,函数体代码为pass/...把所有功能都列举出来用pass充当函数体“占位符”
使用场景:
例如要编写一个ftp程序,我们可能想到的功能有用户认证,下载,上传,浏览,切换目录等功 能,可以先做出如下定义:
def auth_user():
"""user authentication function"""
pass
 
def download_file():
"""download file function"""
pass
 
 def upload_file():
"""upload file function"""
 
pass
 
def ls():
"""list contents function"""
 
def cd():
"""change directory"""
pass
 
三、调用函数的3种方式
1、语句的形式:只加()调用函数,不做任何操作
len('hello')
 
2、表达式形式:
def add(x, y):
res = x + y
return res
赋值表达式:
res = add(1,2)
print(res)
数学表达式:
res = add(1,2)*10
print(res)
 
3、函数调用可以当做参数传给另一个函数
res = add(add(1,2),10)
print(res)
---------》就相当于把add的调用当做参数给了print
 
四、函数参数
总体分:
1、形参:在函数定义阶段括号内指定的参数(变量名)
2、实参:在函数调用阶段括号内传入的值(变量值)
 
形参和实参的关系:
在调用函数时,实参值会绑定给形参名,在调用完毕后解除绑定
 
细分:
形参系列:
1、位置形参:在定义函数时,按照从左到右的顺序依次定义的变量名
特点:每次调用,必须被赋值
def func(name,age):
  print(name)
  print(age)
 
2、默认形参:在定义函数时已经为某个形参赋值了
特点:调用函数时,可以不用为其赋值
def func(name,age=19):
print(name)
print(age)
func("jay")
func("jay",99)
 
注意:位置形参和默认形参可以混用
但是:a、位置实参必须前面
   b、默认形参的值通常应该是不可变类型,但是实际情况又需要可变
      def func(name,hobby,hobbies = None):
          if hobbies is None:
            hobbies = []
            hobbies.append(hobby)
          print('%s的爱好是%s' %(name,hobbies))
 
      func('jay','music')
      func('didi','computer')
      func('toushao','drink',['many woman'])
 
    c、默认形参的值是在函数定义阶段赋值的
      m=111
      def func(x,y,z=m):
        print(x)
        print(y)
        print(z)
        m=666
      func(1,2)
        ------------------->1
               2
               111
实参系列:
1、位置实参:在调用函数时,按照从左到右的顺序依次传入的值
特点:按照位置为形参赋值,一 一对应
func('jay',19)
 
2、关键字实参:按照key=value的形式赋值
特点:可以打乱顺序,但是仍然能够给指定的形参赋值
func(age = 19,name = 'jay')
 
注意:位置实参和关键字实参可以混用
但是:a、位置实参必须在关键字实参前面
    func('jay',age=19)------>成立
    func(age=19,'jay')------>报错
   b、不能为同一形参重复赋值
    def foo(x,y,z):
      pass
    foo(1,y=2,3) ---------->报错
    foo(1,y=2,z=3,x=4)----->报错
 
3、可变长系列:
可变长参数:***
在调用时,传入的实参个数不固定,对应必须有特殊模式的形参来接收溢出的实参
 
==================*与**在形参中是一种汇总行为=====================
1、*在形参中的应用:*会将溢出的位置实参合并成一个元组,然后赋值给紧跟其后的形参名
def func(x,*args): # y = (2,3,4,5)
  print(x)
  print(args)
  func(1,2,3,4,5)
 
def num(*args):
  res = 0
  for i in args:
  res += i
  print(res)
  num(1,9)
 
2、**在形参中的应用:**会将溢出的关键字实参合并成一个字典,然后赋值给紧跟其后的形参名
def func(x,**kwargs): # kwargs = {"a":2,"c":4,"b":3}
  print(x)
  print(kwargs)
 
func(1,a=2,b=3,c=4)
 
==================*与**在实参中是一种打散行为=====================
 
1、*在实参中的应用:*后可以跟可以被for循环遍历的任意类型,*会将紧跟其后的那个值打散位置实参
def func(x,y,z):
  print(x)
  print(y)
  print(z)
 
func([11,22,33])
func(*[11,22,33]) # func(11,22,33)
func(*"hello") # func("h","e","l","l","o")
func(*{"k1":111,"k2":2222}) # func("k1","k2")
 
2、**在实参中的应用:**后只能跟字典类型,*会字典打散关键字实参
func(**{"k1":111,"k2":2222}) # func(k2=2222,k1=111)
func(**{"x":111,"y":2222,"z":333})
 
例:重在理解
def index(x,y,z):
  print(x,y,z)
 
def wrapper(*args,**kwargs): # args=(1,2,3,4,5,6) kwargs={"a":1,"b":2,"c":3}
index(*args,**kwargs) # index(*(1,2,3,4,5,6),**{"a":1,"b":2,"c":3})
# index(1,2,3,4,5,6,a=1,b=2,c=3)
# wrapper(1,2,3,4,5,6,a=1,b=2,c=3)
wrapper(1,2,3,4,5,6,a=1,b=2,c=3)
 
(了解)命名关键字形参: 在*与**中间的形参
特点: 必须按照key=value的形式传值
def func(x,m=333,*args,y=222,z,**kwargs):
  print(x)
  print(args)
  print(y)
  print(z)
  print(kwargs)
 
func(1,2,3,z=4,a=1,b=2,c=3)
func(1,2,3,4,5,6,7)
 
 
五、函数返回值
return
函数结束的标志,即函数代码一旦运行到return会立刻终止函数的运行,并且会将return后的值当做本次运行的结果返回
 
返回值有三种情况:
1、返回None:函数体内没有return
return
return None
2、返回一个值:return 值
3、返回多个值 值1,值2,值3:用逗号分隔开多个值,会被return返回成元组
def func():
  return 10,'aaa',[1,2]
  res = func()
print(res,type(res))--------》(10, 'aaa', [1, 2]) <class 'tuple'>

posted @ 2020-12-28 18:08  Seven_1130  阅读(891)  评论(0)    收藏  举报