每一种编程语言,都会有自己函数的语法格式,正是因为我们有了函数,才是我们的代码变得更加模块化,代码的利用率大大增加,尽可能的避免代码的冗余。其实,在所有的编程中函数的作用都是一样的,因为重复代码多,可读性差,所以就有了函数的产生,函数就是封装一个功能。为什么Python好用,就是因为Python内部本身帮我们封装了好多函数。减少了我们对编程的复杂度。Python内部封装好的函数叫内建函数,但是我们自己当然也是可以编写函数的,这叫自定义的函数。

函数的定义和调用

自己来写一个函数:

#函数定义
def area(r):
       s = r*r*3.14
       return s   
 area(5)

Python中函数定义的方法:

**定义:def 关键词开头,空格之后接函数名称和圆括号(),最后还有一个":"。
   def 是固定的,不能变,他就是定义函数的关键字。
   空格 为了将def关键字和函数名分开,必须空
   函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能
   括号:是必须加的,里面是可以带有参数的。比如,我们这个函数就是带参数的(后面再写关于参数的问题),当然,也可以不带参数。
注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。
调用:就是 函数名() ,你有参数就需要在括号里传相应的参数,如果没有就是空,但是必须要写。
**

函数的返回值

return :将值返回给函数的调用者,函数的返回值分为四种:

  • 无 return
  • return None
  • return 1个值 该值是什么,就直接返回给函数的调用者,函数名()
  • return 多个值 将多个值放到一个元组里,返回给函数的调用者。

需要注意的说,函数只要遇到return。整个函数就结束了,并给你相对应的返回值,函数值中最好或者说尽量不要输出print语句。

函数的传参

任何一种编程语言中的函数,函数的参数都有两种方式:形参和实参,就拿上面的例子来讲,def area(r):中的r就是形式参数, area(5) 就是实际参数。还有人还是分不清这两个,这么来告诉你,函数中传递的参数就是形参,调用函数时,你用的就是实参。
如果按照参数调用函数的话,那就要一一对应。

def func(a,b,c):
     print(a)
     print(b)
     print(c)
 func('fdsafdas',3,4)

动态传参

def func(*args):
    print(args)
    func(1,2,3,4,5,7,8,9,1,2,3,4,5,6,7,8)

*args 动态参数,你也可以说是万能参数,args接受的就是实参对应的 所有位置参数,并将其放在元组中。

形参对应顺序
位置参数,*args,默认参数,给个例子:

def func(a,b,c,d,*args,e='男'):
    print(a)
    print(b)
    print(c)
    print(d)
    print(args)
    print(e)
func(1,2,3,4,5,6,7,e='女')

**kwargs 动态传参,他将所有的关键字参数(无意义的)放到一个字典中。

def func(a,b,c,**kwargs):
     print(kwargs)
 func(1,2,r=4,b1=5,c1=6,c=7,)
 
def func(a,b,c,d,*args,e='男',**kwargs):
     print(a)
     print(b)
     print(c)
     print(d)
     print(args)
     print(e)
     print(kwargs)
 func(1,2,3,4,5,6,7,v=3,m=7,h=9,e='女')

那么,给出一个最终的函数的传参顺序:

**位置参数,*args默认参数,**kwargs

def func1(*args,**kwargs):
     pass
 func1()
 
 * 魔法运用
 def func(*args):
     print(args) #(1,2,30,1,2,33.。。。。。)
 l1 = [1,2,30]
 l2 = [1,2,33,21,45,66]
 tu = (1,2,3)
 func(1,2,30,1,2,33,21,45,66)
 func(*'qweqrfdsaf')
 func(*{'name':'alex',"age":12})
 func(*l1,*l2)
 def func(*args):
     print(args)
 func(1,2,3,10,20,80)
 
 def func(**kwargs):
     print(kwargs)
 
 dic1 = {'name1':'alex','age1':46}
dic2 = {'name':'jj','age':56}
 func(**dic1,**dic2)

在函数的调用执行时, *args可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args。 **kwargs字典,代表打散,将所有键值对放到一个kwargs字典里。
**在函数定义时,*args,**kwargs代表的是聚合。

def func(*args,**kwargs):
     print(args)
     print(kwargs)
 
 dic1 = {'name1':'alex','age1':46}
 dic2 = {'name':'老男孩','age':56}
 func(*[1,2,3,4],*'asdfsad',**dic1,**dic2)
 
def func(*args,**kwargs):
    args = (1,2,3,4)
    kwargs = {'age': 56, 'name': '老男孩'}
     print(*args)
     print(**kwargs) #(age = 56 ,name = 老男孩)
 dic1 = {'name1':'alex','age1':46}
 dic2 = {'name':'老男孩','age':56}
 func(*[1,2,3,4],*'asdfsad',**dic1,**dic2)
 func(**dic2)

