博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

二、Python开发---11、函数

Posted on 2019-10-06 21:51  兰智杰  阅读(261)  评论(0编辑  收藏  举报

pycharm退出test模式

  由于各种原因,pycharm有test字段,或者有test的函数时,会莫名奇妙的进入test模式,有时候怎么也跳不出来,要退出这种模式,在运行键旁边进入‘Edit configuration’模式,可以看到左侧Python下有两个文件,如果进入了test模式,就会有‘Python test’一栏,这时点击‘-’号去掉这栏下的文件即可

          

定义函数

  格式:

    def 函数名(参数):     

      函数体

  函数名其实就是指向一个函数对象的引用,完全可以把函数名赋值给一个变量,相当于给这个函数起了一个别名

def Pname():        #当前函数不放参数
     print('大家好我是杰大哥!')
Pname()             #调用函数  执行了函数里面的代码
pri = Pname         #将函数名赋值给另一个变量,相当于给当前函数取一个别名
pri()               #pri()的作用等于Pname()

函数参数分类

  总体上分为形参和实参

  1、必备参数

    向函数传递参数的方式有很多,通过实参和形参的顺序对应,这就是位置实参,参数的个数不能少,不能多,参数的位置要一一对应,只有位置一致,才能被正确匹配

  2、关键字参数

    关键字实参是传递给函数的名称-值对;直接在实参中将名称和值关联起来,因此向函数传递实参时不会混淆,使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值

  3、默认参数

    函数定义的时候,设置的参数是形参;那么也可以给每个形参指定一个默认值,当调用函数时,如果没有传入实参,就使用形参的默认值,如果调用的时候传入了实参,那么程序将使用传入的实参

  4、不定长参数

     可能需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数;加了星号(*)的变量名会存放所有未命名的变量参数,按元组的类型存放,加了(**)会存放所有命名的变量参数,按字典的类型存放

def Pname(userName):                      #userName为形参  形参的名字是自定义的
    print('大家好我是%s同学!'%userName)
Pname('刘德华')                            #传递了一个实参  '刘德华'

#必备参数
def getInfo(name,address):
    print('大家好我叫%s,我来自%s'%(name,address))
getInfo('刘德华','香港')                   #第一个实参对应了第一个形参,第二实参对应第二个形参
# getInfo('刘德华')                         #形参有两个,调用的时候,实参也要传递两个,否则会报错
                                          #参数的个数不能少,不能多。 参数的位置要一一对应

#关键字参数
def getInfo(name,address):
    print('大家好我叫%s,我来自%s'%(name,address))
getInfo(name='刘德华',address='香港')      #给实参加上关键字  关键字对应着形参

#参数的默认值
def getInfo(name,address = '香港'):       #默认值参数,就是在声明函数的时候给形参赋值
    print('大家好我叫%s,我来自%s'%(name,address))
getInfo('刘德华')                         #有默认值的形参,可以不用传递
getInfo('刘德华','九龙')                   #传递参数时,会覆盖原来的默认值
'''
    不定长参数
    *args 是接受所有未命名的参数(关键字)
    **agrs2 是接受所有命名的参数(带关键字的)
    输出为
        大家好我叫刘德华,我来自九龙
        ('a', 'b', 'c', 'd')
        {'age': 18}
'''
def getInfo(name,address,*args,**agrs2):
    print('大家好我叫%s,我来自%s'%(name,address))
    print(args)                          #args 是一个元组类型  输出为('a', 'b', 'c', 'd')
    print(agrs2)                         #字典数据类型      输出为{'age': 18}
getInfo('刘德华','九龙','a','b','c','d',age = 18)

可变对象与不可变对象的传递

   不可变类型:整数、字符串、元组。如当调用函数fun(a)时,传递的只是a的值,没有影响a对象本身。在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身

  可变类型:列表、字典。如当调用函数fun(la)时,则是将 la 真正的传过去,修改后fun外部的la也会受影响

#不可变对象的传递——值的传递
def fun(args):
    args = 'hello'            #重新赋值
    print(args)               #输出为hello
str1 = 'baby'                 #声明一个字符串的变量   不可变数据类型
fun(str1)                     #将该字符串传递到函数中
print(str1)                   #输出为baby  并没有被改变
#可变对象的传递——引用传递
def fun(args):
    args[0] = 'hello'        #重新赋值
    print(args)              #输出为['hello', 'come on']
list01 = ['baby','come on']  #声明一个列表   可变数据类型
fun(list01)                  #将该字符串传递到函数中
print(list01)                #输出为['hello', 'come on']  传递的是对象本身,函数里面被修改了值,原对象也会跟着修改

函数返回值

  1、return语句

    return语句用于退出函数,选择性的向调用者返回一个表达式。直接return的语句,即不写任何表达式,默认返回None,return后语句不再执行,函数调用过程彻底结束,用一个变量可以接受多个返回值,并会保存在一个元组

def max(x, y):
    if x > y:
        return x                        #结束函数的运行 并且将结果返回给调用的地方
    else:
        return y                        #后面的代码不会执行
        print('我没有被执行')            #没有执行print
num = max(1,2)                          #声明一个变量num 接受调用函数后的返回值
print(max(1,2))                         #输出为2   返回值会返回到调用的地方

def sum(x,y):                           #return返回多个返回值
    return x,y
num = sum(1,2)                          #用一个变量接受多个返回值,会保存在一个元组中
print(num)                              #输出为(1, 2)
num1,num2 = sum(1,2)                    #两个变量分别对应的接受返回值
print(num1)                             #输出为1
print(num2)                             #输出为2

  2、yield语句

    迭代器是一个可以记住遍历的位置的对象, 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束,迭代器只能往前不会后退,迭代器有两个基本的方法:iter() 和 next(),其中字符串,列表或元组,集合对象都可用于创建迭代器

dict={'打野':'Bengi','中单':'Faker'}
list=[1,2,3,4]
it1 = iter(list)                #创建迭代器对象
it2 = iter(dict)
print (next(it1))               #输出为1   迭代器的下一个元素
print (next(it1))               #输出为2
for i in it1:                   #it1已经变为迭代器,所有会接着上边的运行
     print(i)                   #输出为3  4
print (next(it2))               #输出为打野
print (dict[next(it2)])         #输出为Faker

    yield 的作用就是把一个函数变成一个generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个生成器,与return类似,都可以返回值,但不一样的地方,yield可以返回多次值,而return只能返回一次

    在调用生成器运行的过程中,每次遇到 yield 时函数会暂停保存当前所有的运行信息,返回yield的值。并在下一次从当前位置继续运行,可以通过for循环或者手动调用 next() 的方法

def getNum(n):
    i = 0
    while i <= n:
        yield i         #将函数变成一个generator
        i+=1
a = getNum(5)           #把生成器赋值给一个变量a
print(next(a))          #输出为0   使用生成器 通过 next()方法
print(next(a))          #输出为1   输出yield返回的值
for i in a:             #for循环遍历一个生成器   接着上边的运行
    print(i,end=' ')    #输出为2 3 4 5
'''
    使用生成器可以达到延迟操作的效果,所谓延迟操作就是指在需要的时候
    产生结果而不是立即产生就结果,节省资源消耗,和声明一个序列不同的
    是生成器,在不使用的时候几乎是不占内存的
'''
# a = [x for x in range(10000000)]   #这样生成一个很多数据的列表会占用很大的内存
# print(a)
grt = (x for x in range(10000000))  #这是一个生成器 不是元组推导式,就没有元组推导式这一说法
print(grt)                          #输出为<generator object <genexpr> at 0x00000000028231B0>
print(next(grt))                    #输出为0
print(next(grt))                    #输出为1
print(next(grt))                    #输出为2

  3、生成器-send

    a  =  yield  1  ,等号右边是一个yield  1,所以先要执行yield  1,然后才是赋值,yield把1值返回到了调用者那里,因为执行等号右边的yield就是暂停,所以不会对a赋值,换句话说a = yield 1 只执行了一半,那这个表达式的下一步操作:赋值,但这时没有值给a了,而send()里面的值的作用是把值传进当前的yield

'''
    输出为
        0
        None
        1
        我是被传入的值
        2
'''
def gen():
    i = 0
    while i < 5:
        temp = yield i  #不是赋值操作——使用了yield之后是一个生成器
        print(temp)     #因为yield之后返回结果到调用者的地方,暂停运行,赋值操作没有运行
        i+=1
a = gen()
print(next(a))
print(next(a))
print(a.send('我是被传入的值'))  #可以将值发送到 上一次yield的地方

变量的作用域

  1、全局变量

    全局变量是声明在函数外部的变量,定义在函数外的拥有全局作用域

#全局变量
def test1():
    print(a)        #输出为1
    print(id(a))    #输出为8791399764800
def test2():
    print(a)        #输出为1
    print(id(a))    #输出为8791399764800
a = 1
test1()
test2()
print(a)            #输出为1
print(id(a))        #输出为8791399764800——大家使用的是同一个变量,全局变量

  2、局部变量

    局部变量就是在函数内部定义的变量,不同的函数,可以定义相同的名字的局部变量,但是各用各的不会产生影响

#局部变量:声明在函数内部的变量是局部变量
def test1():
    a = 1
    print(a)        #输出为1
    print(id(a))    #输出为8791399764800
def test2():
    a = 2
    print(a)        #输出为2  无法使用test1函数中定义的局部变量
    print(id(a))    #输出为8791399764832
test1()
test2()
#print(a)           #局部变量的作用于只在于函数中,外部无法使用,会报错

  3、可变类型的全局变量

    对于不可变类型的全局变量来说,要在函数中修改需要global声明

    对于可变类型的全局变量来说,要在函数中修改可以不使用global声明

def test1():
    global a        #声明全局变量a
    a = 2           #值以及内存地址都变了
    print(a)        #输出为2
    print(id(a))    #输出为8791399764832
def test2():
    a = 3
    print(a)        #输出为3
    print(id(a))    #输出为8791399764864
a = 1
print(id(a))        #输出为8791399764800
test1()
test2()
print(a)            #输出为2
print(id(a))        #输出为8791399764832

匿名函数

  定义函数的过程中,没有给定名称的函数就叫做匿名函数;Python中使用lambda表达式来创建匿名函数

  lambda匿名函数的表达式规则是:  lambda  参数列表:  表达式

# 没有参数的lambda表达式
s = lambda : '杰大哥牛逼'            #通过lambda声明一个匿名函数,并且赋值给s,冒号后的表达式会返回
print(s())                          #通过s调用匿名函数
# 声明一个参数
s = lambda x: x*2
print(s(3))                         #输出为6
# 声明两个参数
s = lambda x,y: x+y                 #lambda相当于def;x,y相当于形参;x+y是表达式,相当于return后的返回值
print(s(3,4))                       #输出为7
'''
    if  条件:
        代码块哦
    else:
        代码块
    矢量化的三元运算符
    条件成立的内容  if 条件 else 条件不成立的内容
'''
s = lambda x, y: x if x > 2 else y
print(s(1, 4))                      #输出为4

递归函数

  递归就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己

def main(n):
    print('进入第%d层梦境'%n)
    if n == 3:
        print('到达潜意识区,原来我最爱的人是你!开始醒来')
    else:
        main(n+1)
    print('从第%d层梦境醒来'%n)
main(1)                            #回到调用的地方
'''
    第一次调用:进入第1层梦境
        第二次调用:进入第2层梦境
            第三次调用:进入第3层梦境 进入 if 到达潜意识区,原来我最爱的人是你!开始醒来
            从第3层梦境醒来 结束第三次调用
        从第2层梦境醒来 结束第二次调用
    从第1层梦境醒来 结束第一次调用
'''