zoukankan      html  css  js  c++  java
  • 函数基础

    一、函数定义

    1、定义

      函数的定义每个人理解的不一样,最后定义的也是不尽相同,函数可以说它是一个拥有名称、参数以及返回值的代码块。

    2、函数种类

    • 内置函数

      python解释器已经提供的函数,拿来直接使用而无需定义。

    • 自定义函数

      个人根据自己的产品需求,定义好某种函数,以后再进行调用。

    3、定义函数

    #语法格式化
    def 函数名(参数1,参数2,参数3,...):
        '''注释'''
        函数体
        return 返回的值

      从上面定义的语法格式可以看出,定义函数需要使用def语句,接着是函数名,一般需要能反映出其意义,后面是一对圆括号,函数的参数就放在这里,参数之间以“,”分隔,最后以“:”结束;内部是函数的代码块,需要使用缩进进行编写,包含注释,对函数参数等的说明,接着是函数体,也就是实现功能的代码;最后如果有返回值就是用return语句,可以返回多个主,中间使用“,”分隔,如果没有返回值,return语句可以省略。

    def login(username,password):
        """
        :param username: 用户名
        :param password: 密码
        :return: 返回值
        """
        user=models.User.objects.filter(username=username,password=password).first()
        if user:
            return user
    登陆验证函数

      函数在定义阶段只检测语法,不执行代码,也就是说,函数在定义阶段就检查语法是否错误,而逻辑错误只能在执行时抛出。

    4、文档注释

      python语言支持当行或者多行注释,单行使用“#”,多行使用三个单引号或者双引号将注释内容包裹,但其实还有一种注释方法就是:文档注释

    单行和多行注释最后都会被编译器去掉,而文档注释内容却可以获取得到。文档注释需要在函数头(包含def关键字的那一行)的下一行使用单引号或者双引号将注释扩起来即可。然后使用"__doc__"函数属性获取文档注释。

    def add(x,y):
        '计算两个数的和'
        return x+y
    
    print(add.__doc__) #计算两个数的和

    5、无返回值的函数

      如果需要函数无返回值,不使用return即可;或者使用return语句,但return后面什么也不跟,当然这种情况主要用于从函数的的任意深度跳出函数。

      如果return语句后面什么也不跟,打印函数,会输出None

    def bar():
        return
    
    print(bar())#None

    二、函数参数

       def关键字后面圆括号中的参数称为形参,调用函数时指定的参数称为实参。

    1、普通传参

      函数形参的位置很重要,实参的传递都是按照形参的定义进行传递的。

    def bar(name,content):
        return "姓名:{},详情:{}".format(name,content)
    
    print(bar("bright","你好")) #姓名:bright,详情:你好
    • 关键字参数

      但是有时候参数过多,未必记住具体的位置,此时可以进行关键字传参,在混合使用时,注意关键字参数必须放到位置参数后面,否则或抛出异常。

    def bar(name,content,gender):
        return "姓名:{},详情:{},性别:{}".format(name,content,gender)
    
    print(bar("bright","你好",gender="")) #姓名:bright,详情:你好,性别:男
    • 默认值

      有时候在一些情境下,大多数参数需要使用某个固定的值,那么可以为函数的形参指定默认值,如果不指定形参的值,函数就会使用形参的默认值。

    def bar(name,content,gender=""):
        return "姓名:{},详情:{},性别:{}".format(name,content,gender)
    
    print(bar("bright","你好")) #姓名:bright,详情:你好,性别:男

    2、动态传参

    • 可变参数
    def dynamic(*params):
        print(params)
    
    dynamic("helloworld",4,5,6,7,False)#('helloworld', 4, 5, 6, 7, False)

      可以看到params前面加一个*表示该参数是一个可变参数,在调用dynamic函数时可以指定任意的、不同类型的多个参数。从输出结果看到,可变参数在函数内部是以元组的形式体现的。

      使用可变参数需要考虑形参的位置,通常既有普通参数又有可变参数,可变参数如果放到前面或者中间,后面普通参数需要关键字传参。

    def foo(*params,d1,d2):
        print(params)#('helloworld', 1, 2)
    
    foo("helloworld",1,2,d1="gh",d2="mk")

      如果可变参数在中间位置的话,并且也不想关键字传参,那么需要指定默认值。

    def foo(*params,d1="gh",d2="mk"):
        print(params)#('helloworld', 1, 2)
    
    foo("helloworld",1,2)
    • 序列作为函数参数值

      函数的参数值可以是任意的数据类型,包括元组、列表、字典等,那么如何将序列的单个元素传入函数呢?

    def dynamic(p1,p2):
        print(p1,p2)#hello world
    list=['hello','world']
    #将序列中的单个元素作为参数传入dynamic,需要在实参前加*
    dynamic(*list)

      上述并没有使用可变参数传参,如果使用可变参数传参的话也是可以实现的

    def dynamic(*params):
        for i in params:#注意params是以元组的形式存在
            print(i)#hello world
    list=['hello','world']
    dynamic(*list)

      注意:*后加实参,表示传入的值是序列中的单个元素。

      上面说的是列表,如果是字典的话,需要有一些改变,那么如何将字典中的单个元素传入函数呢?

    def DictDynamic(name,age):
        print(name,age)#bright 27
        
    user_info={"name":"bright","age":27}
    #将字典中的单个元素作为参数值,传入实参,前面必须加**
    DictDynamic(**user_info)

      当然也可以通过可变参数:

    def DictDynamic(**params):
        #注意params是一个字典
        print(params)#{'name': 'bright', 'age': 27}
    
    user_info={"name":"bright","age":27}
    #将字典中的单个元素作为参数值,传入实参,前面必须加**
    DictDynamic(**user_info)

      在这里,如果在定义函数时,形参未加**,那么在调用该函数时,也不能加两个**。

    def DictDynamic(params):
        print(params)#{'name': 'bright', 'age': 27}
    
    user_info={"name":"bright","age":27}
    #传入字典
    DictDynamic(user_info)

    三、作用域

      作用域是变量、函数、类等的生效范围,直接在模块中顶层定义的变量、函数都属于全局作用域,而在函数的局部定义的作用域属于函数本身的局部作用域,在局部作用域中定义的变量,上一层作用域是不可见的。

    x=10
    def Foo():
        x=20
    Foo()
    print(x)#10

      在上面的代码中,全局变量x=10,以及局部变量x=20,这是两个不同的变量,在全局作用域中也只能看见x=10,而在函数的局部作用域中只能看见x=20。

      当然局部作用域是可以访问上一层的作用域,除非它本身作用域不存在这个变量。

    y=10 #全局变量
    def Foo():
        print(y)#10
    Foo()

      可以看到上述y=10在全局作用域中,而在函数内部访问这个变量,因为函数本身没有这个变量,所以它会向上一层查找。

    • global

      global是全局变量的关键字,如果在局部作用域中声明一个变量为全局变量可以使用这个关键字

    NAME = "Bright"
    
    def func():
        global NAME #声明NAME时全局变量
        NAME = "tiny" #修改全局变量
        print('hello', NAME)#hello tiny
    func()

      上面的代码通过global实现了局部作用域中修改全局变量的值, 如果函数中有global关键字,变量本质上就是全局的那个变量,可读取可赋值 NAME=“XXX”nonlocal

    • nonlocal

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

    name = "bright"
    def func():
        name = "tiny"
        def bar():
            nonlocal name   # nonlocal,指定上一级变量,如果没有就继续往上直到找到为止
            name = "sandy"
        bar()
        print(name)
    print(name)#bright
    func()#sandy
    • 函数即变量

    先看下面两个实例:

    实例一:

    def func1():
        name="bright"
        print(name)
        func2()
        
    func1()
    
    def func2():
        print("我是func2")

    实例二:

    def func1():
        name="bright"
        print(name)
        func2()
    
    def func2():
        print("我是func2")
    func1()

      上面两个实例你觉得哪一个会出错,没错,就是第一个会出错,为什么呢?

      在实例一中,内存会把代码进行加载,func1作为变量名,函数题作为变量内容加载到内存,当执行func1时,func2还没加载到内存中去,所以毫无疑问:

    NameError: name 'func2' is not defined

      函数即变量意思就是,函数名相当于变量名,函数体相当于变量内容,而把每一个函数体加载到内存,标示就是函数名。

    四、递归

      递归简单的来说就是函数在内部调用自身。因为函数调用是通过栈(stack)这种数据结构实现的,所以,递归调用的次数过多,会导致栈溢出。这也就要求递归必须有一个明确的结束条件。

    • 计算阶乘的递归函数:
    def multiplication(n):
        ##终止条件
        if n==0 or n==1:
            return 1
        ##递归调用
        return n*multiplication(n-1)
    
    res=multiplication(10)
    print(res)
    •  斐波拉契数列的递归函数

      斐波拉契数列指的是这样的一列数字:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,...

      计算第n个值是什么? 

    def fibonacci(n):
    
        if n==1:
            return 0
        elif n==2:
            return 1
        else:
            return fibonacci(n-1)+fibonacci(n-2)
    
    print(fibonacci(5))
  • 相关阅读:
    Springmvc构造RESTful详细讲解
    Http和Socket连接区别
    整合struts2+hibernate详细配置步骤及注意事项
    spring,hibernate,struts的面试笔试题
    泛型中? super T和? extends T的区别
    Java中有关Null的9件事
    Eclipse中的快捷键总结
    Hibernate之Query接口的uniqueResult()方法
    Hibernate插入、查询、删除操作 HQL
    JQuery中$.ajax()方法参数详解 转载
  • 原文地址:https://www.cnblogs.com/shenjianping/p/11008936.html
Copyright © 2011-2022 走看看