6_函数

目录

函数的定义

返回值

函数是对象

局部变量和全局变量

测试局部全局变量的效率

参数的传递

对可变对象的传递

对不可变对象的传递(不能改变不可变部分的值)

浅拷贝与深拷贝

对不可变对象中,可变子对象的内容可以在函数中发生变化

四种参数类型

lambda 函数

eval 函数

递归函数

函数的嵌套

nonlocal与global

LEGB规则


 

  • 函数的定义

# 函数的定义,注意冒号
def printMax(a, b):                 # 冒号
    '''比较大小,输出大的值'''        # 函数注释

    if a > b:
        print(a, "MAX")
    else:
        print(b, "MAX")

printMax(10, 20)
printMax(2, 1)
help(printMax.__doc__)              # 双下划线,查看函数说明

--------------------------------
20 MAX
2 MAX
No Python documentation found for '比较大小,输出大的值'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.
--------------------------------
  • 返回值

# 返回多个值需要用容器装好
def test(x, y, z):
    return [x, y, z]

print(test(1, 2, 3))
  • 函数是对象

函数作为对象,可以作为参数,也可以作为返回值

  • 局部变量和全局变量

局部变量:在函数中使用

                  局部变量和全局变量同名时,在函数中隐藏全局变量,只使用局部变量

                  局部变量引用比全局变量快,尽量使用局部变量

全局变量:可以作为常数使用,作用于定义到模块结束

                  函数内改变全局变量的值,需要用 global 声明

a = 100     # 全局变量

def test():
    b = 4
    print(b*10)
    # print(a)    这一句加上会报错,因为和全局变量重名,别认为是没有定义的局部变量
    a = 200
    print(a)

test()
print(a)            # 全局变量没有改变

-----------------------------
40
200
100
-----------------------------
a = 100

def test():
    global a     # 修改全局变量
    a = 200

test()           # 必须要调用函数,才会修改全局变量
print(a)

测试局部全局变量的效率

import math
import time

def test01():
    start = time.time()
    for i in range(100000):
        math.sqrt(30)
    end = time.time()
    print("time=",(end-start))

def test02():
    b = math.sqrt                # 全局变量变为局部变量
    start = time.time()
    for i in range(100000):
        b(30)
    end = time.time()
    print("time=" ,(end-start))

test01()
test02()

---------------------------
time= 0.03200197219848633
time= 0.022001266479492188
---------------------------
  • 参数的传递

Python 中所有的传递都是“引用传递”

对可变对象的传递

# 对于列表,字典,集合等可变对象
# 对可变对象进行写操作,直接作用于原对象
# 相当于利用 C 中的指针修改主函数变量的值
a = [10, 20]
print(a)
print(id(a))        

def test(m):
    print(id(m))
    m.append(30)
    print(id(m))

test(a)
print(a)

-----------------------------
[10, 20]
13583864                        # 并没有产生新的对象
13583864
13583864
[10, 20, 30]                    # 原对象的值发生了变化
-----------------------------

对不可变对象的传递(不能改变不可变部分的值)

# 对于不可变对象,创建一个新的对象,把新的值给新对象
a = 100
print(a)
print(id(a))

def test(m):
    print(id(m))
    m = m + 200            # 创建了一个新的对象
    print(id(m))           # 可以发现地址的变化
    print(m)

test(a)                    # 这里传递的仍然是对象原地址
print(a)

------------------------
100
1680567008                 # 刚开始 a 和 m 指向同一个对象            
1680567008
5170976
300
100                        
------------------------

浅拷贝与深拷贝

浅拷贝:只是拷贝了子对象的引用,不拷贝子对象的内容,被拷贝的和拷贝出的指向同一个对象

深拷贝:不仅拷贝子对象引用,还拷贝子对象内容,指向拷贝出的内容

浅拷贝相当于克隆了一个人,没有克隆他的子孙

深拷贝把一个人的儿子孙子全克隆了

# 浅拷贝
import copy                        
a = [10, 20, [5, 6]]
b = copy.copy(a)                    # 拷贝出子对象 [10, 20, [5, 6]]
print("a:", a)
print("b:", b)
b.append(30)                        # 只修改了 b
b[2].append(7)                      # 两个都修改了
print("after copy------------")
print("a:", a)            
print("b:", b)

-----------------------------------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
after copy------------
a: [10, 20, [5, 6, 7]]
b: [10, 20, [5, 6, 7], 30]
-----------------------------------------
# 深拷贝
import copy
a = [10, 20, [5, 6]]        
b = copy.deepcopy(a)            # 拷贝了全部,有了一个独立的大家庭
print("a:", a)
print("b:", b)
b.append(30)
b[2].append(7)
print("after deepcopy------------")
print("a:", a)
print("b:", b)

---------------------------------------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
after deepcopy------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6, 7], 30]
---------------------------------------------

对不可变对象中,可变子对象的内容可以在函数中发生变化

