Python基础:函数

函数存在的意义

print('拿到一本书')
print('看书')
print('收起')

# 模拟一个看书的操作,多次调用某个操作,直接封装在函数里即可
def learnling(name, course, start, end):   # 带参数函数
    print(f'{name}报名了课程:{course}')
    print(f'从第{start}节课学习到{end}节课')
    print(f'{name}学习结束')


# 调用函数
learnling('小明', 'Python入门到精通', 1, 2)

带返回值的函数

def add(x, y):
    return x * y


print(add(5, 3) + 6)
print(add('-', 60))

变量作用域

x = 55   # 全局变量  Global


def func():
    global x
    # 函数内调用并改变函数体外的全局变量时需要使用global来指定当前使用的是全局函数的变量
    x = 99     # 否则会在函数内创建一个新的x 局部变量  Local
    return x


print('全局x', x)
print('函数内x', func())
def func2():
    y = 100

    def nested():
        nonlocal y
        # 里层的函调用并改变外层函数的变量时需要使用nonlocal来指定当前使用的是外层函数的变量
        y = 99
        print(y)
    nested()
    print(y)


func2()  # 不加nonlocal打印结果99 \n 100   加了是99 \n 99

参数的传递注意事项:
不可变类型,传递副本给函数,函数内操作不影响原始值
可变那类型,传递地址引用,函数内操作可能会影响原始值

# 数字
def change_numer(x):
    # global x    # 这里跟变量作用域不是一个概念哦,这里加global会报错的,因为变量在函数下面的
    x += 10            # 改变函数参数的值


x = 5
print('原始数字', x)
change_numer(x)
print('被函数祸害过的数字', x)


# 字符串
def change_str(s):
    s = 'xxxxx.cn'   # 改变函数参数的值


s = 'baidu.com'
print('原始字符串:', s)
change_str(s)
print('被函数祸害过的字符串:', s)


# 列表
def change_list(l):
    l[0] = '我变'      # 改变函数参数的值


l = ['小红', '小明', '泰罗']
print('原始列表', l)
change_list(l)
print('被函数祸害过的列表', l)   # 列表内的小红被改成我变

# 想让列表不改变 用copy()  或者[:]   给它个副本就行了
print('原始列表', l)
change_list(l.copy())  # 并没有改变原来的列表l,传给函数的是一个副本
print('被函数祸害过的列表', l)  # 并没有被祸害,啦啦啦....

函数的几种参数

位置参数

*args(可变参数)、**kwargs(关键字参数)传递及解包

lambda表达式、函数的委托

位置参数

# Python是动态类型,函数可以传递任何类型的参数
def function(a, b, c, d):
    print(a, b, c, d)


function('a', 1, 2, 3)
function([1, 2, 3], (4, 5, 6), {'a': 1, 'b': 2})

# 位置参数可以按照关键字参数传递
function(b=1, a=2, d=5, c=4)

# 位置参数的默认值
def func(a, b=2, c='c'):  # 定义参数(形参)的时候设置默认实参:(参数=值, ...)
    print(a, b, c)


func(1)  # 调用的时候可省略传递参数

func(1, c='5')

传递实参时位置顺序与形参不同的时候,需要按照关键词匹配方式:参数=值, …

如果是默认参数,传递的类型要和定义形参时一致

为了安全起见,在不确定的情况下可以尽量使用关键词匹配方式传参:参数=值, …,可以避免顺序错误

*args(可变参数)

def avg(score1, score2):   # 计算平均分的函数
    return (score1+score2)/2


def avg(a, b, c):
    # 假如此时成绩变成了三门科目,可以重新定义这个函数进行代码重载(也叫做函数的迭代)
    return (a+b+c)/3


def avg(*args):
    # 如果有五门、十门成绩的话,这个时候又要重载函数,此时就用到可变参数了
    return sum(args) / len(args)  # sum可以把一个集合里的值汇总


avg(88, 89, 60)   # 传递的时候 可以传递任意数量的参数


