python之路14--函数、命名空间、作用域和三元运算

函数说明:

      通过使用函数,可以对程序进行更加好的组织。将一些相对独立的代码变成函数,可以提高程序的可读性和重用性。避免重复编写大量相同的代码。

在python中函数的定义

f = "www.71box.net"
def my_len():                #定义函数名,函数名和变量名一样的规则,def为关键字
    i = 0
    for k in f:
        i +=1
    print(i)
    return i             #设置函数返回值
my_len()              #执行函数

说明:函数定义后可以在任何需要它的地方调用,不能变,只能执行函数里面的代码;

当前函数的缺点:当前函数只可以计算变量f的长度;

函数的返回值说明

函数的返回值分为三种:

                                   1、没有返回值 -->返回None

                                                                                 1、不写return默认返回None

                                                                                 2、只写return,不写返回什么(一个函数遇到ruturn后,return后面的代码将不在执行,结束该函数)

                                   2、返回一个值

                                                           1、可以返回任何数据类型,只要返回就可以在函数外面用变量接收到;

                                                           2、如果在一个函数中有多个return,那么只执行第一个;

                                   3、返回多个值

                                                          1、用多个变量接收,有多少返回值就用多少变量接收

                                                           2、如果用一个变量接收,得到的是一个元组

定义可以传参的函数

def my_len(s):   #自定义函数只需要0个参数,接收参数,形式参数,简称形参
    i = 0
    for k in s:
        i += 1
    return i  #返回值
ret = my_len('www.71box.net')  #传递参数:传参,实际参数,简称实参
ret = my_len([1,2,3,4,5])      #传递参数:传参
print(ret)

参数说明

参数:
        1、没有参数
                            定义函数和调用函数时括号里都不写内容
        2、有一个参数
                               传的是什么就是什么
        3、有多个参数
                               也叫位置参数

定义一个带有位置参数的函数

def my_sum(a,b,c):
    print(a,b,c)
    res = a+b+c  #result
    return res
ret = my_sum(1,2,3)
print(ret)             #结果为:6
说明:按照顺序,1传给了a,2传给了b,3传给了c,所以也叫位置参数

定义一个带有默认参数的函数

def classmate(name,sex=''):                #默认参数为sex='男',如果传实参是不定义sex=,则默认为男
    print('%s : %s'%(name,sex))
classmate('欧阳')                 #结果为欧阳:男
classmate('李四')                 #结果为李四:男
classmate('小七','')            #结果为小七:女
classmate(sex='女',name='小妞') #结果为小妞:女 #此为关键字传参

说明:

站在实参的角度上:
                              可以按照位置传参
                              可以按照关键字传参
                              混着用也可以:但是 必须先按照位置传参,再按照关键字传参数
                              不能给同一个变量传多个值

站在形参的角度上
                            位置参数:必须传,且有几个参数就传几个值
                            默认参数: 可以不传,如果不传就是用默认的参数,如果传了就用传的

调用函数的时候
                         按照位置传 : 直接写参数的值
                         按照关键字: 关键字 = 值

定义函数的时候:
                          位置参数 : 直接定义参数
                          默认参数,关键字参数 :参数名 = '默认的值'

定义一个带有动态参数的函数

说明:

动态参数有两种:可以接收N个参数
                          1、*args :      接收的是按照位置传参的值,组织成一个元组
                          2、**kwargs: 接受的是按照关键字传参的值,组织成一个字典

1、*args

说明:

         动态参数 : 可以接受任意多个参数

         参数名之前加*,习惯参数名args,

def sum(*args):
    n = 0
    for i in args:
        n+=i
    return n
print(sum(1,2))
print(sum(1,2,3))
print(sum(1,2,3,4))

2、**kwargs

说明:

       动态参数,可以接收任意个关键字参数

        参数名之前加**,习惯参数名kwargs

def func(**kwargs):
    print(kwargs)
func(a = 1,b = 2,c =3)
func(a = 1,b = 2)
func(a = 1)

创建一个含有多种参数的函数

定义函数时形参的位置说明:    1、位置参数,2、*args,3、默认参数,4、**kwargs

def func(*args,default = 1,**kwargs):
    print(args,kwargs)
func(1,2,3,4,5,default=2,a = 'aaaa',b = 'bbbb',)

动态参数的另一种传参形式

def func(*args):    #站在形参的角度上,给变量加上*,就是组合所有传来的值。
    print(args)
func(1,2,3,4,5)
l = [1,2,3,4,5]
func(*l)     #站在实参的角度上,给一个序列加上*,就是将这个序列按照顺序打散

def func(**kwargs):
    print(kwargs)
func(a=1,b=2)
d = {'a':1,'b':2}     #定义一个字典d
func(**d)

函数的注释

def func():
    '''
    这个函数实现了什么功能
    参数1:
    参数2:
    :return: 是字符串或者列表的长度
    '''
    pass            #函数里的代码
func()              #调用函数

