python基础——7(函数)

一、函数的定义(函数一定是先定义,后引用)

函数是完成特定功能的代码块。

def:声明函数的关键字

fun:函数变量名

():参数列表,参数可以是0-n个,但是()不能丢

函数体:实现功能的具体代码

return:函数的返回值

代码示例

def fn():
    print("In the function1")
    return 'good'
print(fn())

def fn1(money):
    print('你付了%s元钱' % money)
    print('函数的一行代码')
    print('函数的二行代码')
    return '冰红茶'
# 直接打印fn1,只能看到函数存放代码的地址
print(fn1,id(fn1)) #<function fn1 at 0x00000098D1DF9BF8> 656356121592
#使用函数名调用
fn1(10)
# 函数的返回值也称之为函数值,就是函数执行结束后的结果
# 可以用变量接收;可以直接打印;可以直接使用
print('---------------------')
msg = fn1(10)
print(msg)
print('>>>>',fn1(10)+'好喝')

案例:函数实现文件复制

# 源文件和复制的文件都自由指定
def copy_file(source,target):
    '''
    :param source: 源文件
    :param target: 复制后的文件
    :return:
    '''
    with open(source, 'rb') as r, open(target, 'wb') as w:
        for line in r:
            w.write(line)

二、函数的分类

1、按函数体分为空函数和非空函数

空函数:项目之初,明确项目有哪些功能,但是不清楚具体的功能体,可以先用pass填充

def calculate():
    pass

非空函数,用函数体

def add_num(n1, n2):
    ''' 函数的注释
    :param n1: 第一个数
    :param n2: 第二个数
    :return: 两个数之和
    '''
    return n1 + n2
res = add_num(10,20)
print(res)

2、按参数列表分为有参和无参函数

无参函数

def test1():
    print("in the test1")

def test2():
    print("in the test2")
    return 0

def test3():
    print("in the test3")
    return 1,'hello',['shj','xxn'],{'name':'shj'}

x = test1()
y = test2()
z = test3()
print(x)  #None
print(y)  #0
print(z)  #元组(1, 'hello', ['shj', 'xxn'], {'name': 'shj'})

有参函数

def test4(x,y):
    print(x)
    print(y)
test4(2,1)  位置参数调用,与形参一一对应,等价于test4(y=1,x=2)
test4(y=1,x=2) 关键字调用,不需要按形参定义的顺序给值
位置参数一定不能放在关键字参数的后面

参数详解

# 默认参数:调用函数的时候,默认参数非必须传递
# 用途:
#     1、默认安装与自定义安装
#     2、给数据库默认端口等
def test5(x,y=2):
    print(x)
    print(y)
test5(1)
test5(1,5)  #定义了默认参数,如果不给值就按默认,给值就打印所给的值

# 参数组:针对实参不固定,需要多个形参的情况
# 第一种
def test6(*args):   #args相当于形参名
    print(args)
test6(1,2,3,4,5)
test6(*[1,2,3,4,5]) #args=tuple([1,2,3,4,5]),元组相当于只读列表

# 第二种
# *args:接收n个位置参数,转换成元组的形式
def test7(x,*args):
    print(x)
    print(args)
test7(1,2,3,4,5,6,7)

# 第三种,接收字典
# **kwargs:接收n个关键字参数,转换成字典的形式
def test8(**kwargs):
    print(kwargs)
    print(kwargs['name'])
    print(kwargs['age'])
    print(kwargs['sex'])
test8(name='shj',age=23,sex='男') #关键字参数转为字典:{'age': 23, 'sex': '男', 'name': 'shj'}
test8(**{'name':"shj",'age':23,'sex':'男'})

# 跟位置参数结合
def test9(name,**kwargs):
    print(name)
    print(kwargs)
#test9('shj','aaa')  报错,必须加关键字参数才行
test9('shj',age=22,sex='man')   #正确写法

# 跟默认参数结合(定义时,参数组一定放最后)
def test9(name,age=23,**kwargs):
    print(name)
    print(age)
    print(kwargs)
test9('shj',sex='man',hobby='街舞',age=18)  #关键字参数赋值
test9('shj',18,sex='man',hobby='街舞')  #跟上面等价,这里是位置参数赋值

def test10(name,age=23,*args,**kwargs):
    print(name)
    print(age)
    print(args)
    print(kwargs)
test10('shj',age=18,sex='man',hobby='街舞')

3、按返回值分类:

