Python基础知识-09-函数

 

python其他知识目录

1、函数介绍

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()
。但你也可以自己创建函数,这被叫做用户自定义函数。

def 函数名(参数列表):
     函数体d
函数名(参数)
函数名(参数)

2、函数使用优缺点:

公司随随便便几百上千行。可读性,重用性,函数,面向过程编程
优点:
缺点:
面向过程,可以将可重复性的代码做成一个函数,用参数代替变化的量,实现具有重复性操作的功能。
当事物需要做这个操作的时候,调用函数即可实现功能。#自己理解
#发邮件:设置里面开启pop3,smtp服务器 ,往smtp服务器发邮件
比如发邮件,很多对象都使用的一个动作,写成函数,调用函数。避免代码冗余。
什么情况写函数,就是为了能重复使用某个功能,就写成函数,一个功能一个函数。或者是为了方便阅读,增加代码可读性
函数式编程是做什么的?避免重复性代码。代码拆分,增强可移植性,可读性

本质:将N行代码拿到别处并给他起个名字,以后通过名字就可以找到这段代码并执行。
场景:代码重复执行。
代码量特别多超过一屏,可以选择通过函数进行代码的分割。

3、函数定义:

你可以定义一个由自己想要功能的函数,以下是简单的规则:
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
函数内容以冒号起始,并且缩进。
return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None

语法:
Python 定义函数使用 def 关键字,一般格式如下:

def 函数名(参数列表):
    函数体

默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

函数执行:
def xiaoma():
print("魔降风云变")
xiaoma()
---------结果:
魔降风云变

4、函数调用

定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。

这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从 Python 命令提示符执
行。
函数不调用,内部代码不执行。调用后用不用变量接收返回值,函数都会执行。

def xiaoma():
    print("魔降风云变")
xiaoma()
---------结果:
魔降风云变

def xiaoma():
    print("魔降风云变")
a=xiaoma()
----------结果:
魔降风云变

def xiaoma():
print("魔降风云变")

def mcw():        #函数调用函数
print("我是:")
xiaoma()
mcw()
--------------结果:
我是:
魔降风云变

5、函数传参

5.1、函数传参简介

不同的对象做相同的操作,可以定义函数。如果每个对象还有些区别,那么有区别的地方使用函数传参

定义带参数的函数的时候
函数式编程。通过传参,返回不同的值,返回不同的参数。同一个功能不同的地方就使用传参
形式参数(形参):形参就是形式上的参数,可以理解为数学的X,没有实际的值,通过别人赋值后才有
意义。相当于变量。
实际参数(实参):实参就是实际意义上的参数,是一个实际存在的参数,可以是字符串或是数字等

函数里面使用字符串格式化
函数可以定死了,也可以传递变量。写函数不一定需要参数。如果有变的,使用参数,没有变的就定死
了就可以,看实际情况了。


def eat(arg1,arg2):
print("%s喜欢吃%s"%(arg1,arg2))
eat("小马过河","米饭")
eat("小明","面条")
-----------结果:

小马过河喜欢吃米饭
小明喜欢吃面条

5.1没有函数传参
案例1:
使用函数只计算某一个列表内元素的和:
def list_sum():
    li = [1, 2, 3]
    sum=0
    for i in li:
        sum+=i
    print(sum)
list_sum()
-----------结果
6

5.2一个函数传参:
案例2:
使用函数计算指定列表内元素的和:
def list_sum(li):
    sum=0
    for i in li:
        sum+=i
    print(sum)
info=[1,2,3]
list_sum(info)
-------------结果:
6

报错问题1:
报错:函数没有形参,调用函数时带着参数的报错:
def list_sum():
    sum=0
    for i in li:
        sum+=i
    print(sum)
info=[1,2,3]
list_sum(info)      #调用时,可以直接做参数,也可以用变量做实参
-------------------结果:
list_sum(info)
TypeError: list_sum() takes 0 positional arguments but 1 was given

5.3多个函数传参:
def xiaoma(arg1,arg2):
    print(arg1+arg2)
xiaoma(2,3)
-----------结果:
5

报错问题2:传参传少了
def xiaoma(arg1,arg2):
    print(arg1+arg2)
xiaoma(2)
-----------结果:
    xiaoma(2)
TypeError: xiaoma() missing 1 required positional argument: 'arg2'

报错问题3:传参传多了
def xiaoma(arg1,arg2):
    print(arg1+arg2)
xiaoma(2,3,4)
------------结果:
  xiaoma(2,3,4)
TypeError: xiaoma() takes 2 positional arguments but 3 were given

严格按照顺序来传参数,按位置一一对应。

5.2基本参数知识

  • 任意个数
  • 任意类型