默认参数为可变类型的问题描述

如果默认参数的值是一个可变数据类型,那么每次调用函数的时候,如果不传值就共用这个数据类型的资源
def yisou(l = []):        #定义yisou函数,形参为可变的列表
    l.append(1)           #往列表里追加内容(每次调用就追加一次)
    print(l)              #打印列表内容
yisou()         #调用一次,结果为:[1]
yisou([])       #此次调用时传了一个空列表(即默认参数没有生效,当前的实参生效),然后追加1,结果还是:[1]
yisou()         #此次调用没传参数,结果为:[1, 1]
yisou()         #结果为:[1, 1, 1]

def vip(k,l = {}):     #定义函数vip(位置参数,默认参数 = {}),默认参数为一个空字典(可变类型)
    l[k] = 'v'         #默认参数[位置参数] = 'v',即往字典里添加内容
    print(l)           #打印默认参数          #显示结果
vip(1)             #第一次调用vip函数(1),传参为1,结果为:{1: 'v'}
vip(2)             #第二次调用vip函数(2),传参为2,结果为:{1: 'v', '2':'v'}
vip(3)             #第三次调用vip函数(3),传参为3,结果为:{1: 'v', 2: 'v', 3: 'v'}

函数的总结:

函数说明:可读性强,复用性强

 

定义函数:

所有的函数,只定义不调用就一定不执行(先定义后调用)

def 函数名():
    函数体
    return 返回值
        
函数名()          #调用函数、不接收返回值
返回值 = 函数名()     #接收返回值

返回值:
没有返回值
不写return:默认返回None(函数内的代码执行结束,自动结束)、
只写return不写返回值:(可以结束函数)、
return None:返回结果即为None
返回一个值
结束了函数并且返回一个值(返回的这个值可以是任意值)
返回多个值
多个值之间用逗号隔开,接收的时候可以用一个变量接收(接收到的是一个元组),也可以用等量的多个变量接收(返回的是啥,接收到的就是啥),

参数:
形参
定义的函数的时候(def 函数名(形参))
形参的位置顺序:
1、位置参数(必须传),
2、*args(动态参数,可以接收任意多个按位置传入的参数),
3、默认参数(可以不传),
4、**kwargs(动态参数,可以接收任意多个按关键字传入的参数)
实参
调用函数的时候(函数名(实参))
1、按照位置传参
2、按照关键字传参(可以混用,位置参数必须在关键字传参之前、不能对一个参数重复赋值)

动态参数的名一种传参方法:
def wa(*args):
    print(args)
l = [1,2,3,4]
wa(*l)          #另一种*args的调用方法  

命名空间

命名空间说明:
1、内置命名空间(和python解释器有关):
就是python解释器一启动就可以使用的名字存储在内置命名空间中,内存的名字在启动解释器的时候被加载进内存里,如(print\input\len等)
在内置命名空间中:不能使用局部命名空间的名字和全局命名空间的名字
2、全局命名空间(和写的函数外的代码有关):
在程序从上到下被执行的过程中依次被加载进内存的,放置了我们设置的所有变量名和函数名
在全局命名空间:可以使用内置命名空间中的名字,但是不能用局部命名空间的名字
3、局部命名空间(和函数内的代码有关):
就是函数内部定义的名字,当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了
在局部命名空间:可以使用全局,内置命名空间的名字
画图说明:

实操演示命名空间下变量之间的调用

1、函数调用全局命名空间的变量

1、从局部命名空间调用全局命名空间的变量
a = 1           #在全局命名空间定义变量
def budao():    #定义函数
    print(a)    #再函数里调用全局命名空间的变量
budao()         #结果为1

2、从全局命名空间调用局部命名空间的变量会报错
def budao():     #定义函数
    a = 1        #函数内容为a = 1,再局部命名空间
print(a)       #再全局命名空间调用局部命名空间的变量,此时会报错

2、命名空间的调用优先级说明

说明:
在正常情况下,直接使用内置的名字,
当我们在全局定义了和内置命名空间中同样的名字时,会使用全局的名字,
当我自己有的时候,我就不找上级要了,如果我自己没有就找上级要,如果最上级也没有就再找上级,如果内置的命名空间都没有就会报错
画图说明:

实操说明:

def input():                    #在全局命名空间定义一个input函数,和内置函数一样的名字
    print('in input now')      #函数体为这个

def func():                   #在全局命名空间定义另一个函数
    input()                   #函数体为input,此时input为全局命名空间的input,也就是上面定义的input函数
func()                              #此时我执行func函数,调用的是全局命名空间的函数,并不是内置命名空间的input

def fun():             #在全局命名空间里定义了另一个函数
    input = 1          #函数体为input = 1
    print(input)       #打印input的结果为1,因为我局部命名空间有input这个变量,就不去全局命名空间去找了
fun()                  #执行函数

func1 vip1():       #在全局命名空间定义vip1函数,
    a = 1           #函数主体为a = 1