'''
1. 没有return的函数
2. 空return
# 空返回

3. return一个值
4. return多个值
# 值返回
'''
# 空返回
def fun():
    print('in the fun')
res = fun()
print('没有return关键字的返回值:%s'% res) #None

def fun2():
    print('fun2 run!!!')
    return
res = fun2()
print('空return关键字的返回值:%s' % res)  # None

# 无return和空return函数的区别
# 空return:可以根据具体情况主动退出函数(像break结束循环一样)
def fn3(msg):
    print('fn3 第一行逻辑')
    # msg信息不正常:'' | None
    if msg == '' or msg is None:
        # 结束函数
        return
    print('msg信息正常: %s' % msg)
msg = input('msg: ')
fn3(msg)

# 值返回
# 一个值的返回
def add_num(n1,n2):
    return n1 + n2
print(add_num(1,2))

def computed(n1, n2):
    # 返回四则运算的结果
    r1 = n1 + n2
    r2 = n1 - n2
    r3 = n1 / n2
    r4 = n1 * n2
    return [r1, r2, r3, r4]

a, b, c, d = computed(50, 25)
print(a, b, c, d)


# 多个值的返回: 本质就是返回装有多个值的元组
def computed_sup(n1, n2):
    # 返回四则运算的结果
    r1 = n1 + n2
    r2 = n1 - n2
    r3 = n1 // n2
    r4 = n1 ** n2
    return r1, r2, r3, r4

a, b, c, d = computed_sup(50, 25)
print(a, b, c, d)

res = computed_sup(50, 25)  # 得到的是装有所有结果的元组
print(res)

三、函数的嵌套调用:在一个函数体调用另一个函数

# 在解释过程中,不执行函数体,在函数被调用时,函数体才被执行

def fn1():
    print('fn1 run')
    fn2()

def fn2():
    print('fn2 run')
    fn3()

def fn3():
    print('fn3 run')

# 注:在fn1中调用了fn2,所以调用fn1的逻辑应该在fn2定义之后
fn1()

嵌套函数案例:实现比较数字的最大值

# 两个数
def max_2(n1,n2):
    if n1 > n2:
        return n1
    return n2
print(max_2(2,3))
# 三个数
def max_3(n1,n2,n3):
    m = max_2(n1,n2)
    return max_2(m,n3)
print(max_3(1,2,3))
# 四个数
def max_4(n1,n2,n3,n4):
    m2 = max_3(n1,n2,n3)
    return max_2(m2,n4)
print(max_4(1,2,3,4))

四、函数对象

def fn():
    num = 10
    print("fun function run")
print(fn)  # <function fn at 0x000000E0B324C1E0>

函数名存放的就是函数的地址,所以函数名也是对象,称之为函数对象

函数的用法:

1、可以直接被引用

def fn():
    num = 10
    print("fun function run")
print(fn)  # <function fn at 0x000000E0B324C1E0>

func = fn
print(func)  # <function fn at 0x000000E0B324C1E0>
fn()    # fun function run
func()  # fun function run

2、可以当作函数参数传递

def add(a,b):
    return a + b

def subtract(a,b):
    return a-b

def multiply(a,b):
    return a*b

def divide(a,b):
    return a/b

#计算:通过该函数可以完成任意两个数的四则运算
def computed(fn,n1,n2):
    # fn代表四则运算的任一种
    # res为运算结果
    res = fn(n1,n2)
    print(res)

# 完成两个数的某一运算,拿到结果
while True:
    cmd = ("cmd:")
    if cmd == 'add':
        result = computed(add,100,20)
    elif cmd == 'substract':
        result = computed(substract,100,20)
    else:
        print("Invalid input")
        break
    print(result)

3、可以作为容器类型的元素

def add(a, b):
    return a + b
def low(a, b):
    return a - b
def jump(a, b):
    return a * b
def full(a, b):
    return a / b
def quyu(a, b):
    return a % b
def computed(fn, n1, n2):
    res = fn(n1, n2)
    return res
method_map = {
    'add': add,
    'low': low,
    'jump': jump,
    'full': full,
    'quyu': quyu,
}
while True:
    cmd = ("cmd:")
    # 用户输入的指令只要有对应关系,就会自动去走对应的计算方法
    # 这样外界就不用去关心到底有哪些计算方法
    if cmd in method_map:
        cp_fn = method[cmd]  #拿到计算方法
        result = computed(cp_fn,100,20)  #通过计算得到结果
        print(result)
    else:
        print("输入有误,退出")
        break

4、可以作为函数的返回值

