Python学习之函数篇

Posted layblogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习之函数篇相关的知识,希望对你有一定的参考价值。

函数基础

  • 定义函数
#语法
def 函数名(参数1,参数2,参数3,...):
    ‘‘‘注释‘‘‘
    函数体
    return 返回的值

#函数名要能反映其意义
#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
#3、空函数:设计代码结构
技术图片
#定义阶段
def tell_tag(tag,n): #有参数
    print(tag*n)

def tell_msg(): #无参数
    print(hello world)

#调用阶段
tell_tag(*,12)
tell_msg()
tell_tag(*,12)

‘‘‘
************
hello world
************
‘‘‘

#结论:
#1、定义时无参,意味着调用时也无需传入参数
#2、定义时有参,意味着调用时则必须传入参数
有参、无参
技术图片
def auth(user,password):                             
    ‘‘‘                                                           
    auth function                                                 
    :param user: 用户名                                              
    :param password: 密码                                           
    :return: 认证结果                                                 
    ‘‘‘                                                           
    pass                                                          
                                                                  
def get(filename):                                                
    ‘‘‘                                                           
    :param filename:                                              
    :return:                                                      
    ‘‘‘                                                           
    pass                                                          
                                                                  
def put(filename):                                                
    ‘‘‘                                                           
    :param filename:                                              
    :return:                                                      
    ‘‘‘
    pass       
def ls(dirname):                                                  
    ‘‘‘                                                           
    :param dirname:                                               
    :return:                                                      
    ‘‘‘                                                           
    pass
#程序的体系结构立见 
空函数
  • 调用函数
#函数的调用:函数名加括号
#1 先找到名字
#2 根据名字调用代码
#
函数返回值
#无return->None
#return 1个值->返回1个值
#return 逗号分隔多个值->元组


#调用函数的三种形式
#1 语句形式:foo()
#2 表达式形式:3*len(‘hello‘)
#3 当中另外一个函数的参数:range(len(‘hello‘))
  • 函数参数
技术图片
1、位置参数:按照从左到右的顺序定义的参数
        位置形参:必选参数
        位置实参:按照位置给形参传值

#2、关键字参数:按照key=value的形式定义的实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右面
                2. 对同一个形参不能重复传值

#3、默认参数:形参在定义时就已经为其赋值
        可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
        注意的问题:
                1. 只在定义时赋值一次
                2. 默认参数的定义应该在位置形参右面
                3. 默认参数通常应该定义成不可变类型


#4、可变长参数:
        可变长指的是实参值的个数不固定
        而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs

        ===========*args===========
        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,3,4,5)

        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,*[3,4,5])


        def foo(x,y,z):
            print(x,y,z)
        foo(*[1,2,3])

        ===========**kwargs===========
        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,a=1,b=2,c=3)

        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,**a:1,b:2,c:3)


        def foo(x,y,z):
            print(x,y,z)
        foo(**z:1,x:2,y:3)

        ===========*args+**kwargs===========

        def foo(x,y):
            print(x,y)

        def wrapper(*args,**kwargs):
            print(====>)
            foo(*args,**kwargs)

#5、命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
可以保证,传入的参数中一定包含某些关键字
        def foo(x,y,*args,a=1,b,**kwargs):
            print(x,y)
            print(args)
            print(a)
            print(b)
            print(kwargs)

        foo(1,2,3,4,5,b=3,c=4,d=5)
        结果:
            1
            2
            (3, 4, 5)
            1
            3
            c: 4, d: 5
重点!
  • 作用域