func2 vip2():       #在全局命名空间定义函数vip2
    print(a)        #函数主体是调用vip1函数局部空间的a,
vip2()              #执行vip2,会报错,
说明:多个函数,每个函数拥有单独的局部命名空间,不互相共享。

作用域

作用域的种类及说明:

全局作用域:

                  作用在全局:内置和全局命名空间中的名字都属于全局作用域,可以用globals查看全局命名空间的变量及内置变量

局部作用域:

       作用在局部:函数(局部名字空间中的名字属于局部作用域),可以用locals查看局部的命名空间的变量(locals:查看当前命名空间的变量)
a = 1           #明空间里定义变量a = 1
def func():     #定义函数func
    global a    #global a声明a(表示当前局部命名空间的a可以作用于全局)
    a += 1      #修改变量a
func()          #执行函数
print(a)        #结果为2,
说明:
     对于不可变的数据类型,在局部可是查看全局作用域中变量,但是不能直接修改。
     如果想要修改,需要在程序的一开始添加global生明
     如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效,(写代码时尽量少用global,如果想在外面调用局部变量可以用return返回)


a = 1
b = 2
def func():
    x = 'aaa'
    y = 'bbb'
    print(locals())         #locals:查看局部命名空间的变量
func()
print(globals())            #可以查看全局命名空间的变量,和内置的变量
说明:
     globals:永远打印全局的名字
     locals:输出什么,根据locals所在的位置,在全局就打印全局的名字,在局部就打印局部的名字

函数的嵌套

a = 1                        #全局命名空间定义了变量a = 1
def outer():                 #定义函数outer    a = 1                    #局部命名空间里定义a = 1    def inner():             #在outer函数里定义了另一个函数        b =2                 #定义了变量b = 2        print(a)             #此时打印变量a  -->打印的时outer函数里的变量a        print('inner')       #打印字符串inner        def inner2():        #在函数inner里定义另一个函数innner2            nonlocal a          #nonlocal:声明了上层的第一个的局部变量,            a += 1               #不可变的数据类型修改,需要要声明,(局部变量声明用nonlocal、全局变量声明用global)            print('innner2')        inner2()          #结果为inner2,因为并没有输入a +=1的结果,只是做了计算    inner()               #这里打印的是outer里的a,没有做修改的,结果为1    print('****',a)       #这里打印的是inner2里已经做过a += 1之后的a了,a += 1时用在outer函数下的a上的,结果为2outer()#nonlocal:只能用于局部变量,找出上层中离当前函数最近的一层的局部变量、声明了nonlocal的内部函数的变量修改会影响到里当前函数最近一层的局部变量

函数名的本质

说明:
可以被引用,可以被当作容器类型的元素,,可以当作函数的参数和返回值(即可以当作普通变量使用),
第一类对象:可以在运行期创建,可以做函数参数或返回值,可存入变量实体
操作:
1、
def func():          #函数名就是内存地址,
    print(123)
func2 = func         #函数名可以赋值
func2()               #执行结果为:123
rint(func,func2)          #结果为:<function func at 0x0000020BF6A45AE8> <function func at 0x0000020BF6A45AE8>     两块内存地址

l = [func,func2]             #函数名可以作为容器类型的元素
print(l)                     #结果内两块内存地址
for i in l:                 #循环函数名,
    i()                     #调用函数

2、

def func():           #定义func函数
    print(123)        #函数体

def func2(f):         #定义func2函数,并设置形参f
    f()               #调用形参,结果为123
    return f          #函数名可以作为函数的返回值来返回
func2(func)           #执行func2函数,并将上面的func函数当实参传给func2的形参

闭包

说明:

       闭包即为内部的函数调用外部函数的变量。

操作:

def outer():         #定义函数
    a = 1            #函数体
    def inner():     #在outer函数里又定义了一个函数,这是一个闭包
        print(a)      #函数体,调用上级函数里的变量了
    return inner     #将outer函数里的函数inner作为返回值
inn = outer()         #在全局里接收返回值
inn()                 #在外面接收函数返回值后再外面执行outer函数下的inner函数,
#说明:由于outer里定义了变量a=1,且被inner函数调用,同时inner函数被当返回值传到外面,外面调用了inner函数,这样,a = 1这个变量使用后就不会清除,而是等到整个程序结束后才清除,这样节省了这个变量的生成和清除的时间

 三元运算

说明:

        1、使用三元运算的条件:1、必须要有结果,2、必须要有if和else,3、只能时简单的情况,如果负责则三元运算实现不了

实操:

a = 3          #定义变量a = 3
b = 2          #定义变量b = 2
print(a) if a > b else print(b)     #语法说明:条件为True的结果(这个结果可以直接打印,或变量接收等)  if  条件  else  条件为False的结果

 

 

 

 

 

 


 

 

 


 





posted @ 2018-07-25 22:44  欧-阳  阅读(115)  评论(0)    收藏  举报