命名空间

每一个变量都有自己的变量存储位置,那么存放名字与值的关系’的空间起了一个名字-------命名空间。
命名空间一共分为三种:

全局命名空间:可以理解为,从开始时就已经创建变量并且贯穿整个代码,我们可以随时调用。

局部命名空间:可以理解为,我们临时创建的变量,它只能在某一个地方调用该变量。

内置命名空间:内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple…它们都是我们熟悉的,拿过来就可以用的方法

三种命名空间之间的加载与取值顺序:

加载顺序

内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

取值顺序

局部调用:局部命名空间->全局命名空间->内置命名空间

全局调用:全局命名空间->内置命名空间

综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。

作用域

作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围内生效

globals和locals方法

在全局调用globals和locals

print(globals())
print(locals())

在局部调用locals和globals

def func():
    a = 12
    b = 20
    print(locals())
    print(globals())

func()       ##执行结果:{'a': 12, 'b': 20}
{'__spec__': None, '__file__': 'D:/myPython/data/作用域.py', '__doc__': None, '__builtins__': <module 'builtins' (built-in)>, 'func': <function func at 0x00000241FE045378>, '__name__': '__main__', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000241FDBF8F28>, '__cached__': None, '__package__': None}

global关键字,nonlocal关键字

global

1,声明一个全局变量。

2,在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。

def func():
    global a
    a = 3
func()
print(a)
 
 
count = 1
def search():
    global count
    count = 2
search()
print(count)

需要注意的是,对可变数据类型(list,dict,set)可以直接引用不用通过global

li = [1,2,3]
dic = {'a':'b'}
 
def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
change()
print(li)
print(dic)

nonlocal

1,不能修改全局变量。

2,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)
        dd_nonlocal()
        print(b)
    do_global()
    print(b)
add_b()

函数的嵌套和作用域链

函数的嵌套调用

def max2(x,y):
    m  = x if x>y else y
    return m
 
def max4(a,b,c,d):
    res1 = max2(a,b)
    res2 = max2(res1,c)
    res3 = max2(res2,d)
    return res3
max4(23,-7,31,11)

函数的嵌套定义

def f1():
    print("in f1")
    def f2():
        print("in f2") 
    f2()
f1()

##执行结果:in f1
in f2

def f1():
        def f2():
            def f3():
                print("in f3")
            print("in f2")
            f3()
        print("in f1")
        f2()
    f1()

执行结果:
in f1
in f2
in f3

函数的作用域链

小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。

def f1():
    a = 1
    def f2():
        def f3():
            print(a)
        f3()
    f2()
 
f1()

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

def f1():
    a = 1
    def f2():
        a = 2
    f2()
    print('a in f1 : ',a)
 
f1()

函数名的本质
函数名本质上就是函数的内存地址。

1.可以被引用

def func():
    print('in func')
 
f = func
print(f)

2.可以被当作容器类型的元素

def f1():
    print('f1')

def f2():
    print('f2')
 
def f3():
    print('f3')
    
l = [f1,f2,f3]
d = {'f1':f1,'f2':f2,'f3':f3}
#调用
l[0]()
d['f2']()

3.可以当作函数的参数和返回值

def f1():
    print('f1')
 
def func1(argv):
    argv()
    return argv
 
f = func1(f1)
f()

第一类对象(first-class object)指
1.可在运行期创建
2.可用作函数参数或返回值
3.可存入变量的实体。

闭包

def func():
name = ’ luckfariy ’
def inner():
print(name)

闭包函数

内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数
函数内部定义的函数称为内部函数

由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们非得要拿到?那就返回呀!函数内的变量我们要想在函数外部用,可以直接返回这个变量,那么如果我们想在函数外部调用函数内部的函数呢?是不是直接就把这个函数的名字返回就好了?

这才是闭包函数最常用的用法

def func():
    name = ' luckfariy '
    def inner():
        print(name)
    return inner

f = func()
f()

判断闭包函数的方法__closure__

#输出的__closure__有cell元素 :是闭包函数
def func():
    name = ' luckfariy '
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f = func()
f()

#输出的__closure__为None :不是闭包函数
name = ' luckfariy '
def func2():
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

f2 = func2()
f2()

闭包嵌套

def wrapper():
    count = 1000
    def func():
        name = ' luckfariy '
        def inner():
            print(name,count)
        return inner
    return func
 
f = wrapper()
i = f()
i()

闭包函数获取网络应用

from urllib.request import urlopen
 
def index():
    def get():
        return urlopen(url).read()
    return get
 
luckfariy = index()
content =  luckfariy ()
print(content)

将函数封装成python函数 函数的封装python_将函数封装成python函数


将函数封装成python函数 函数的封装python_作用域_02


将函数封装成python函数 函数的封装python_将函数封装成python函数_03