007 函数

  1.   1 # 函数的引入:
      2 # 在程序中,具备“某一功能”的工具就是函数,
      3 # “事先准备工具”的过程就是函数的定义
      4 # “拿来就用”就是函数的定义
      5 
      6 # 定义函数:
      7 # 函数的使用必须遵从先定义后使用的原则
      8 # 函数体为pass代表什么都不做,称之为空函数。
      9 
     10 # 函数的使用分为定义阶段和使用阶段,定义阶段只检测语法
     11 # 不执行函数体代码,函数名加括号即函数调用,只有调用时才会执行函数体代码
     12 
     13 def foo():
     14     print('foo函数')
     15     bar()
     16 
     17 
     18 def bar():
     19     print('bar函数')
     20 
     21 
     22 foo()
     23 '''
     24 # 解释by李基鹏:foo函数内调用了bar函数,但是此时bar函数还未加载到内存,未报错,说明定义阶段只检测语法,不执行函数内的代码。
     25 # 解释by林海峰:定义阶段函数foo和bar均无语法错误,而在调用阶段调用foo函数时,函数foo和bar都早已经存在于内存中了,所以不会出现任何问题。
     26 result:
     27 foo函数
     28 bar函数
     29 '''
     30 
     31 
     32 # 调用有参函数时,实参(变量值)会赋值给形参(变量名),在函数调用时生效,函数调用结束后解除绑定关系
     33 
     34 def register(name, age, sex=''):  # 默认参数必须在位置参数后面
     35     return 'name:%s age:%s sex:%s' % (name, age, sex)
     36 
     37 
     38 # register() TypeError: register() missing 3 required positional arguments: 'name', 'age', and 'sex'
     39 print(register('李基鹏', 31, ''))
     40 print(register(age=31, sex='', name='李基鹏'))  # 关键字实参
     41 # print(register(sex='男',18,name='李基鹏')) # 位置实参必须在关键字实参前面
     42 print(register('李基鹏', age=31, sex=''))  # 位置实参必须在关键字实参前面
     43 
     44 print(register('egon', 18))  # 带默认参数函数的调用
     45 
     46 # 默认参数的值仅在定义阶段被赋值一次
     47 x = 1
     48 
     49 
     50 def foo(arg=x):
     51     print(arg)
     52 
     53 
     54 x = 5
     55 foo()  # 定义阶段arg的值被赋值成1,此处没有传值相当于用的默认值1
     56 
     57 
     58 # 默认参数通常为不可变类型
     59 # def foo(n, arg=[]):  # 此处arg是列表可变类型,应该修改为不可变类型
     60 #     arg.append(n)
     61 #     return arg
     62 
     63 
     64 def foo(n, arg=None):
     65     if arg is None:
     66         arg = []
     67     arg.append(n)
     68     return arg
     69 
     70 
     71 print(foo(1))
     72 print(foo(2))
     73 print(foo(3))
     74 
     75 
     76 # 参数的长度可变指的是在调用函数时,实参的个数可以不固定,而在调用函数时,实参的定义无非是按位置或者按关键字两种形式
     77 # 这就要求形参提供两种解决方案来分别处理两种形式的可变长度的参数。
     78 
     79 def foo(x, y, z, *args):
     80     print(x)
     81     print(y)
     82     print(z)
     83     print(args)  # (4, 5, 6, 7)
     84 
     85 
     86 foo(1, 2, 3, 4, 5, 6, 7)  # 1、2、3按照位置参数传给x、y、z,4,5,6,7以元祖的形式传给args
     87 
     88 L = [4, 5, 6, 7]  # L为列表形式
     89 foo(1, 2, 3, *L)
     90 L = (4, 5, 6, 7)  # L为元组形式
     91 foo(1, 2, 3, *L)
     92 
     93 # 传入时L未加*号,相当于是作为元组的第一个元素传入了
     94 L1 = (8, 9, 10)
     95 foo(1, 2, 3, L, L1)  # L为元组的第一个元素,L1为元组的第二个元素
     96 
     97 '''
     98 1
     99 2
    100 3
    101 ((4, 5, 6, 7),)
    102 '''
    103 foo(1, 2, 3, L, *L1)  # 相当于L作为元组的第一个元素,L1里面的8、9、10作为元组的第二个、第三个、第四个元素
    104 
    105 '''
    106 1
    107 2
    108 3
    109 ((4, 5, 6, 7), 8, 9, 10)
    110 '''
    111 
    112 
    113 # 如果形参为常规的参数(位置或默认),实参仍然可以是*的形式,我理解为就是打散后传给形参
    114 def foo1(x, y, z=3):
    115     print(x)
    116     print(y)
    117     print(z)
    118 
    119 
    120 foo1(*(1, 2))  # 相当于是将1、2打散后传给x、y
    121 
    122 
    123 # 求多个数字的和(个数不定)
    124 def foo(*args):
    125     res = 0
    126     for i in args:
    127         res += i
    128     return res
    129 
    130 
    131 print(foo(1, 2, 3, 4))
    132 print(foo(1, 2, 3))
    133 
    134 
    135 # 可变长度的关键字参数
    136 # 如果在最后一个形参名前加**后,那么在函数调用时,溢出的关键字参数都会被接收,以字典的形式保存下来赋值给该形参
    137 
    138 def foo(x, **kwargs):
    139     print(x)
    140     print(kwargs)
    141 
    142 
    143 foo(x=1, y=2, z=3)
    144 '''
    145 1
    146 {'y': 2, 'z': 3}
    147 '''
    148 foo(y=2, z=3, x=1)
    149 
    150 '''
    151 1
    152 {'y': 2, 'z': 3}
    153 '''
    154 
    155 
    156 # 如果我们事先生成了一个字典,也是可以传值给**kwargs
    157 def foo(x, y, **kwargs):
    158     print(x)
    159     print(y)
    160     print(kwargs)
    161 
    162 
    163 dic = {'a': 1, 'b': 2}
    164 # 字典的key必须是字符串类型
    165 # key和value之间是:
    166 foo(3, 4, **dic)
    167 
    168 
    169 # 如果在传入dic时,没有加**,那dic就只能是一个普通的位置参数了
    170 # foo(3, 4, dic)
    171 
    172 
    173 # foo() takes 2 positional arguments but 3 were given,相当于多给了一个位置参数
    174 
    175 # 如果形参是常规参数(位置参数或者默认参数),实参仍然可以是**的形式
    176 def foo(x, y, z=3):
    177     print(x)
    178     print(y)
    179     print(z)
    180 
    181 
    182 foo(**{'x': 1, 'y': 2})
    183 
    184 
    185 # 如果我们要编写一个用户认证的函数,最开始可能只需要用户名密码就可以了,**kwargs可以为该函数提供扩展,同时保持了代码的简洁性
    186 # **kwargs是未命名的关键字参数
    187 def register(name, age, **kwargs):
    188     if 'sex' in kwargs:
    189         # 如果字典内有sex属性执行代码
    190         pass
    191 
    192     if 'height' in kwargs:
    193         # 如果字典内有height属性执行代码
    194         pass
    195 
    196 
    197 # 想要限定函数的调用者必须用key=value的形式传值,python3提供了专门的语法
    198 # 需要在定义形参时用*作为分隔符号,*之后的形参被称为命名关键字参数
    199 # 对于这类参数,在函数调用时实参必须以key=value的格式传参,且必须传参
    200 def register(name, age, *, sex, height):
    201     pass
    202 
    203 
    204 # register('李基鹏', 31, sex='男')  # TypeError:register()缺少1个只需要关键字的参数:“height”
    205 # register('李基鹏', 31, sex='男', height=181, width=18) # TypeError:register()收到意外的关键字参数“width”
    206 register('李基鹏', 31, sex='', height=181)  # 正确调用
    207 
    208 
    209 # register('李基鹏', 31, '男', height=181)  # TypeError:register()接受2个位置参数,但给出了3个位置参数(和1个仅关键字参数)
    210 
    211 
    212 # 命名关键字也可以有默认值,从而简化调用
    213 def register(name, age, *args, sex='male', height):
    214     print('name:%s age:%s sex:%s height:%s' % (name, age, sex, height))
    215 
    216 
    217 # sex不是默认参数,height也不是位置参数,因为他两都在*后,所以是命名关键字参数
    218 # 'male'属于命名关键字参数sex的默认值,因此放在height之前也没问题
    219 # 如果形参中已经有一个args了,就不需要单独的*作为分割了
    220 
    221 
    222 register('lili', 28, height=181)  # 正确调用
    223 register('gege', 30, sex='female', height=191)  # 正确调用
    224 register('egon', 18, 'python', '自动化', height=190)
    225 
    226 
    227 # 所有参数都可以任意组合使用,但顺序必须是位置参数>默认参数>*args或者*>命名关键字参数>**kwargs
    228 def test(x, y, z=3, *args, sex='male', height, **kwargs):
    229     print(x)
    230     print(y)
    231     print(z)
    232     print(args)
    233     print(sex)
    234     print(height)
    235     print(kwargs)
    236 
    237 
    238 test(1, 2, 5, 6, 7, sex='female', height=190, hobby='eat')
    239 '''
    240 1
    241 2
    242 5
    243 (6, 7)
    244 female
    245 190
    246 {'hobby': 'eat'}
    247 '''
    248 
    249 
    250 # 可变参数*args和关键字参数**kwargs通常是一起组合使用的,如果一个函数的形参为*args和**kwargs,那么这个函数是可以接收任意形式、任意长度的参数。
    251 
    252 
    253 def func(x, y, z):
    254     print(x)
    255     print(y)
    256     print(z)
    257 
    258 
    259 def warpper(*args, **kwargs):
    260     func(*args, **kwargs)
    261 
    262 
    263 # warpper(1, 2, y = 3) # func()为参数“y”获取了多个值
    264 # warpper(1, 2, z=3)
    265 # warpper(x=1, y=2, z=3)
    266 warpper(1, z=3, y=2)
    267 
    268 # warpper(1, z=3, y=2)相当于是将1被*接收赋值给了args以元组的形式保存下来,z=3、y=2被**接收赋值给了kwargs以字典的形式保存下来
    269 # 即args = (1,)
    270 # kwargs = {z:3,y:2}
    271 # 调用func(*args,**kwargs)即func(*(1,),**{z:3,y:2})
    272 # 等同于func(1,z=3,y=2),所以打印结果为123

     

      1 import requests
      2 
      3 # 在程序执行期间,最多存在3种名称空间
      4 # x = 3
      5 # print(x)
      6 # del x  # 删除x的引用
      7 # # print(x)
      8 
      9 # 内建名称空间:
     10 # 生命周期:伴随着python解释器的启动而启动,关闭而回收
     11 # 是第一个被加载的名称空间,用来存放一些内置的名字
     12 # print(max)  # <built-in function max>
     13 
     14 # 全局名称空间:
     15 # 生命周期:伴随着python文件的执行而存在,执行结束而回收
     16 # 是第二个被加载的名称空间,文件执行过程中产生的名字都会存在于该名称空间中
     17 
     18 # 局部名称空间:
     19 # 生命周期:伴随着函数的调用而产生,调用结束而回收
     20 # 是第三个被加载的名称空间,函数的形参、函数内定义的名字都会存放于该名称空间中
     21 
     22 # 按照名字作用范围的不同,可以将三个名称空间划分为两个区域。
     23 x = 100
     24 
     25 
     26 # locals():查看局部作用域的名字
     27 # globals():查看全局作用域的名字
     28 def foo():
     29     x = 300
     30     print(x)
     31     print(locals())
     32     print(globals())
     33 
     34 
     35 foo()
     36 print(locals())  # 全局作用域查看locals()等于globals()
     37 print(globals())
     38 x = 1
     39 
     40 
     41 def outer():
     42     x = 2
     43 
     44     def inner():  # 函数名inner属于outer这一层作用域的名字,函数未调用时不执行函数体代码,切记切记切记
     45         x = 3
     46         print('inner x:%s' % x)
     47 
     48     inner()
     49     print('outer x:%s' % x)
     50 
     51 
     52 print('全局 x:%s' % x)
     53 
     54 outer()
     55 
     56 # 若要在局部作用域内修改全局名称空间的值,则需要用到global关键字
     57 x = 1
     58 
     59 
     60 def foo():
     61     global x  # 声明x为全局的
     62     x = 3
     63     x = 2
     64     x = 1
     65     print(x)  # 这里打印的x也是全局的
     66 
     67 
     68 foo()
     69 print(x)
     70 
     71 # 当实参的值为可变类型时,函数体内对该值的修改,将直接反映到原值
     72 
     73 num_list = [1, 2, 3]
     74 
     75 
     76 def foo(nums):
     77     nums.append(5)
     78 
     79 
     80 foo(num_list)
     81 print(num_list)
     82 
     83 
     84 # 对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)
     85 
     86 def f1():
     87     x = 1
     88 
     89     def f2():
     90         nonlocal x
     91         x = 2
     92 
     93     f2()  # 调用f2其实是修改的f1作用域中x的值
     94     print(x)  # 打印x,打印的是修改后的x的值
     95 
     96 
     97 f1()
     98 
     99 
    100 # 函数对象指的是函数可以被当做数据来处理,具体可分为四个方面的使用
    101 
    102 def add(a, b):
    103     return a + b
    104 
    105 
    106 func = add  # 1、函数可以被引用
    107 print(func(1, 2))
    108 
    109 
    110 # 2、函数可以作为容器类型的元素
    111 def max(a, b):
    112     return a if a > b else b
    113 
    114 
    115 dic = {'add': add, 'max': max}
    116 print(dic['add'](3, 4))
    117 print(dic['max'](5, 6))
    118 
    119 
    120 # 3、函数可以作为参数传入另外一个函数
    121 
    122 def foo(a, b, xxx):
    123     return add(a, b)
    124 
    125 
    126 print(foo(10, 20, add))
    127 
    128 
    129 # 4、函数的返回值可以是一个函数
    130 
    131 def bar():
    132     return add
    133 
    134 
    135 print(bar()(20, 30))
    136 
    137 # 闭包函数
    138 # 基于函数对象的概念,可以将函数返回到任意位置去调用,但作用域的关系是在定义完函数时就已经被确定
    139 # 了的,与函数的调用位置无关。
    140 x = 1
    141 
    142 
    143 def f1():
    144     def f2():
    145         print('x = ' + str(x))
    146 
    147     return f2
    148 
    149 
    150 def f3():
    151     x = 3
    152     f2 = f1()
    153     f2()
    154 
    155 
    156 f3()
    157 
    158 x = 1
    159 
    160 
    161 def outer():
    162     x = 2
    163 
    164     def inner():
    165         print(x)
    166 
    167     return inner
    168 
    169 
    170 func = outer()
    171 func()
    172 
    173 print(func.__closure__[0].cell_contents)  # 可以查看闭包函数所包裹的外部变量
    174 
    175 
    176 # 为函数传值的两种方式
    177 def get(url):
    178     return requests.get(url).text
    179 
    180 
    181 url = get('https://www.baidu.com')
    182 print(url)
    183 
    184 
    185 def page(url):
    186     def get():
    187         return requests.get(url).text
    188 
    189     return get
    190 
    191 
    192 message = page('https://www.baidu.com')
    193 print(message())

     

posted @ 2024-11-13 15:31  lzp123456  阅读(1)  评论(0编辑  收藏  举报