#1、作用域即范围
        - 全局范围(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
      - 局部范围(局部名称空间属于该范围):临时存活,局部有效
#2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,如下
x=1
def f1():
    def f2():
        print(x)
    return f2
x=100
def f3(func):
    x=2
    func()
x=10000
f3(f1())

#3、查看作用域:globals(),locals()


LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
  • 函数嵌套
def f1():
    def f2():
        def f3():
            print(from f3)
        f3()
    f2()

f1()

闭包函数

  • 什么是闭包
#内部函数包含对外部作用域而非全局作用域的引用


        def counter():
            n=0
            def incr():
                nonlocal n
                x=n
                n+=1
                return x
            return incr

        c=counter()
        print(c())
        print(c())
        print(c())
        print(c.__closure__[0].cell_contents) #查看闭包的元素
  • 闭包的意义和作用
#闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
#应用领域:延迟计算(原来我们是传参,现在我们是包起来)
    from urllib.request import urlopen

    def index(url):
        def get():
            return urlopen(url).read()
        return get

    baidu=index(http://www.baidu.com)
    print(baidu().decode(utf-8))

装饰器

  • 什么是装饰器
#装饰器他人的器具,本身可以是任意可调用对象,被装饰者也可以是任意可调用对象。
#强调装饰器的原则:1 不修改被装饰对象的源代码 2 不修改被装饰对象的调用方式
#装饰器的目标:在遵循1和2的前提下,为被装饰对象添加上新功能
技术图片
被装饰函数的正上方,单独一行
        @deco1
        @deco2
        @deco3
        def foo():
            pass

        foo=deco1(deco2(deco3(foo)))
装饰器语法
  • 装饰器的使用
技术图片
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(run time is %s %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print(from foo)
foo()
无参装饰器
技术图片
def auth(driver=file):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == file:
                if name == egon and pwd == 123:
                    print(login successful)
                    res=func(*args,**kwargs)
                    return res
            elif driver == ldap:
                print(ldap)
        return wrapper
    return auth2

@auth(driver=file)
def foo(name):
    print(name)

foo(egon)
有参装饰器

迭代器

#迭代是Python最强大的功能之一,是访问集合元素的一种方式。
#迭代器是一个可以记住遍历的位置的对象。
#迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
#迭代器有两个基本的方法:iter() 和 next()。
#字符串,列表或元组对象都可用于创建迭代器
技术图片
#!/usr/bin/python3
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")
示例
技术图片
#基于for循环,我们可以完全不再依赖索引去取值了
dic=a:1,b:2,c:3
for k in dic:
    print(dic[k])

#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环
for循环工作原理
技术图片
#优点:
  - 提供一种统一的、不依赖于索引的迭代方式
  - 惰性计算,节省内存
#缺点:
  - 无法获取长度(只有在next完毕才知道到底有几个值)
  - 一次性的,只能往后走,不能往前退
迭代器的优缺点

生成器

#在 Python 中,使用了 yield 的函数被称为生成器(generator)。
#跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
#在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
#调用一个生成器函数,返回的是一个迭代器对象。
技术图片
#!/usr/bin/python3
 
import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()
示例

表达式

技术图片
name=input(姓名>>: )
res=SB if name == alex else NB
print(res)
三元表达式
技术图片
#1、示例
egg_list=[]
for i in range(10):
    egg_list.append(鸡蛋%s %i)

egg_list=[鸡蛋%s %i for i in range(10)]

#2、语法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
类似于
res=[]
for item1 in iterable1:
    if condition1:
        for item2 in iterable2:
            if condition2
                ...
                for itemN in iterableN:
                    if conditionN:
                        res.append(expression)

#3、优点:方便,改变了编程习惯,可称之为声明式编程
列表推导式
技术图片
#1、把列表推导式的[]换成()就是生成器表达式

#2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
>>> chicken=(鸡蛋%s %i for i in range(5))
>>> chicken
<generator object <genexpr> at 0x10143f200>
>>> next(chicken)
鸡蛋0
>>> list(chicken) #因chicken可迭代,因而可以转成列表
[鸡蛋1, 鸡蛋2, 鸡蛋3, 鸡蛋4,]

#3、优点:省内存,一次只产生一个值在内存中
生成器表达式

递归

#递归调用是函数嵌套调用的一种特殊形式,函数在调用时,直接或间接调用了自身,就是递归调用
技术图片
#直接调用本身
def f1():
    print(from f1)
    f1()
f1()

#间接调用本身
def f1():
    print(from f1)
    f2()

def f2():
    print(from f2)
    f1()
f1()

# 调用函数会产生局部的名称空间,占用内存,因为上述这种调用会无需调用本身,python解释器的内存管理机制为了防止其无限制占用内存,对函数的递归调用做了最大的层级限制
四 可以修改递归最大深度

import sys
sys.getrecursionlimit()
sys.setrecursionlimit(2000)

def f1(n):
    print(from f1,n)
    f1(n+1)
f1(1)

虽然可以设置,但是因为不是尾递归,仍然要保存栈,内存大小一定,不可能无限递归,而且无限制地递归调用本身是毫无意义的,递归应该分为两个明确的阶段,回溯与递推
示例

匿名函数

匿名就是没有名字
def func(x,y,z=1):
    return x+y+z

匿名
lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,除非让其有名字
func=lambda x,y,z=1:x+y+z 
func(1,2,3)
#让其有名字就没有意义

内置函数

技术图片

 

以上是关于Python学习之函数篇的主要内容,如果未能解决你的问题,请参考以下文章

Python学习之函数篇

python入门学习之变量篇

python学习之函数

Python学习之函数进阶

python入门学习之变量注释篇

python学习之函数