TOPIC

磷光与烟火逆流

一个敲代码的程序猿

Python之函数与作用域

函数初识

  1. 什么是函数

    获取任意一个字符串的元素的个数
    s1 = 'fdskjlgfdgfdjkslgdfjkjafdsajk'
    count = 0
    for i in s1:
        count += 1
    print(count)
    
    
    # 获取列表的元素的个数
    l1 = [1, 2, 3]
    count = 0
    for i in l1:
        count += 1
    print(count)
    
    
    # 面向过程编程
    1. 代码重复。
    2. 代码可可读性不高。
    
    初识函数
    l1 = [1, 2, 3]
    def new_len():
        count = 0
        for i in l1:
            count += 1
        print(count)
    new_len()
    
    
    函数:函数是以功能为导向,一个函数封装一个功能。登录,注册,文件的改的操作.....
    函数减少代码的重复性,增强了代码的可读性。
    
  2. 函数的结构

    l1 = [1, 2, 3]
    
    def new_len():
        count = 0
        for i in l1:
            count += 1
        print(count)
    new_len()
    
    def 关键字: 定义一个函数。紧跟一个空格。
    new_len函数名:与变量命名规范一致。一定要具有可描述性。 
    ():结构需要,传参使用。
        : 分割符。
    tab键:四个空格。缩进。函数体
    
    
    
  3. 函数的调用

    l1 = [1, 2, 3]
    
    def new_len():
    
    count = 0
    
    for i in l1:
    
    count += 1
    
    print(count)
    
    函数的执行写多少次,执行多少次。
    
    new_len() # 函数名() 函数的执行者。调用者。
    
    new_len()  # 函数名() 函数的执行者。
    
    new_len()  # 函数名() 函数的执行者。
    
    new_len()  # 函数名() 函数的执行者。
    
    new_len()  # 函数名() 函数的执行者。
    
       l1 = [1, 2, 3]
       def new_len():
           count = 0
           for i in l1:
               count += 1
           print(count)
    
       for i in range(10):
           print(111)
    
       for i in range(3):
           new_len()
    
  4. 函数的返回值

    一个函数就是封装一个功能,这个功能一般都会有一个最终结果的,比如你写一个登录函数,最终登录成功与否是不是需要返回你一个结果?还有咱们是不是都用过len这个函数,他是获取一个对象的元素的总个数,最终肯定会返回一个元素个数这样的结果:

    s1 = 'abfdas'

    print(len(s1)) # 6

    函数的返回值用return表示:

    1.结束函数。

    l1 = [1, 2, 3]	
    def new_len():	
        print(111)
        print(222)
        if 1 == 1:
            return
        print(333)
        print(444)
    new_len()
    

    2.函数中没有return或者只写一个return,函数的执行者得到的是None。

    # l1 = [1, 2, 3]
    # def new_len():
    #     count = 0
    #     for i in l1:
    #         count += 1
    #     return
    # print(new_len())
    

    3.函数中return后面是单个值,函数的执行者得到的是这个值(不改变值的类型)。

    def func():
    	print(111)
    	# return 100
    	# return [1, 2, 3]
    	return {'name': '太白'}
    ret = func()
    print(ret, type(ret))
    
  5. 函数中return后面是多个值,函数的执行者得到的是一个元组。

    # def func():
    #     print(111)
    #     return 1, '23期', [22, 33]
    # ret = func()
    # print(ret, type(ret))  # (1, '23期', [22, 33])
    
    # def func():
    #     print(111)
    #     # return 1, '23期', [22, 33]
    # a,b,c = func()
    # print(a,b,c)
    
    
    def func():
        print(111)
        # return 1+1+2
        return 2 > 1
    ret = func()
    print(ret)
    

函数的传参

我们上面研究了,函数的结构,函数的执行,以及函数的返回值。对函数有一个初步的了解,那么接下来就是一个非常重要的知识点,函数的参数。函数是以功能为导向的,上面我们写的函数里面的代码都是写死的,也就是说,这个函数里面的更改起来很麻烦,试想一下,我们使用探探,陌陌等软件,可不可以进行筛选,比如选择性别,年龄等,导出结果? 再拿我们之前学过的len 这个len是不是可以获取字符串的总个数?是不是可以获取列表的总个数?你更改了len函数内部的代码了?没有吧?你看下面的例子:

s1 = 'sfdas'
l1 = [1, 3, 7]
print(len(s1))  # 5
print(len(l1))  # 3
# # 函数的传参:函数的拓展性
#
#
# def new_len(a):  # 定义函数时:参数:形参。
#     count = 0
#     for i in a:
#         count += 1
#     return count
# l1 = [1, 2, 3]
# s1 = 'fdsjaklsfjgfds'
# # print(new_len(l1)) # 函数的调用者:参数 实参。
# print(new_len(s1)) # 函数的调用者:参数 实参。
# print(len(s1))