def func(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8):
    print(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
func(1,False,None,"mcw",["xiaoma","1"],(1,2),{"name":"xiaoma"},{3,4})
------结果:
1 False None mcw ['xiaoma', '1'] (1, 2) {'name': 'xiaoma'} {3, 4}

 5.3、位置传参(调用函数并传入参数)【执行】

位置传参:根据位置意义对应传递参数

def func(a1, a2):
    print(a1, a2)
func(1, 3)
------------结果:
1 3

5.4关键字传参【执行】

关键字传参:指定形参接收实参

def func(a1, a2, a3):
    print(a1, a2, a3)
func(1,2,a3=9)          
func(1,a2=2,a3=9)
func(a1=1,a2=2,a3=9)
------------------结果:
1 2 9
1 2 9
1 2 9

def func(a1, a2, a3):
    print(a1, a2, a3)
func(a1=1,2,3) # 错误
-------------结果:
SyntaxError: positional argument follows keyword argument
follows关键字定位论点论据

5.5默认参数【定义】

使用场景:定义函数默认参数,方便

指定形参等于什么参数,如果没有接收到实参,那么函数就使用默认参数

def func(a1,a2,a3=9,a4=10):      #a3默认9,a4默认10,调用时可以传可以不传。;给默认传参传了参数就用传进函数的参数,否则用的默认参数。比如open函数有默认的参数。
print(a1,a2,a3,a4)
func(11,22)
func(11,22,10)
func(11,22,10,100)
func(11,22,10,a4=100)
func(11,22,a3=10,a4=100)
func(11,a2=22,a3=10,a4=100)
func(a1=11,a2=22,a3=10,a4=100)
-------------------结果:
11 22 9 10
11 22 10 10
11 22 10 100
11 22 10 100
11 22 10 100
11 22 10 100
11 22 10 100

5.6万能参数(打散)

*args:传递多个实参给形参*args,并让函数以元组的形式来接收外部传参

        -  实参前面加*号,将实参内的每个元素传到*args元组中,而非实参本身。

*kwargs:传递多个键值对或字典给*kwargs,并且在函数内以字典的形式存在

         -  实参字典前面加**给*kwargs,会将实参内每个键值对添加到*kwargs字典中,而非实参字典本身

  • *args

    • 可以接受任意个数的位置参数,并将参数转换成元组。

    • *args只能接收n个参数。传入多个实参时,都放到args这个元组里面。如果传入元组参数,那么元组作为args的单个元素。如果*(),实参元组前面有*,那么实参元组内的每个元素都放到形参构成的元组内,即形参

    • 构成的元组内是实参内的各个元素。只能位置传参,不能关键字传参#假设可以关键字传参,那么设定之后,它后面就接收不了参数 

    • 了,所以不可以做关键字传参

    • 使用场景:不确定需要传参个数的时候使用万能参数。

      • 调用函数无 *

        def func(*args):
            print(args)       #*args只能接收n个参数。传入多个实参时,都放到args这个元组里面。
        func(1,2,3,4)
        -------------------结果:
        (1, 2, 3, 4)
        def func(*args):
        print(args) #如果传入元组参数,那么元组作为args的单个元素。
        func((1,2),(3,4))
      • 调用函数有 *

        def func(*args):
            print(args)
        func(*(1,2,3,4))         #如果*(),实参元组前面有*,那么实参元组内的每个元素都放到形参构成的元组内,即形参
        func(*[1,2,3,4])
        -----------------------结果:
        (1, 2, 3, 4)
        (1, 2, 3, 4)

        def func(*args):  #函数内print星号和不print星号的区别
        print(args)
        print(*args)
        func(1,2,3,4)
        ---------结果:

        (1, 2, 3, 4)
        1 2 3 4

    • 只能用位置传参

      def func(*args):
          print(args)
      func(1)
      func(1,2) # args=(1, 2)
      func((11,22,33,44,55)) # args=((11,22,33,44,55),)
      func(*(11,22,33,44,55)) # args=(11,22,33,44,55)
      -----------------------结果:
      (1,)
      (1, 2)
      ((11, 22, 33, 44, 55),)
      (11, 22, 33, 44, 55)
  • **kwargs

    • 可以接受任意个数的关键字参数,并将参数转换成字典。

      • 调用函数无 **

        def func(**kwargs):
            print(kwargs)
        func(k1=1,k2="mcw")
        ------------------------结果:
        {'k1': 1, 'k2': 'mcw'}
      • 调用函数有**

        def func(**kwargs):
            print(kwargs)
        func(**{'k1':'v2','k2':'v2'}) # kwargs={'k1':'v2','k2':'v2'}
        ---------------------------------结果:
        {'k1': 'v2', 'k2': 'v2'}
    • 只能用关键字传参

    • 综合应用:无敌 + 无敌 => 真无敌

      def func(*args,**kwargs):
          print(args,kwargs)
      func(1,2,3,4,5,k1=2,k5=9,k19=999)
      func(*[1,2,3],k1=2,k5=9,k19=999)
      func(*[1,2,3],**{'k1':1,'k2':3})
      func(111,222,*[1,2,3],k11='alex',**{'k1':1,'k2':3})
      ------------------------结果:
      (1, 2, 3, 4, 5) {'k1': 2, 'k5': 9, 'k19': 999}
      (1, 2, 3) {'k1': 2, 'k5': 9, 'k19': 999}
      (1, 2, 3) {'k1': 1, 'k2': 3}
      (111, 222, 1, 2, 3) {'k11': 'alex', 'k1': 1, 'k2': 3}

5.7、混合传参

def func(a1,*args)
func(1,2,3) 传了1给a1,后面给args

def func(a1,*args,a2) 混搭
func(1,2,3,a2=4)

def func(a1,*args,a2=10) 混搭 a2只能靠关键字来传与上同。
func(1,2,3,a2=4)

def func(a1=2,*args,a2) #混搭 错误方式
func(1,2,3,a2=4)

def func(**kwargs) #传多个键值对到函数,实参为键=值 #万能,传n个关键字参数。并将参数转换
为字典
func(k1=1,k2="s")

def func(**kwargs): #kwargs={k1=1,k2="s"} #传字典到函数内 **字典
print(kwargs)
func(**{"k1":1,"k2":"s"})
-------------结果:
{'k1': 1, 'k2': 's'}

def func(**kwargs) #kwargs={k1:{"m":"c"},k2:"s"} #将键值对和字典一起传到函数内,
func(k1={"m":"c"},k2="s")

5.8、传参使用场景总结:

  1、我想要简单点的基本传参,用位置传参;
  2、我传参想让谁接收,用关键字传参。               
  3、我没传参想让形参有个默认值,用默认传参;
  4、我要传递多个参数,用一个*号的接收;
  5、我要传递多个键值对或字典,用两个**接收。

函数:增加代码重用性,可读性。
比如去楼下拿快递,是个函数,告诉他拿**的快递,他就拿到**的快递

6、函数返回值return

1) print 和 return 的区别,print 仅仅是打印在控制台,而 return 则是将 return 后面的部分作
为返回值作为函数的输出,可以用变量接走,继续使用该返回值做其它事。
2)函数需要先定义后调用,函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句
,其实它有一个隐含的 return 语句,返回值是 None,类型也是 'NoneType'。
3)return作用:结束函数调用、返回值
4)终止函数的方法:满足某个条件 return False