# 传递元组,元组中的列表元素内容可以修改
a = (10, 20, [4, 5])
print("a:", a)
def test(m):
    print("m:", m)
    m[2][1] = 50            # 不能修改整个 m[2]
    m[2].append(6)
    print("m:", m)
test(a)
print("a:", a)

-----------------------------
a: (10, 20, [4, 5])
m: (10, 20, [4, 5])
m: (10, 20, [4, 50, 6])
a: (10, 20, [4, 50, 6])
-----------------------------

 m[2] = 5    会报错,这是对元组的操作

m[2].append(5)     这是对列表的操作

四种参数类型

# 位置参数,一一对应,个数不匹配会报错
def test(a, b, c):
    print(a, b, c)

test(1, 2, 3)

#############################################################

# 默认值参数
def test(a, b, c, d = 20):        # 默认值参数要放在位置参数后面,否则会报错   
    print(a, b, c, d)

test(1, 2, 3)
test(1, 2, 3, 4)
---------------------------
1 2 3 20                    # 如果没有传递默认值参数,就使用初始化的默认值参数值
1 2 3 4                     # 如果传递了,则使用传递的值    
---------------------------

##############################################################

# 命名参数,在调用时通过形参名称对应
def test(a, b, c):
    print(a, b, c)

test(1, 2, 3)
test(c=3, b=2, a=1)
-------------------------------
1 2 3
1 2 3
-------------------------------

###############################################################

# 可变参数,可变参数放到元组或字典中 
def test(a, b, *c, **d):       # * 元组  ** 字典
    print(a, b, c, d)

test(1, 2)
test(1, 2, 3, 4)
test(1, 2, 3, 4, name="aaa", age=18)
--------------------------
1 2 () {}
1 2 (3, 4) {}
1 2 (3, 4) {'name': 'aaa', 'age': 18}
--------------------------

# 如果把可变参数放到前面,需要强制命名参数
def test(*a, b, c):
    print(a, b, c)

test(1, 2, b=6, c=7)     # b c 都要指明,不然会报错
----------------------------
(1, 2) 6 7
----------------------------

lambda 函数

# 第一种
f = lambda a, b, c: a + b + c
print(f(1,2,3))

# 第二种
g = [lambda a: a+5, lambda b: b*2, lambda c: c*3]
print(g[0](4))

# 相当于以下用法
def test01(a, b, c):
    return a+b+c

def test02(a, b, c):
    return a*b*c

h = [test01, test02]
print(h[0](1,2,3))
print(h[1](2,2,2))

----------------------------------------
6
9
6
8
----------------------------------------

eval 函数

# eval(source[,global,local])   global 只能是字典,global,local 可选
eval('print("abcd")')

a = 30
b = 10
c = eval("a+b")
print(c)

dict1 = dict(a = 300, b = 100)
d = eval("a+b", dict1)            # 基本用法
print(d)

递归函数

def test(n):
    print("test",n)
    if n==0:
        print("over")
    else:
        test(n-1)
    print("test***", n)

test(4)

-----------------------------------
test 4
test 3
test 2
test 1
test 0
over
test*** 0                # 注意这里,函数在栈中的运行
test*** 1
test*** 2
test*** 3
test*** 4
-----------------------------------

首先打印一个 5 个 test ,接着 n 变为 0,运行最后一次递归的最后一步,打印 test***,最后一轮全部结束,进入倒数第二轮递归的最后一步,即 n=1······

# 实例,求阶乘

def f(n):
    if n == 1:
        return 1
    else:
        return n*f(n-1)

print( f(5) )

----------------------------------
120
----------------------------------

函数的嵌套

def f1():
    print("f1 running...")

    def f2():
        print("f2 running...")

    f2()

f1()

------------------------------------
f1 running...
f2 running...
------------------------------------

用于函数的封装(隐藏)、避免代码重复、闭包(见后面讲解)

# 小例子
# 原代码
def printchinesename(surname, firstname):
    print("{0} {1}".format(surname, firstname))

def printforeignname(surname, firstname):
    print("{0} {1}".format(firstname, surname))

printchinesename("爱", "学习")
printforeignname("Lu", "Yaoyi")

# 可以改成这样
def print_name(Ischina, surname, firstname):
    def printname(a, b):
        print("{0} {1}".format(a, b))

    if Ischina:
        printname(surname, firstname)
    else:
        printname(firstname, surname)
print_name(True, "爱", "学习")
print_name(False, "Lu", "Yaoyi")

nonlocal与global

用来声明全局变量和外部的局部变量,以便在函数内修改他们的值

a = 100

def f():
    b = 10
    def g():
        nonlocal b      # 注释掉,b 的值为 10
        global a        # 注释掉,a 的值为 100
        a = 500
        b = 50
    g()
    print("a:", a)
    print("b:", b)
f()

------------------------------------------
a: 500
b: 50
------------------------------------------

LEGB规则

Python中查找名称的规则

L: Local   函数和类的内部

E: Enclosed  嵌套的上层函数

G: Global   模块中的全局变量

B: Build in    Python 自带函数

全部查找不到就会报错,错误类型是未定义

注:基本常识

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值