python07_函数

函数

  1. 为什么要用函数?

  2. 定义一个函数

    你可以定义一个由自己想要功能的函数,以下是简单的规则:

    • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
    • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
    • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
    • 函数内容以冒号起始,并且缩进。
    • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
  3. 可更改(mutable)与不可更改(immutable)对象

    在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

    1. 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
    2. 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

    python 函数的参数传递:

    1. 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的地址,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
    2. 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

    python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

  1. 参数

    以下是调用函数时可使用的正式参数类型:

    • 必备参数

    • 默认参数

    • 不定长参数

    • 关键字参数

    • 命名关键字参数

        # role
        
            role={
                “type:”:0,"info":"管理员",
                “type:”:1,"info":"普通用户",
                ”type“ :8,"info":"最高指挥官"
            }
        #type:0 管理员 1:普通用户
        def login(id,pwd,type=0):
            pass
        
        def show(name,age=12):
        print('name is:',name,'and age is',age)
        return
       
        # show()   #error
        
        show('tom',22)
        
        show(name='jack',age=32)
        show(name='rose')
        show(age=32,name='nick')
      

    python的默认值参数只会在函数定义处被解析一次,此后每次调用函数的时候,默认值参数都会是这个值了。碰到一些不可变的数据类型比如:整型,字符串,元祖之类的还好,但如果碰到可变类型的数据比如数组的话,就会有发生一些意想不到的事情。

     def add_to(num, target=[]):
         target.append(num)
         print id(target), target
    
    
     改进:
     
     def add_to(num, target=None):
         if target is None:
             target = []
             ...
    

    可变的数据类型,函数局部作用域里面的任何改变会保留在数据上;不可变的数据类型,发生的任何改变都只会体现在新生成的局部变量上

    不定长参数

    def printinfo( arg1, *vartuple ):
        #"打印任何传入的参数"
       print "输出: "
       print arg1
       for var in vartuple:
          print var
       return;
    
    # 调用printinfo 函数
    printinfo( 10 );
    printinfo( 70, 60, 50 );
    

**关键字参数**

    
        def person(name, age,*args, **kw):
            print('name:', name, 'age:', age,'args',args, 'other:', kw)
            person('Bob', 35,'苏州', city='Beijing')


​ person('Adam', 45, gender='M', job='Engineer')

            #也可以这么些
            extra = {'city': 'Beijing', 'job': 'Engineer'}
            person('Adam', 45, **extra)

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:

    def person(name, age, *, city, job):
        print(name, age, city, job)

和关键字参数kw不同,命名关键字参数需要一个特殊分隔符后面的参数被视为命名关键字参数。

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符了:*

    def person(name, age, *args, city, job):
        print(name, age, args, city, job)

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:
命名关键字参数可以有缺省值,从而简化调用:

    def person(name, age, *, city='Beijing', job,**kargs):
        print(name, age, city, job)

由于命名关键字参数city具有默认值,调用时,可不传入city参数:

总结:

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

  1. 函数返回值
    def show(a,b):
        return a+b,a-b
    res=show(10,20)
    print(res) #(30,-10)

>实际是利用的元组的特性
  1. 匿名函数-lambda
python 使用 lambda 来创建匿名函数。

lambda只是一个表达式,函数体比def简单很多。

lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。



    nation='china'
    show=lambda name,age=12: print('name is:',name,'and age is',age,nation)





    arr=[1,2,3,4,5,6]

    lam=lambda array:[i for i in array if i%2==0]
    
    arr2=lam(arr)
    
    print(arr2)


字典排序

    infors = [{"name":"wang","age":10},{"name":"xiaoming","age":20},{"name":"banzhang","age":10}]

    infors.sort(key=lambda x:x['age']) #根据age对字典排序

函数嵌套


    def func():
        x=4
        action = (lambda n: x**n)      # Pass x in lIlanllally return action
        return action
    
    
    def makeAction():
        acts=[]
        for i in range(5):
            acts.append((lambda x:i**x))
        return acts
    
    atcs=makeAction()
    
    print(atcs[1](3))
    print(atcs[3](3))
    
    
    def makeActionB():
        acts=[]
        for i in range(5):
            acts.append((lambda x,i=i:i**x))  # i=i
        return acts
    
    atcsb=makeActionB()
    
    print(atcsb[1](3))
    print(atcsb[3](3))



匿名函数优点

* 使用Python写一些脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。
* 对于一些抽象的,不会被别的地方再重复使用的函数,有时候函数起个名字也是个难题,使用lambda不需要考虑命名的问题
* 使用lambda在某些时候然后代码更容易理解
  1. 变量作用域
    一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。

    变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。两种最基本的变量作用域如下:

    1. 全局变量
    2. 局部变量
      全局变量和局部变量
      定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

    局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

    小结:

    • 在函数外边定义的变量叫做全局变量
    • 全局变量能够在所有的函数中进行访问
    • 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错
    • 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的,"强龙不压地头蛇"
  2. 全局变量想作用于函数内,需加 global

    nation='china'
    def show(name,age=12):
    
        #nation='hello'+nation #error
        global nation
        nation='usa'
        print('name is:',name,'and age is',age,'and nation is',nation)
        return
    
    # show()
    
    show('tom',22)
    
    
    print(nation)



    def add_b():
        global  b
        b = 42
        def do_global():
            global  b
            b = b + 10
            print(b)
        do_global()
        print(b)
    add_b()
    print(b)



    def add_b():
        #global  b
        b = 42
        def do_global():
            global  b
            b =  10
            print(b)
        do_global()
        print(b)
    add_b()
    print(" b = %s " % b)
    