成功与不成功返回一个结果。如果不需要打印,用户只需要某个结果,那么让函数返回一个值,让用户
根据返回值做对应的操作。return实现函数返回值。
调用函数,并用变量接收函数的返回值。

6.1使用变量接收返回值:

def xiaoma():
    a=1
    return a
mcw=xiaoma()
print(mcw)
------------结果
1

6.2用户根据函数返回值做别的操作。(根据返回值进行通信)

#当小明吃完饭,给我返回1。小明吃完后小马过河找他玩

def xiaoming(arg):
    a=0
    if arg=="吃完":
        a=1
    return a
status=xiaoming("吃完")
if status==1:
    print("小马过河去找小明玩")
--------------结果:
小马过河去找小明玩

6.3返回多个值的方法:

如果程序需要有多个返回值,则既可将多个值包装成列表之后返回,也可直接返回多个值。如果 Python
函数直接返回多个值,Python 会自动将多个返回值封装成元组。多个值用逗号隔开。

1)python 函数使用 return 语句返回 "返回值",可以将其赋给其它变量作其它的用处

2)所有函数都有返回值,如果没有 return 语句,会隐式地调用 return None 作为返回值

3)一个函数可以存在多条 return 语句,但只有一条可以被执行,如果没有一条 reutrn 语句被执行,同样会隐式调用 return None 作为返回值

4)如果有必要,可以显式调用 return None 明确返回一个None(空值对象)作为返回值,可以简写为 return

5)如果函数执行了 return 语句,函数会立刻返回,结束调用,return 之后的其它语句都不会被执行了

def list_sum(li):
    sum=0
    e_str=""
    for i in li:
        e_str+=str(i)
        sum+=i
    return sum,e_str
li=[1,2,3]
mcw=list_sum(li)  # 获取list_sum函数返回的多个值,多个返回值被封装成元组
v1,v2=list_sum(li)               #此外,也可使用 Python 提供的序列解包功能,直接使用多个变量接收函数返回的多个值。
print(mcw)
print(v1,v2)
---------------结果:
(6, '123')
6 123

6.4return终止循环

def mcw():       #没有return的时候,返回值默认是None,循环正常结束。
    for i in range(1,4):
        print(i)
m=mcw()
print(m)
-------------结果:
1
2
3
None

def mcw():    #有return的时候,返回指定的值,并终止函数向后继续执行了。
    for i in range(1,4):
        if i==3:
            return "终止函数了"
        print(i)
m=mcw()
print(m)
-------------结果:
1
2
终止函数了

6.5、直接打印返回值

def mcw():
    return "魔降风云变"
print(mcw())

6.6 for .. else .. 语句 (意外终止情况)

# 表示如果 for 语句段的内容正常循环结果才会执行 else 段的语句,如果 for 在循环过程中时被 break 或者 return 语句意外终止循环,就不会执行 else 段中的语句。

6.7、return可以返回任意类型。

#假如需要函数返回字典,列表等,就可以给函数调用的时候使用。

retrue 一个数据类型。