实参角度:

  1. 位置参数。
  2. 关键字参数。
  3. 混合参数。

形参角度:

  1. 位置参数。
  2. 默认参数。
  3. 动态参数。
  4. 仅限关键字参数。(了解)

实参角度:

  1. 位置参数。

    # 1. 位置参数。: 从左至右,按照顺序,一一对应
    def meet(sex,age,job,):
        print('左划一下')
        print('右划一下')
        print(f'寻找性别{sex},年龄{age}岁,{job}')
        print('聊天')
        print('约吗')
        print('约....')
    meet('女','18~25','讲师')
    
    # 写一个函数,接收两个数字的参数,将较大的数字返回。
    # def comp(a,b):
    #     if a > b:
    #         return a
    #     else:
    #         return b
    # ret = comp(1,2000)
    # print(ret)
    
    # 三元运算符:简单的if else。
    # a1 = 1
    # b2 = 2
    # ret = a1 if a1 > b2 else b2
    # # print(ret)
    #
    # def comp(a,b):
    #     # ret = a if a > b else b
    #     # return ret
    #     return a if a > b else b
    # ret = comp(1,2000)
    # # print(ret)
    
  2. 关键字参数。一一对应

    def meet(sex,age,job,hight,weight,):
        print('左划一下')
        print('右划一下')
        print(f'寻找性别{sex},年龄{age}岁,身高{hight},体重{weight},工作{job}')
        print('聊天')
        print('约吗')
        print('约....')
    
    # meet(sex='女',job='学生',weight=120,hight=170,age='18~25')
    
  3. 混合参数。关键字参数一定在位置参数后面,一一对应。

    # def meet(sex,age,job,hight,weight,):
    #     print('左划一下')
    #     print('右划一下')
    #     print(f'寻找性别{sex},年龄{age}岁,身高{hight},体重{weight},工作{job}')
    #     print('聊天')
    #     print('约吗')
    #     print('约....')
    #
    # meet('男',27,'ITC语言',weight=120,hight=175,)
    

形参角度:

  1. 位置参数:与实参角度位置参数一样。

    # def meet(sex,age,job):
    #     print('左划一下')
    #     print('右划一下')
    #     print(f'寻找性别{sex},年龄{age}岁,{job}')
    #     print('聊天')
    #     print('约吗')
    #     print('约....')
    # meet('女','18~25','讲师')
    
  2. 默认参数: 一定在位置参数后面,不传参数即沿用默认的参数。

    # open('文件的改',encoding='utf-8')
    def meet(age,job,sex='女'):
        print('左划一下')
        print('右划一下')
        print(f'寻找性别{sex},年龄{age}岁,{job}')
        print('聊天')
        print('约吗')
        print('约....')
    # meet('18~25','幼师')
    # 更改默认参数
    # meet('18~25','幼师',sex='laddy_boy')
    meet('18~25','幼师','laddy_boy')
    
    