scores = (88, 89, 60)  # 如果事先有了个元组,想把这个元组传入
avg(*scores)    # 这里传递的时候要用*号解包,解包后就跟88, 89, 60这种一样了
# 不解包的话元组本身是带括号的,不能直接传个元组
# 虽然要求传递的值刚好就是元组,但是传递的时候习惯是还是以参数1, 参数2 这种方式传递的,所以要解包

**kwargs(关键字参数)

def display_enployee(**kwargs):
    print(kwargs)


display_enployee(name="Ton", age=23, aa='用这种方式传而不是用冒号,传什么都行')
# 这种传值方式跟字典表的构造函数一样  dict(name="Ton", age=23)


emp = {
    'name': 'tom',
    'age': 23
}         # 事先有了个字典表
display_enployee(**emp)    # 这里传递的时候要用**号解包,解包后就跟name="Ton", age=23这种一样了

lambda表达式

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


f1 = lambda a, b: a + b


def hello(name):
    print(name)


f2 = lambda name: print(name)


print(f1(5, 3))
f2('tom')

综合实例、函数的委托

def hello_chinese(name):
    print('你好', name)


def hello_english(name):
    print('Hello', name)


while True:
    name = input('请输入您的姓名:\n')
    if name == 'stop':
        break
    language = input('请输选择语言版本:\n c =>中文\n e =>英文\n j =>日文\n')

    # 直接调用函数执行
    if language == 'c':
        hello_chinese(name)
    elif language == 'e':
        hello_english(name)
    elif language == 'j':
        (lambda name: print('靠你吉娃', name))(name)  # lambda用括号括起来直接传值并执行

    # 委托   函数赋值给一个变量(定义一个函数指针)
    if language == 'c':
        action = hello_chinese      # 把函数赋值给action  定义一个函数指针
    elif language == 'e':
        action = hello_english      # 把函数赋值给action  定义一个函数指针
    elif language == 'j':
        action = lambda name: print('靠你吉娃', name)   # 同上 这里相当于给匿名函数取了个名字

    action(name)    # 所有的函数和匿名函数都赋值给action 委托action来调用
def hello_chinese(name):
    print('你好', name)


def hello_english(name):
    print('Hello', name)


# 用字典表实现多个if elif(switch) 因为Python没有switch
operation = {
    'c': hello_chinese,     # 把函数当做字典表的值来使用
    'e': hello_english,
    'j': lambda name: print('靠你吉娃', name)
}

while True:
    name = input('请输入您的姓名:\n')
    if name == 'stop':
        break
    language = input('请输选择语言版本:\n c =>中文\n e =>英文\n j =>日文\n')
    operation.get(language)(name)
    operation.get(language, lambda name: print('输入的语言不存在'))(name)


# 更简洁的委托 将一个函数作为参数传递给另一个函数
def hello(action, name):
    action(name)


hello(hello_english, 'jiuren')
# 这个函数的第一个形参传递的参数(实参)是上面的函数,第二个参数是name
# 间接的把hello_english的函数的功能都给了hello这个函数 执行的时候都是靠hello执行

hello(lambda name: print('靠你鸡娃', name), 'jiuren')
# 用lambda表达式直接就可以在第一个参数里临时里写一个匿名函数  参数二还是name

高级函数工具

函数高级工具 map() filter() 返回带next()的可迭代对象(迭代器对象)
需要返回列表可以用list转换。也可以用for循环遍历出来

l = list(range(1, 21))
res = []

for x in l:    # for循环
    if x % 2 == 0:
        res.append(x)

res = [x for x in l if x % 2 == 0]   # 推导


'''
1.for循环'''
for x in l:
    res.append(x + 5)

'''
2.推导    最实用'''
res = [x + 5 for x in l]


'''
3.map()     灵活性好  返回迭代器对象'''


def add(x):
    return x + 5


res = list(map(add, l))
# 把l这个可迭代对象的每个值作为参数传递给add这个函数,返回迭代器对象,使用list转换成列表