def func(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8):
return (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
print(func(1,False,None,"mcw",["xiaoma","1"],(1,2),{"name":"xiaoma"},{3,4}))
-------------------结果:
(1, False, None, 'mcw', ['xiaoma', '1'], (1, 2), {'name': 'xiaoma'}, {3, 4})

6.8、if判断使用返回值的三种方式:

def func(a1,a2):
    if a1>a2:
        return a1
    else:
        return a2
def func(a1,a2):
    return a1 if a1>a2 else a2
def func(a1,a2):
    b=a1 if a1>a2 else a2
    return b

 6.9可利用返回值True和默认的返回值None做函数返回的判断

def func(arg1):
    if arg1==1:
        return True
print(func(0))
-----------结果:
None

6.10其他的返回值,非函数返回值总结

li=[1,2]
print(li.append(3))      #没有返回值就是None吗?
---------------结果:
None

li=[1,2]
m=li.append(3)               
print(m)
-----------结果:
None

a="mcw"
a="*".join(a)
print(a)
----------------结果:
m*c*w

总结:列表所有方法基本上都是返回None,字符串的所有方法基本上是返回新值

7、函数作用域

7.1全局作用域

  • py文件:全局作用域

  • 函数:局部作用域

  • 变量先创建才能再使用。
  • 函数也可以看做一个变量,指向一堆代码
  • 作用域中的数据归自己所有,别人访问不到,局部作用域可以继承全局作用域 
  • 函数调用全局变量,可以使用在函数调用之前的环境变量,但是不可以使用函数调用之后的
  • print(func) 返回的地址
    print(func()) 返回调用值

  • a = 1
    def s1():
        x1 = 666
        print(x1)
        print(a)
        print(b)
    
    b = 2
    print(a)
    s1()
    a = 88888
    def s2():
        print(a,b)
        s1()
    
    s2()
    ---------------------结果:
    1
    666
    1
    2
    88888 2
    666
    88888
    2
     
  • 总结:

    • 一个函数一个作用域,(其他语言很多是一个代码块一个作用域

    • 作用域中查找数据的规则,优先在自己作用域寻找,自己没有就去父集作用域中寻找,父集没有再不断往上层的父集去找。直到全局作用域,再没有就报错。

    • 父集无法使用子集的变量。子集可以不断往外层的父集寻找变量
    • 1、找变量,本层没有,2、去上一级作用域中,找调用本函数之前最后赋值的那个变量,3、如果到达全局环境变量后还没有就会报错。如果没有到达环境变量,请执行第2步。
    • globla 找到全局   找到后可以给全局变量重新赋值,
      nonloacl 找到上级,找到后可以给上级变量重新赋值。

    • 作用域每层都是有自己独立的内部空间的,子能继承父,但不能重新赋值父,需要借助global和nonlocal。#思考(不确定的问题):有global和nonlocal找到父所在空间,重新开辟空间进行赋值,否则开辟的是自己所在的空间吗?

    • def func():
          x = 9
          print(x)
      func()
      print(x)         #函数内部能使用内部变量,但是函数外部不能使用函数内部变量
      -------------结果:
      9
      Traceback (most recent call last):
        File "D:/aPython_full目录/小马过河的代码练习/mcwday09.py", line 269, in <module>
          print(x)
      NameError: name 'x' is not defined

 

作用域中查找数据规则:优先在自己的作用域找数据,自己没有就去 "父级" -> "父级" -> 直到全局,全部么有就报错。注意:父级作用域中的值到底是什么?

x = 10
def func():
    x = 9
    print(x)
func()
---------------结果:
9

globla 找到全局 找到后可以重新赋值,
nonloacl 找到上级,找到后后面重新赋值
函数能修改函数外部可变数据类型如列表,集合,字典,但是默认是无法重新赋值的。
如果一定要在函数中给环境变量重新赋值,使用gloabal 变量。子作用域重新赋值全局变量
如果是子函数中使用global重新赋值,改的也是全局
nonloacl改的是父集,上一层的变量。
尽量不要修改全局。会造成代码出现问题
全局变量都是使用大写。局部变量正常的就行了。方便阅读。潜规则。

7.2、global语句

 https://www.jb51.net/article/147644.htm

https://blog.csdn.net/weixin_37583747/article/details/81262859

7.3、nonlocal语句

 8、lambda函数(匿名函数)

8.1、lambda函数简介

python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

8.2、lambda 函数语法

lambda 函数的语法只包含一个语句,如下:

lambda [arg1 [,arg2,.....argn]]:expression

8.3、

lambda 为了解决简单函数的情况。运算相当于简单函数编写方式。这样函数就相当于一个变量
一行表示,所以不定义变量,使用上一层作用域的变量
变量名=lambda 参数(有无*/**):操作或者函数返回值(返回值可为表达式,为三元运算;表达式有返回的就
作为返回值,否则返回None)

表达式1:
没有参数,只返回指定值
有一个参数,返回表达式
有*和**的参数,举例比如返回*和**长度和
lambda 表达式结合三元运算,返回值部分使用三元运算。
多个lambda放入列表。调用lambda.

9、函数中高级使用  高阶函数

9.1、函数可以作为变量来使用

1
def func():
    print("mcw")
v1 = func  #将函数名赋予一个变量,再给变量加上小括号便能代替原函数名执行这个函数。函数名指

向函数体的内存位置
func()  #
v1()
-------------结果:
mcw
mcw

由上面那个函数打印可知,函数名赋予给变量后,他们都是指向一个内存地址,函数()代表函数返回值

,默认为None。
print(type(func),type(func()),func,func())
print(type(v1),type(v1()),v1,v1())
------------结果:
123
123
<class 'function'> <class 'NoneType'> <function func at 0x00A28D20> None
123
123
<class 'function'> <class 'NoneType'> <function func at 0x00A28D20> None
2)函数名可以放入列表等数据类型,调用函数时加上小括号
def func():
    print(123)
func_list = [func, func, func]
func_list[0]()
-----------结果:
123

def func():
    print(123)
func_list = [func, func, func]
for item in func_list:        循环函数列表并打印函数返回值
    v = item()
    print(v)
----------------结果:
123
None
123
None
123
None

3)函数名作为字典的值来用,(不建议当做键来用,没啥意义)。
def func():
    print(123)
def bar():
    print(666)
info = {'k1': func, 'k2': bar}
info['k1']()
info['k2']()
------------------结果:
123
666

4)容易弄错的案例:
def func():
    return 123
func_list1 = [func,func,func]
func_list2 = [func(),func(),func()]
print(func_list1)
print(func_list2)
info = {
    'k1':func,
    'k2':func(),
}
print(info)
------------------结果:
[<function func at 0x00648D20>, <function func at 0x00648D20>, <function func at 

0x00648D20>]        #func函数名是指向函数的地址
[123, 123, 123]     # func()是函数返回值。这里指定返回值为123
{'k1': <function func at 0x00648D20>, 'k2': 123}  

)综上可知:
def func():
    print("mcw")
v1 = func 

函数名实质上就是函数的内存地址。

当我们定义a=1的时候,系统会开辟一块内存空间来保存1,然后用a变量名保存1所在的内存地址引用,变量名就好像C语言中的指针,大家可以把引用理解成地址,a里面存的是1这个数值所在的地址,a存了1的引用。当我们在代码中定义了一个函数,系统会分配一块内存空间,用于保存函数体的内部变量和函数名,这个v1只是一个变量名,保存了函数内存中的地址,我们可以v1=func,v2=func.这样的操作就相当于把func中引用的地址,赋值给v1,v2 ,这样v1和v2都指向了func函数所在的引用,我们可以v1()和v2()来
调用func函数,调用实际上是一个函数,而v1,v2,func三个变量存了同一个函数的地址。

9.2、函数可以当作参数进行传递

1
def func(arg):
    print(arg)
def show():
    return 999
func(show)
----------结果:
<function show at 0x00598D20>  #将show函数作为参数传到func函数,结果为print(show),show这个

函数名指向内存地址

2
def func(arg):
    v1 = arg()
    print(v1)
def show():
    print(666)
func(show)
---------------结果:
666
None
#函数执行分析:将函数名show作为func的参数,执行函数后,arg()会让show函数执行并打印666,然后

将show函数执行的默认返回结果赋予变量v1,打印出v1的值。
3
def func(arg):
    v1 = arg()
    print(v1)
def show():
    print(666)
result = func(show)
print(result)
---------------结果:
666
None
None
#函数执行分析:将函数名show传参给func函数,然后show会在func内执行,打印666,并将默认返回值

赋予变量v1并打印。func函数执行返回默认值None并将值赋予变量result,然后打印result
4)函数传参功能的使用案例。
(指定用户输入选项,并将每个选项的功能写成函数,然后将函数做成字典,根据用户输入执行不同的函数,实现不同的功能) def func(): print(
'花费查询') def bar(): print('语音沟通') info = { 'f1': func, 'f2': bar, } choice = input('请选择要选择功能:') function_name = info.get(choice) if function_name: function_name() else: print('输入错误') ---------------结果: 请选择要选择功能:f1 花费查询

9.3、函数可以做返回值来使用

1)没有
def func():
    print(123)
def bar():
    return func
v = bar()
v()
-----------结果:
123
#函数执行分析:函数bar执行后返回另一个函数名func,将函数名赋值给变量v,v()执行函数就等于func()执行func函数,即打印出123(原因:赋值后,v和func指向同一个函数)
2)返回另一个函数名并赋值给变量
name = 'mcw'
def func():
    print(name)
def bar():
    return func
v = bar()
v()
--------------结果:
mcw
#函数执行分析:执行bar函数的返回值(func函数名)赋给变量v。执行v也是执行func函数,打印变量name,func当前作用域没有变量name,于是去上级作用域中找到并打印出来。
3)返回子函数名并赋值给变量
def bar():
    def inner():
        print(123)
    return inner
v = bar()
v()
----------结果:
123
#函数执行分析:执行bar函数返回inner,并将子函数名赋值给变量v,执行函数v就是执行函数inner,

并打印出123.
4)返回值为子函数结合作用域
name = 'xiaoma'
def bar():
    name = 'mcw'
    def inner():
        print(name)
    return inner
v = bar()
v()
------------------结果:
mcw
#函数执行分析:执行函数bar,将返回值inner函数名赋值给变量v,调用v即执行inner函数(二者执行同一个函数)。inner当前作用域没有变量name,那么先从上一级作用域中去找。

name = 'mcw'
def bar(name):
    def inner():
        print(name)
    return inner
v1 = bar('yh') # { name=yh, inner }  # 闭包,为函数创建一块区域(内部变量供自己使用),为他

以后执行提供数据。
v2 = bar('syn') # { name=syn, inner }
v1()
v2()
-----------------结果:
yh
syn
#函数执行分析:[1]执行bar函数并传入参数yh后,系统会创建一个独立的内存空间给函数bar,然后将返回值inner子函数名赋值变量v1。如果bar函数内的资源没有人占用那么就会销毁,而这里由于函数的资源还有变量v1在使用所以没有销毁。[2]再次执行函数bar,并传入参数syn,分析与第一步相同。[3]两次调用同一个函数,但是两次开辟的内存空间都是独立的,传入的参数也是不同的,并且在各自的内存空间中。当执行v1的时候,就是执行inner子函数,变量还是找v1所在的函数空间,即打印yh。当执行v2的时候,就是执行inner子函数,变量还是找v2所在的函数空间,即打印syn。
5)解释闭包现象
def bar(name):
    def inner():
        print(name)
    return inner()  #没有闭包,函数已经执行完毕
v1 = bar('yh')
#
空间不释放,还被引用,空间还存在东西,没有传参也是闭包,函数执行终止了,内存还没有释放,。
怎样不是闭包,返回子函数返回值,子函数已经执行完毕没人使用它的资源

9.4函数闭包问题

函数名指向函数代码,每次执行此函数,新开辟一份空间,(将代码复制过来)。所以多次执行此函数
互不影响,它们有各自的空间。如果返回的值正在被调用,函数的这个空间不销毁,调用之后才销毁
看函数是由谁创建的,谁那里有函数的入口

name = 'mcw'
def bar(name):
    def inner():
        print(name)
    return inner
v1 = bar('yh') # { name=yh, inner }  # 闭包,为函数创建一块区域(内部变量供自己使用),为他

以后执行提供数据。
v2 = bar('syn') # { name=syn, inner }
v1()
v2()
----------------结果:
yh
syn
#函数执行分析:[1]执行bar函数并传入参数yh后,系统会创建一个独立的内存空间给函数bar,然后将返回值inner子函数名赋值变量v1。如果bar函数内的资源没有人占用那么就会销毁,而这里由于函数的资源还有变量v1在使用所以没有销毁。[2]再次执行函数bar,并传入参数syn,分析与第一步相同。[3]两次调用同一个函数,但是两次开辟的内存空间都是独立的,传入的参数也是不同的,并且在各自的内存空间中。当执行v1的时候,就是执行inner子函数,变量还是找v1所在的函数空间,即打印yh。当执行v2的时候,就是执行inner子函数,变量还是找v2所在的函数空间,即打印syn。

 

10、Python内置函数的了解

Python 解释器内置了很多函数和类型,您可以在任何时候使用它们。以下按字母表顺序列出它们。

  内置函数  
abs() delattr() hash() memoryview() set()
all() dict() help() min() setattr()
any() dir() hex() next() slice()
ascii() divmod() id() object() sorted()
bin() enumerate() input() oct() staticmethod()
bool() eval() int() open() str()
breakpoint() exec() isinstance() ord() sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()  

 

  •  自定义函数

  • 内置函数

    • 其他

    • len open  range  id  type  
    • 输入输出

    • print  input
    • 强制转换

    • dict() list()  tuple()   int()  str()  bool()  set()  
    •  数学相关

      • abs,绝对值

        print(abs(1),abs(-1),abs(0))
        -------结果:
        1 1 0
      • float,转换成浮点型(小数)

        print(float(3),float(0),float(2.5))
        ----------结果:
        3.0 0.0 2.5
      • max,找到最大值

        mcw=[2,1,4,3]
        print(max(mcw),min(mcw),sum(mcw))
        -----------结果:
        4 1 10
      • min,找最小值

        mcw=[2,1,4,3]
        print(max(mcw),min(mcw),sum(mcw))
        -----------结果:
        4 1 10
      • sum,求和

        mcw=[2,1,4,3]
        print(max(mcw),min(mcw),sum(mcw))
        -----------结果:
        4 1 10
        • divmod,两数相除的商和余数

          a,b = divmod(1001,5)
          print(a,b)
          # 练习题  请通过分页对数据进行展示
          """
          要求:
              每页显示10条数据
              让用户输入要查看的页面:页码
          """
          USER_LIST = []  #此处生成列表元素[{'name': '魔降风云变-1', 'email': '12337@qq.com'},{'name': '魔降风云变-2', 'email': '12337@qq.com'}。。。。。]
          for i in range(1,836):
          temp = {'name':'魔降风云变-%s' %i,'email':'123%s@qq.com' %i }
          USER_LIST.append(temp)
          def paging(num,data_list):
          """
          实现分页功能
          :param num: 传入分页后每页显示的内容
          :param data_list: 传入列表,将每个列表元素分页展示出来
          """
          total_count = len(data_list) # 数据总条数
          per_page_count= num # 每页显示10条
          max_page_num,a = divmod(total_count,per_page_count) # 总页码数
          if a>0:
          max_page_num += 1
          while True:
          try:
          page = int(input('要查看第几页:'))
          except Exception as e:
          print("输入有误!")
          if page < 1 or page> max_page_num:
          print('页码不合法,必须是 1 ~ %s' %max_page_num )
          else:
          start = (page-1) * per_page_count
          end = page * per_page_count
          data = data_list[start:end]
          for item in data:
          print(item)
          paging(4,USER_LIST)
          ------------------------------结果:

          要查看第几页:4
          {'name': '魔降风云变-13', 'email': '12313@qq.com'}
          {'name': '魔降风云变-14', 'email': '12314@qq.com'}
          {'name': '魔降风云变-15', 'email': '12315@qq.com'}
          {'name': '魔降风云变-16', 'email': '12316@qq.com'}
          要查看第几页:10000
          页码不合法,必须是 1 ~ 209
          要查看第几页:
          输入有误!
          页码不合法,必须是 1 ~ 209
          要查看第几页:10
          {'name': '魔降风云变-37', 'email': '12337@qq.com'}
          {'name': '魔降风云变-38', 'email': '12338@qq.com'}
          {'name': '魔降风云变-39', 'email': '12339@qq.com'}
          {'name': '魔降风云变-40', 'email': '12340@qq.com'}

           

          #总结:

    • 进制转换相关

      • bin,将十进制转化成二进制

        print(bin(4),bin(256))     #将十进制转换为二进制
        ----------结果:
        0b100 0b100000000
      • oct,将十进制转换成八进制

        print(oct(3),oct(8),oct(18))    #十进制转换为8进制
        ------------结果:
        0o3 0o10 0o22
      • int,将其他进制转化成十进制

        a="0b1001"
        b="0o5"
        c="0xA"
        print(int(a,base=2),int(b,base=8),int(c,base=16))
        --------------结果:
        9 5 10
        
        
        a=0b1001
        b=0o5
        c=0xA
        print(int(a,base=2),int(b,base=8),int(c,base=16))
        -----------------结果:
            print(int(a,base=2),int(b,base=8),int(c,base=16))
        TypeError: int() can't convert non-string with explicit base
        
        a=0b1001
        print(type(a))
        b=0o5
        c=0xA
        print(int(a),int(b),int(c),type(a))
        ----------------结果:
        <class 'int'>
        9 5 10 <class 'int'>
        综上:
        类似数字类型转换为十进制:int(0o**),int(0x**),int(0b**) #不用加base参数
        字符串类型转换为十进制s             #要加base参数
      • hex,将十进制转换成十六进制

        print(hex(9),hex(10),hex(16),hex(20))  #将十进制转换为16进制
        -----------------------结果:
        0x9 0xa 0x10 0x14
      • 一道进制转换的题

        # 1字节等于8位
        # IP: 192.168.12.79  ->  001010010 . 001010010 . 001010010 . 001010010
        
        # 1. 请将 ip = "192.168.12.79" 中的每个十进制数转换成二进制并通过,连接起来生成一个新的字符串。
        
        ip="192.68.12.79"
        li=ip.split(".")
        li2=[]
        for i in li:
            # li2.append(str(bin(int(i))))
            li2.append(bin(int(i)))
        print(",".join(li2))
        -----------------结果:
        0b11000000,0b1000100,0b1100,0b1001111
        # 2.请将ip=192.168.12.79中的四个十进制数转换成二进制,将四个二进制数拼接成一个二进制数并转换为 十进制。(注意:12转换为二进制位数不满8位)
        # 0010100100001010010001010010001010010 -> 十进制的值。
        ip="192.168.12.79"
        li=ip.split(".")
        li2=[]
        for i in li:
            m=str(bin(int(i))).lstrip("0b")
            m="0"*(8-len(m))+m
            li2.append(m)
        mcw="".join(li2)
        print(int(mcw,base=2))
        ----------------结果:
        3232238671

bow使用:

1)函数有两个必需参数x,y和一个可选参数z,结果返回x的y次幂乘(相当于x**y),如果可选参数z有传入值,则返回幂乘之后再对z取模(相当于pow(x,y)%z)。
v1=pow(2,3)
v2=2**3
v3=pow(2,3,5)
v4=pow(2,3)%5
print([v1,v2,v3,v4])
----------------结果:
[8, 8, 3, 3]
2、所有的参数必须是数值类型
print(pow("3","2"))
----------结果:
print(pow("3","2"))
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'str'
3、如果x,y有一个是浮点数,则结果将转换成浮点数。
print(pow(3.0,2))
--------------结果:
9.0
4、如果x,y都是整数,则结果也是整数,除非y是负数;如果y是负数,则结果返回的是浮点数,浮点数不能取模,所有可选参数z不能传入值。
>>> pow(10,2)
100
>>> pow(2,4)
16
>>> pow(2,-4)
0.0625
>>> pow(2,-4,3)
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
pow(2,-4,3)
ValueError: pow() 2nd argument cannot be negative when 3rd argument specified
 5. 如果可选参数z传入了值,x,y必须为整数,且y不能为负数。
>>> pow(2,3,5)
3
>>> pow(10,0.1,3)
Traceback (most recent call last):
File "<pyshell#17>", line 1, in <module>
pow(10,0.1,3)
TypeError: pow() 3rd argument not allowed unless all arguments are integers
>>> pow(10,-2,3)
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
pow(10,-2,3)
ValueError: pow() 2nd argument cannot be negative when 3rd argument specified
>>>

-- 编码解码相关:

1)chr,将十进制数字转换成 unicode 编码中的对应字符串。

print(chr(9798),chr(10087),chr(9787))
------------------结果:
♆ ❧ ☻

print(chr(9679),chr(9711),chr(9734),chr(9733))
-----------结果:
● ◯ ☆ ★
print([chr(i) for i in range(65,91)]) print([chr(i) for i in range(97,123)]) print(chr(65),chr(65+32),chr(90),chr(90+32)) -------------------结果: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] A a Z z

2)ord,根据字符在unicode编码中找到其对应的十进制。

print(ord("A"),ord("a"),ord(""))
---------------结果:
65 97 9787

一些可能会用到的特殊符号(Unicode)

 3)map,循环每个元素(第二个参数),然后让每个元素执行函数(第一个参数),将每个函数执行的结果保存到新的列表中,并返回。

v1 = [11,22,33,44]
result = map(lambda x:x+100,v1)
print(list(result)) # 特殊
-------------结果:
[111, 122, 133, 144]

4)

v1 = [11,22,33,'asd',44,'xf']
def func(x):
    if type(x) == int:
        return True
    return False
result = filter(func,v1) # [11,]
print(list(result))
-------------结果:
[11, 22, 33, 44]

v1 = [11,22,33,'asd',44,'xf']
result = filter(lambda x: True if type(x) == int else False ,v1)
print(list(result))
result = filter(lambda x: type(x) == int ,v1)
print(list(result))
---------------结果:
[11, 22, 33, 44]
[11, 22, 33, 44]

5)reduce

import functools
v1 = ['','','','']
def func(x,y):
    return x+y
result = functools.reduce(func,v1)
print(result)
result = functools.reduce(lambda x,y:x+y,v1)
print(result)
----------------结果:
小马过河
小马过河

from functools import reduce
result = reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
print(result)
---------------结果:
15
原理图:在这个例子里,其实计算过程是这样的:((((1+2)+3)+4)+5) ,累加的过程。还可以实现阶乘
来自:https://blog.csdn.net/caimouse/article/details/78129956

 6)dir()

dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。

import sys,os
print(dir(os))
----------------结果:
['DirEntry', 'F_OK', 'MutableMapping', 'O_APPEND', 'O_BINARY', 'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL', 'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT', 'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'PathLike', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_execvpe', '_exists', '_exit', '_fspath', '_get_exports_list', '_putenv', '_unsetenv', '_wrap_close', 'abc', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'close', 'closerange', 'cpu_count', 'curdir', 'defpath', 'device_encoding', 'devnull', 'dup', 'dup2', 'environ', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fdopen', 'fsdecode', 'fsencode', 'fspath', 'fstat', 'fsync', 'ftruncate', 'get_exec_path', 'get_handle_inheritable', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb', 'getenv', 'getlogin', 'getpid', 'getppid', 'isatty', 'kill', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', 'pathsep', 'pipe', 'popen', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'replace', 'rmdir', 'scandir', 'sep', 'set_handle_inheritable', 'set_inheritable', 'spawnl', 'spawnle', 'spawnv', 'spawnve', 'st', 'startfile', 'stat', 'stat_float_times', 'stat_result', 'statvfs_result', 'strerror', 'supports_bytes_environ', 'supports_dir_fd', 'supports_effective_ids', 'supports_fd', 'supports_follow_symlinks', 'symlink', 'sys', 'system', 'terminal_size', 'times', 'times_result', 'truncate', 'umask', 'uname_result', 'unlink', 'urandom', 'utime', 'waitpid', 'walk', 'write']

 

 

参考:https://docs.python.org/zh-cn/3/library/functions.html

11、上述总结

没传参的函数,有传参的函数,没返回值的函数,有返回值的函数。既有传参又有返回值的函数。需要
什么样的根据具体需求。
#自我总结

 

打印菱形

for i in range(1,4):
    a=" "*(5-i) +"*"*i +"*"*(i-1)
    print(a)
for i in range(2,4):
    b=" "*(i+1)+"*"*(3-i)+"*"*(4-i)
    print(b)

 


参考链接:
http://www.runoob.com/python3/python3-function.html
https://www.cnblogs.com/i-honey/p/7679897.html
http://c.biancheng.net/view/2248.html

参考续集

http://c.biancheng.net/view/2247.html

posted @ 2019-04-09 17:57  马昌伟  阅读(465)  评论(0编辑  收藏  举报