函数进阶

  1. 函数的传参:形参角度:第三种传参方式。

    动态参数: *args **kwargs

    # def eat(food1,food2,food3):
    #     print(f'我请你吃:{food1},{food2},{food3}')
    # eat('蒸羊羔','蒸熊掌','蒸鹿尾')
    
    # 当给函数传入的参数数目不定时,之前的传参方式解决不了问题。
    # 万能参数,动态参数。 *args
    def eat(food1,food2,food3):
        print(f'我请你吃:{food1},{food2},{food3}')
    eat('蒸羊羔','蒸熊掌','蒸鹿尾','烧花鸭','烧企鹅')
    
    def eat(*args):  # 将实参角度:定义一个函数时,* 所有的位置参数聚合到一个元组中。
        print(args)
        print(f'我请你吃:{args}')
    eat('蒸羊羔','蒸熊掌','蒸鹿尾','烧花鸭','烧企鹅')
    
    # **kwargs
    def func(**kwargs):  # 函数的定义时:**将实参角度所有的关键字参数聚合成了一个字典,给了kwargs.
        print(kwargs)
    func(name='alex',age=84,hobby='唱跳rap篮球')
    
    # *args,**kwargs 万能参数
    def func(*args,**kwargs):
        print(args,kwargs)
    

    练习:写一个函数,求传入函数中的不定个数的数字实参的和。

    def func(lis):
        num1 = 0 
        for i in lis:
            num1 += i
        return num1
    
  2. *的魔性用法

    # 函数中
    def func(*args,**kwargs):
        print(args)  # (1, 2, 3,'太白', 'wusir', '景女神')
        print(kwargs)
    l1 = [1, 2, 3]
    l2 = ['太白', 'wusir', '景女神']
    # func(l1,l2)
    # func(*l1,*l2)  # 当函数的执行时:*iterable 代表打散。
    func(*[1, 2, 3],*(11,22),*'fdsakl')  # 当函数的执行时:*iterable 代表打散。
    def func(*args,**kwargs):
        print(args)
        print(kwargs)
    func(**{'name':"alex"},**{'age': 73,'hobby': '吹'})
    #当函数的执行时:**dict 代表打散。
    
    
    # 函数外:处理剩余元素
    a,b,*c = [1,2,3,4,5]
    a,*c,b, = [1,2,3,4,5]
    a,*c = range(5)
    a,*c,b = (1,2,3,4,5,6)
    print(a,c,b)
    
  3. 形参角度的最终顺序

    *args的位置
    *args不能放在位置参数前面,a,b取不到值
    def func(*args,a,b,sex='man',):
        print(a)
        print(b)
        print(sex)
        print(args)
        # print(kwargs)
    func(1,2,4,5,6)
    
    args如果想要接收到值之前,肯定要改变sex默认参数。
    def func(a,b,sex='man',*args):
        print(a)
        print(b)
        print(sex)
        print(args)
        # print(kwargs)
    func(1,2,4,5,6)
    
    def func(a,b,*args,sex='man'):
        print(a)
        print(b)
        print(sex)
        print(args)
        # print(kwargs)
    func(1,2,4,5,6)
    func(1,2,4,5,6,sex='women')
    
    **kwargs
    位置参数,*args,默认参数,**kwargs
    def func(a,b,*args,sex='man',**kwargs,):
        print(a)
        print(b)
        print(sex)
        print(args)
        print(kwargs)
    func(1,2,4,5,6,name='太白',age=18)
    
    
  4. 函数的传参:形参角度:第四种传参方式(了解)

    位置参数,*args,默认参数,仅限关键字参数,**kwargs
    def func(a,b,*args,sex='man',c,**kwargs,):
        print(a)
        print(b)
        print(sex)
        print(c)
        print(args)
        print(kwargs)
    func(1,2,4,5,6,67,c=666,name='太白',age=18,)
    

函数的作用域

  1. 从空间角度研究函数

    全局名称空间: py文件运行时开辟的,存放的是执行的py文件(除去函数内部)的所有的变量与值(地址)的对应关系,整个py文件结束之后,才会消失。

    临时(局部)名称空间: 函数执行时,在内存中临时开辟的一个空间,存放的函数中的变量与值的对应关系,随着函数的结束而消失。

    内置名称空间:input,print,内置函数等。

    TIM图片20190618163607

    ![V05C~N6C[ECT6X11%CC876

    Z[GM0O~}JA4)D2R]MZMF($OD2R]MZMF($O.png)

  2. 取值顺序加载顺序

    加载顺序:上面这三个空间,谁先加载到内存。

    内置名称空间 ----》 全局名称空间 ----》 (函数执行时)临时名称空间

    取值顺序:(就近原则)

  3. 作用域

    全局作用域:全局名称空间,内置名称空间。

    局部作用域:局部名称空间。

  4. 内置函数:globals,locals

    """
    此文件研究的是内置函数 globals locals
    """
    # name = 'alex'
    # l1 = [1, 2, 3]
    #
    # def func():
    #     age = '18'
    #
    # print(globals()) # 全局作用域所有的内容
    # print(locals())  # 当前位置
    
    
    # name = 'alex'
    # l1 = [1, 2, 3]
    
    # def func():
    #     age = '18'
    #     oldboy = '老男孩教育'
    #     print(globals()) # 全局作用域所有的内容
    #     print(locals())  # 当前位置的变量与值的对应关系
    #
    # func()
    
    # name = 'alex'
    # l1 = [1, 2, 3]
    #
    # def func():
    #     age = '18'
    #     oldboy = '老男孩教育'
    #     def inner():
    #         name_class = 'python23期'
    #         print(globals()) # 全局作用域所有的内容
    #         print(locals())  # 当前位置的变量与值的对应关系
    #     inner()
    # func()
    
  5. 高阶函数(嵌套函数)

    # 例1:
    # def func1():
    #     print('in func1')
    #     print(3)
    # def func2():
    #     print('in func2')
    #     print(4)
    # func1()
    # print(1)
    # func2()
    # print(2)
    '''
    in func1
    3
    1
    in func2'
    4
    2
    '''
    
    # 例2:
    def func1():
        print('in func1')
        print(3)
    
    def func2():
        print('in func2')
        func1()
        print(4)
        
    print(1)
    func2()
    print(2)
    
    '''
    1
    in func2
    in func1
    3
    4
    2
    '''
    # # 例3:
    #
    def fun2():
        print(2)
        def func3():
            print(6)
        print(4)
        func3()
        print(8)
    
    print(3)
    fun2()
    print(5)
    
    '''
    3 2 4 6 8 5
    
    '''
    