res = list(map(lambda n: n**2, l))     # 直接传入一个lambda表达式


'''
4.filter()   灵活性好  返回迭代器对象'''
l = list(range(1, 16))
res = []


def even(x):
    return x % 2 == 0


res = list(filter(even, l))
# 从列表里找到符合even()这个函数条件的值返回给列表


# 用for循环遍历map()和filter()返回的结果

res = filter(even, l)
for i in res:
    print(i, end=' ')      # end=' ' 是指用空格分割 默认是换行符


# 用lambda表达式 直接传一个匿名函数
res = list(filter(lambda l: l % 2 == 0, l))


res = filter(lambda l: l % 2 == 0, l)
for i in res:
    print(i, end=' ')




作用域测试

"""
函数外的变量、函数内的变量和语句/循环体内的变量"""


def f():
    a1 = 0   # Python每次定义变量要赋值,相当于其他语言定义一个变量不赋值的默认值和类型
    # 空变量一般可以赋值为None,不占内存,这里赋值为0
    for i in range(1, 6):
        print('for循环里打印', a1)  # 这里只能打印a1的初始值0
        a1 = i
        a2 = i
        print('for循环里打印', a1, a2)
    a1 += 1
    a2 += 1
    print('函数里 for循环体外打印', a1, a2)
    while True:
        a1 -= 1
        a2 -= 1
        print('while循环里打印', a1, a2)
        if a1 and a2 <= 2:
            break
    if a1 >= 0 or a2 >= 0:
        a1 += 1
        a2 += 1
        print('if里打印', a1, a2)


# print(a1, a2)  # 函数内的变量在外面调用不了


abc = '函数体外的全局变量'
print('全局变量的初始值 => ' + abc)


def f1():
    print('函数内调用函数外的全局变量(只调用不做更改其值) => ' + abc)


def f2():
    # 函数内调用并更改函数体外的abc,需要用global指定,其他语言貌似不需要(易语言的程序集变量就不需要)
    global abc
    # abc *= 3
    abc = '函数体外的全局变量被改变'
    print('指定global后 更改过的全局变量 => ' + abc)


def f3():
    abc = '不指定global,函数体外的全局变量不会改变,将创建一个新的局部变量'
    # 如果不指定global,直接赋值给一个与函数体外同名的变量,会创建一个新变量,而不是改变函数体外的变量,
    # 相当于易语言在程序集和局部分别创建一个变量abc,两个变量同名,一般是需要避免这种重名的
    print('无global => ' + abc)  # 这里打印会打印函数里(自己的)变量abc


'''
想调用并更改函数体外的变量就必须有global,有了global,就不可以再有其他与函数体外同名的变量了,
所有针对这个变量abc的调用和操作都需要在global下面。

没有global的话可以调用函数体外的变量的,且只能调用不能更改,
如果更改的话,会创建一个新变量,而不是改变函数体外的变量,这个时候就永远调用不到函数体外面的变量了,
所有针对这个新变量的调用和操作都需要在创建这个变量的下面。
'''


if __name__ == '__main__':
    # f()
    # f()
    '''
    对于Python来说,每次调用函数的时候a1的初始值都是等于0
    因为Python定义变量是一定要先赋值的,在函数外面定义的a1初始值就是0
    易语言不给初始值默认就有初始值,比如整数型是0,文本型是“”,每次调用子程序的时候所有局部变量也会变为初始值
    '''

    f1()
    f2()
    f1()

    f3()
    f1()

'''
作用域只是对函数来说的,对循环和判断语句没影响,跟易语言一样,java中只要是代码块,都有作用域
只是有时候定义变量 初始化的时候,需要考虑放到循环体外还是循环体内,比如用变量计数的时候

将变量放到函数外面,所有子程序都能调用到它,更改它的时候需要指定global
'''



拓展:

谈谈自己的理解:python中闭包,闭包的实质

廖雪峰博客里 对函数的几种参数 讲的很细

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值