def add(a, b):
    return a + b
def low(a, b):
    return a - b
def jump(a, b):
    return a * b
def full(a, b):
    return a / b
def quyu(a, b):
    return a % b
def computed(fn, n1, n2):
    res = fn(n1, n2)
    return res
method_map = {
    'add': add,
    'low': low,
    'jump': jump,
    'full': full,
    'quyu': quyu,
}
# 根据指令获取计算方法
def get_cp_fn(cmd):
    if cmd in method_map:
        return method_map[cmd]
    return add  # 输入有误用默认方法处理


while True:
    cmd = input('cmd: ')
    if cmd == 'quit':
        break
    cp_fn = get_cp_fn(cmd)
    result = computed(cp_fn, 100, 20)
    print(result)

五、名称空间,作用域

名称空间:存放名字与内存空间地址对应关系的容器

作用:解决由于名字有限,导致名字重复发送冲突的问题

三种名称空间:

1、Built-in:内置名称空间;系统级,一个;随解释器执行而产生,解释器停止而销毁

2、Global:全局名称空间;文件级,多个;随所属文件加载而产生,文件运行完毕而销毁

3、Local:局部名称空间;函数级,多个;随所属函数执行而产生,函数执行完毕而销毁

注:

del  函数名:可以移除查找最近的名字与内存空间地址的对应关系

加载顺序:Built-in > Global > Local

print(len('abc'))

len = len('abcdef')
print(len)

del len

# del len

print(len('000111222'))
'''
[
    # ['len': 100001]  # 保存长度的变量
    ['len': 200001]  # 计算长度的函数
]
'''

def fn1():
    len = 10
    print(len)

def fn2():
    len = 20
    print(len)

fn1()
fn2()

global关键字:

global关键字可以将local的名字提升为global的名字

一个文件中的global名字就是一个,所以函数内部外部使用的名字都是一个

def fn():
    global num
    num = 20
    print(num)
fn()    注:一定要调用函数,才能产生名字,并提升为全局变量
print(num)

作用域:名字起作用的范围

作用:解决同名共存问题

# 四种作用域
# Built-in:内置作用域,所有文件所有函数
# Global:全局作用域,当前文件所有函数
# Enclosing:嵌套作用域,当前函数与当前函数的内部函数
# Local:局部作用域,当前函数
len = 10
def outer():
    len = 20  # 外层函数的局部变量:Enclosing - 嵌套作用域
    def inner():
        len = 30
        print('1:', len)  # inner -> outer -> global -> built-in
    inner()
    print('2:', len)  # outer -> global -> built-in
outer()
print('3:', len)  # global -> built-in

del len
print('4:', len)  # built-in

LEGB

不同作用域之间名字不冲突,以达到名字的重用

查找顺序:Local -> Enclosing -> Global -> Built-in -> 抛异常

六、闭包

闭包就是嵌套函数(格式稍作改良)

inner可以使用outer的局部变量:可以将inner定义在outer中

inner的调用还是在外部,inner函数对象能被outer返回

# 将内部函数对象作为外部函数的返回值

1、可以使用局部变量

2、不改变函数的调用位置

def outer():
    num = 10
    def inner():  # 闭包:定义在函数内部的函数称之为闭包
        print(num)
    return inner
fn = outer()   # fn = inner
fn()

闭包案例:

# 案例一:外部函数可以为闭包传递参数 (了解)
"""
import time
def download():
    print('开始下载')
    time.sleep(2)
    print('下载完成')
    data = "下载得到的数据"
    outer(data)
# 为闭包传参
def outer(data):
    def inner():
        # 保存,播放,删除等操作
        print("闭包打印:", data)
    inner()
download()
"""

# 案例二:延迟执行
import requests

'''
# get_html一执行就获取页面
def get_html(url):
    html = requests.get(url)
    print(html.text)
get_html('https://www.baidu.com')
get_html('https://www.python.org')
get_html('https://www.sina.com.cn')
get_html('https://www.baidu.com')
'''

def outer(url):
    def get_html():
        html = requests.get(url)
        print(html.text)
    return get_html
# 先预定义多个爬虫方法,爬页面操作并未执行
baidu = outer('https://www.baidu.com')
python = outer('https://www.python.org')
sina = outer('https://www.sina.com.cn')
# 什么时候想爬什么页面就调用指定页面的爬虫方法
baidu()
sina()
baidu()

猜你喜欢

转载自blog.csdn.net/weixin_40406241/article/details/88881144