关键字:global,nonlocal

# count = 0
#
# def func():
#     count += 1
# func()
# UnboundLocalError: local variable 'count' referenced before assignment
# 解释器认为:如果你在局部作用域对一个变量进行修改了,
# 你在局部作用域已经定义好这个变量了。

global

  1. 可以在局部作用域声明一个全局变量。

    # 这是剪切
    # def func():
    #
    #     global name
    #     name = 1
    #
    #     print(globals())
    #     # print(locals())
    #     name += 1
    #     print(globals())
    #
    #
    # func()
    # # print(name)
    # print(globals())
    
    
  2. 可以修改全局变量。

    # count = 0
    #
    # def func():
    #     global count
    #     count += 1
    #
    # print(count)
    # func()
    # print(count)
    

nonlocal

  1. 不能操作全局变量。
  2. 可以对父级作用域的变量进行修改,并且在当前作用域创建(复制)一份此变量。
# 这是复制
# def func():
#     count = 0
#     def inner():
#         nonlocal count
#         count += 1
#         print(count)
#         print(locals())
#     inner()
#     print(locals())
# func()
# UnboundLocalError: local variable 'count' referenced before assignment
# 解释器认为:如果你在局部作用域对一个变量进行修改了,
# 你在局部作用域已经定义好这个变量了。

默认参数的坑

# def func(a,b=False):
#     print(a)
#     print(b)
# func(1,True)
# 当你的默认参数如果是可变的数据类型,你要小心了。

# def func(a,l=[]):
#     l.append(a)
#     return l
# print(func(1))  # [1,]
# print(func(2))  # [2,]
# print(func(3))  # [3,]

函数名的应用

  • 函数名的内存地址
# a = 1
# b = 2
# c = a + b
# print(c)
# def func():
#     print(666)
#
# print(func)  # func = <function func at 0x00000000003F1EA0>
# 1,函数名指向的是函数的内存地址,加上()就执行这个函数。
# func()
  • 函数名可以作为一个变量赋值给其他变量
# age1 = 12
# age2 = age1
# age3 = age2
# print(age3)
# def func():
#     print(666)
#
# f1 = func
# f2 = f1
# f2()
# f1()

  • 函数名可以作为容器类类型的元素。
# a = 1
# b = 2
# c = 3
# l = [a,b,c]
# print(l)

# def func1():
#     print('in func1')
#
# def func2():
#     print('in func2')
#
# def func3():
#     print('in func3')
#
# l = [func1, func2, func3]
# # print(l)
# for i in l:
#     i()

  • 函数名可以作为函数的实参。
# a = 1
# def func(argv):
#     print(argv)
# func(a)

# def func1():
#     print('in func1')
#
# def func2(argv):
#     argv()
#     print('in func2')
#
# func2(func1)
  • 函数名可以作为函数的返回值
# b = 666
#
# def func1():
#     print('in func1')
#
# def func2(argv):
#     print('in func2')
#     return argv
# ret = func2(b)
# print(ret)



# def func1():
#     print('in func1')
#
# def func2(argv):
#     # argv = func1 : function 43543
#     print('in func2')
#     return argv
# ret = func2(func1)  # func1 : function 43543
# ret()

# def wrapper():
#
#     def inner():
#         print(666)
#     return inner
# # ret = wrapper()
# # ret()
# wrapper()()

python新特性:f-string格式化输出

# 1,不区分大小写
# num = input('>>>')
# s = F'python{num}'
# print(s)

# 可以加入表达式

# s1 = 'alex'
# s2 = f'我的名字{s1.upper()}'
# print(s2)

# l1 = ['太白', 18, 176]
# s1 = f'我的名字{l1[0]},我的年龄{l1[1]},我的身高{l1[2]}'
# print(s1)

# 可以结合函数
# def func(a,b):
#     return a + b

# s1 = f'最终的结果{func(1,3)}'
# print(s1)

# 不能放一些特殊的字符 ! , : { } ;
# print(f"替换结果{{{73}}}")
# print(f'{12,}')
posted @ 2018-07-14 20:55  Jacobyang  阅读(110)  评论(0编辑  收藏  举报