* 在函数中不使用global声明全局变量时不能修改全局变量的本质是不能修改全局变量的指向,即不能将全局变量指向新的数据。
* 对于不可变类型的全局变量来说,因其指向的数据不能修改,所以不使用global时无法修改全局变量。
* 对于可变类型的全局变量来说,因其指向的数据可以修改,所以不使用global时也可修改全局变量。
* global 要先声明后定义,下面会出错

        def add():
            a=3
            global a
            print(a)
  1. nonlocal

    nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。

    def outer():
        x=100
        def inner():
            nonlocal x
            x=x+1000
            print(x)
    
        return inner
    
    inner=outer()
    
    inner()
  1. 内置函数补充

    1. sum() 方法对系列进行求和计算。

       sum([0,1,2])  
       sum((2, 3, 4), 1)    #元组计算总和后再加 1
       sum([0,1,2,3,4], 2)
      
  2. map()

      把所有列表元素字符串化
    
      list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
    
  3. reduce

    reduce把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
    在Python 3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里

    用的话要 先引入from functools import reduce

      from functools import reduce
      arr=[2,3,4]
      
      def total(x,y):
          return x*2+y*2
      print(reduce(total,arr))
    

    案例:实现字符串反转

      result = reduce(lambda x,y:y+x,s)
    
  4. filter

      arr=[2,3,4]
    
      res=filter(lambda x:x%2==0,arr)
      
      print(list(res))
      
      ??arr=['张晓明','张三丰','王重阳']
      #找出姓张而且单名的人
    
  5. sorted

          sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
      ​   
          users=[
              {'id':'008','user_name':'admin','user_password':'888','type':0},
              {'id':'002','user_name':'joke','user_password':'777','type':1},
              {'id':'001','user_name':'nose','user_password':'777','type':1}
          ]
          
          res=sorted(users,key=lambda u:u['id'])
          
          res=sorted(users,key=lambda user:user['id'],reverse=True)
    
  6. zip()

    zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

    如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

      a = [1,2,3]
      b = [4,5,6]
      c = [4,5,6,7,8]
      zipped = zip(a,b)     # 打包为元组的列表
          #[(1, 4), (2, 5), (3, 6)]
      zip(a,c)              # 元素个数与最短的列表一致
          #[(1, 4), (2, 5), (3, 6)]
      zip(*zipped)          # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
          #[(1, 2, 3), (4, 5, 6)]
    
  7. enumerate()

    函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

     seasons = ['Spring', 'Summer', 'Fall', 'Winter']
     list(enumerate(seasons))
         #[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
     list(enumerate(seasons, start=1))       # 小标从 1 开始
         #[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
    
     
     seq = ['one', 'two', 'three']
     for i, element in enumerate(seq):
         print(i, seq[i])
    
  8. vars() 函数返回对象object的属性和属性值的字典对象。

  9. reversed 函数返回一个反转的迭代器。

  10. 查看系统内置函数

print(dir(_builtins_))

  1. Python 中 LEGB

    LEGB 指的是 Python 中的变量作用域问题,其中

    L:local 局部变量,仅存在函数内部,其存储位置位于栈中,其生命周期在函数结束时就会被释放。

    E:enclosing 外部作用域变量,常见于闭包函数,也就是嵌套函数中的上一层函数变量。其生命周期在整个闭包函数结束时会被释放。

    G:global 全局变量,作用于整个程序,其存储位置位于全局数据区中,其生命周期在程序销毁时就被释放。

    B:builtins 内建模块变量,其存储于内置变量命名空间。

  2. 递归函数

    100 之和

    def func(n):
        if n<=1:
            return 1
        return n+func(n-1)
    
    
    print(func(100))
    

    斐波那契数列

    def fibonacci(n):
        if n <= 2:
            return 1
        else:
            return fibonacci(n - 2) + fibonacci(n - 1)
    
    
    for i in range(1,10):
        print(fibonacci(i))
    
  3. 快速排序

    def quicksort(arr):    
        if len(arr) <= 1:        
            return arr    
        pivot = arr[len(arr) // 2]    
        left = [x for x in arr if x < pivot]    
        middle = [x for x in arr if x == pivot]    
        right = [x for x in arr if x > pivot]    
        return quicksort(left) + middle + quicksort(right)
    print(quicksort([3, 6, 8, 19, 1, 5]))  # [1,3, 5, 6, 8, 19]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容