Python程序设计案例课堂
上QQ阅读APP看书,第一时间看更新

5.6 用户自定义函数

函数是组织好的、可重复使用的、用来实现单一或相关联功能的代码段。根据实际工作的需求,用户可以自己创建函数,即用户自定义函数。

5.6.1 定义函数

Python的函数定义方法是使用def关键字,语法格式如下:

        def函数名称(参数1,参数2, ...):
          "文件字符串"
          <语句>

“文件字符串”是可省略的,用来作为描述此函数的字符串。如果“文件字符串”存在,它必须是函数的第1个语句。

定义一个函数的规则如下。

(1)函数代码块以def关键字开头,后接函数名称和圆括号()。

(2)任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

(3)函数的第1行语句可以选择性地使用文件字符串——用于存放函数说明。

(4)函数内容以冒号起始,并且缩进。

(5)return [表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。

下列是一个简单的函数定义:

        >>>def addnumbers(x, y):
            "x + y"
            return x + y

        >>> addnumbers(5,4)
        9

可见,定义一个函数,主要是指定函数里包含的参数和代码块。这个函数的基本结构完成以后,用户可以通过另一个函数调用执行,也可以直接从Python命令提示符窗口执行。

如果用户调用的函数没有参数,就必须在函数名称后加上小括号()。举例如下:

        >>> def getmyname():
            "my name is John"
            return "John"

        >>> myname = getmyname()
        >>> print (myname)
        John

用户可以将函数名称设置为变量,然后使用该变量来运行函数的功能。例如:

        >>>x = abs
        >>>print (x(-3))
        3

其中abs()函数是Python的内置函数。

如果用户的函数只有一个表达式,就可以使用lambda运算符来定义这个函数。例如:

        >>>f = lambda x, y: x + y
        >>>f(10,5)
        15

这里Python使用lambda创建一个匿名函数。所谓匿名,即不再使用def语句这样标准的形式定义一个函数。这个函数可以使用def关键字来做,语句如下:

        >>> def f(x, y):
            return x + y

        >>> f(10,5)
        15

5.6.2 函数的参数传递

Python函数的参数传递都是使用传址调用的方式。所谓传址调用,就是将该参数的内存地址传过去,如果参数在函数内被更改,则会影响到原有的参数。参数的数据类型可以是模块、类、实例(instance),或是其他的函数,用户不必在参数内设置参数的数据类型。

调用函数时,可使用的参数类型包括必需参数、关键字参数、默认参数和不定长参数。下面分别介绍它们的使用方法和技巧。

1.必需参数

必需参数要求用户必须以正确的顺序传入函数。调用时的数量必须和声明时的数量相同,设置函数的参数时须依照它们的位置排列顺序。例如:

        >>> def addnumbers(x, y):
            return x + y

        >>> addnumbers(2, 5)
        7

在上述例子中,调用addnumbers(2, 5)时,x参数等于2, y参数等于5,因为Python会根据参数排列的顺序来取值。

如果调用addnumbers()函数时,没有传入参数或者传入参数和声明不同,则会出现语法错误。例如:

        >>> addnumbers()
        Traceback (most recent call last):
          File "<pyshell#88>", line 1, in <module>
            addnumbers()
        TypeError: addnumbers() missing 2 required positional arguments: 'x' and
        'y'

2.关键字参数

用户可以直接设置参数的名称与其默认值,这种类型的参数属于关键字参数。设置函数的参数时可以不依照它们的位置排列顺序,因为Python解释器能够用参数名匹配参数值。

例如:

        >>> def addnumbers(x, y):
            return x + y

        >>> addnumbers(y = 5, x = 20)
        25

用户可以将必需参数与关键字参数混合使用,但是必需参数必须放在关键字参数之前。

例如:

        >>> def addnumbers(x, y):
            return x + y

        >>> addnumbers(2, y = 4)
        6

3.默认参数

调用函数时,如果没有传递参数,则会使用默认参数值。例如:

        >>>def printinfo( name, price=65 ):
          "输出商品报价信息"
          print ("名称: ", name)
          print ("价格: ", price)
          return

        >>>printinfo( price=80, name="耳机" )
        名称:  耳机
        价格:  80
        >>>printinfo( name="键盘" )
        名称:  键盘
        价格:  65

在本案例中,首先定义一个函数printinfo(name, price=65),这里变量price的默认值为65。当第1次调用该函数时,指定了变量price的值为80,所以输出值也为80;第2次调用该函数时,没有指定变量price的值,结果将会输出变量price的默认值,结果为65。

当使用默认参数时,参数的位置排列顺序可以任意改变。如果每个参数值都定义了默认参数,则调用函数时可以不设置参数,直接使用函数定义时的参数默认值。例如:

        >>> def addnumbers(x=10, y=15 ):
            return x + y

        >>> addnumbers()
        25

4.不定长参数

如果用户在声明参数时不能确定需要使用多少个参数,可以使用不定长参数。不定长参数不用命名。基本语法如下:

        def functionname([formal_args, ] *var_args_tuple ):
          "函数_文档字符串"
          function_suite
          return [expression]

加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。用户也可以不向函数传递未命名的变量。例如:

        >>> def addnumbers(*args):
            sum = 0
            for arg in args:
                sum += arg
            return sum

        >>> addnumbers(1,2,3,4)
        10
        >>> addnumbers(1,2,3,4,5,6,7,8)
        36

当用户无法预计参数的数目时,可以使用*args类型的参数,*args代表一个元组对象。或是使用**args类型的参数,**args代表一个字典对象。

下列案例显示**args类型的参数应用:

        >>> def spam(**args):
            print ("Keys = "),
            for k in args.keys():
                print (k),
            print ("Values = "),
            for v in args.values():
                print (v),

        >>> spam(x = 10, y = "python", z = (1,2,3))
        Keys =
        x
        y
        z
        Values =
        10
        python
        (1, 2, 3)

5.6.3 return语句

return语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。下面通过一个案例来学习return语句返回数值的方法:

        >>>def sum(count, price ):
          "输出商品总价格"
          total = count * price
          print ("商品总价格: ", total)
          return total

        >>>sum( 100, 28 )
        商品总价格:  2800
        2800

函数的返回值可以是一个表达式。例如:

        >>> def addnumbers(x, y):
            return x * 10 + y * 20

        >>> addnumbers(1, 2)
        50

函数的返回值可以是多个,此时返回值以元组对象的类型返回。例如:

        >>> def returnxy(x, y):
            return x, y

        >>> a, b = returnxy(10, 20)
        >>> print (a, b)
        10 20

如果函数没有返回值,则返回None。例如:

        >>> def myfunction():
            return

        >>> ret = myfunction()
        >>> print (ret)
        None

5.6.4 变量作用域

在Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。变量的作用域决定了程序在哪一部分可以访问哪个特定的变量名称。

最基本的变量包括全局变量和局部变量。其中,定义在函数内部的局部变量拥有一个局部作用域,定义在函数外的全局变量拥有全局作用域。

在函数之外定义的变量属于全局变量,用户可以在函数内使用全局变量。例如:

        >>> x = 10
        >>> def get(y = x):
            return y

        >>> get()
        10

在本案例中,x就是一个全局变量。在函数get(y = x)中将变量x的值赋给变量y。

当用户在函数内定义的变量名称与全局变量名称相同时,函数内定义的变量不会改变全局变量的值。因为函数内定义的变量属于局部命名空间,而全局变量则属于全局命名空间。

例如:

        >>> x = 10
        >>> def changex():
            x = 20
            return x

        >>> x
        10
        >>> changex()
        20

如果要在函数内改变全局变量的值,就必须使用关键字global。例如:

        >>> x = 10
        >>> def changex():
            global x
            x = 20
            return x

        >>> changex()
        20
        >>> x
        20

在本案例中,首先定义一个全局变量x,然后定义函数changex(),该函数通过使用关键字global,将x的值修改为20。

5.6.5 函数的内置属性和命名空间

函数有许多的内置属性,用户可以在Python解释器内输入“dir(函数名称)”命令,即可以显示这些内置属性。代码如下:

        >>> def myfunction():
            return

        >>> dir(myfunction)
        ['__annotations__', '__call__', '__class__', '__closure__', '__code__',
        '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
        '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__',
        '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__',
        '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__',
        '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

下面挑选一些常见的内置属性进行讲解。

(1)__dict__:该属性包含该函数的命名空间。

(2)__doc__:该属性显示该函数的文件字符串。例如:

        >>> def returnxy(x, y):
            "return x + y"
            return x + y

        >>> returnxy.__doc__
        'return x + y'

(3)__name__:该属性显示该函数的名称。例如:

        >>> def returnxy(x, y):
            "return x + y"
            return x + y

        >>> returnxy.__name__
        'returnxy'

Python使用动态命名空间,在创建每一个函数、模块与类时,都会定义它自己的命名空间。当用户在Python解释器内输入一个指令或语句时,Python会先搜索局部命名空间,然后搜索全局命名空间。

Python包含的命名空间如下。

●内置命名空间(built-in namespace):int、string、def、print等。

●全局命名空间(global namespace):位于模块的最上层。

●局部命名空间(local namespace):位于函数内。

Python解释器在搜索名称或变量时,首先会在局部命名空间中搜索;如果找不到,再到全局命名空间中搜索,如果还是找不到,则会到内置命名空间中搜索;最后如果还是找不到,Python会输出一个NameError异常。