1、如何自定义一个函数

  前面我们已经使用过像print()len()这些函数,那么如何自己定义一个函数呢,函数的格式如下:

def function_name(参数、参数):

   做一些事情

   return value

   函数的定义都是以def开头的,然后是函数的名字,以一个冒号结束,冒号后会新起一行,从这一行开始你可以写任何的python语句来实现一些函数功能,当然函数结束后,还可以返回一个值给调用者,value就是返回给调用者的值。

例如,定义一个叫greeting的函数,如下:

def greeting(username):

   print(“hello “ + username)

   print(“hello “ + username)

   print(“end...”)

   return len(username)


length = greeting(“xiaoming”)

print(length)

   上面定义了一个叫greeting的函数,他带一个叫做username的参数,在函数体中输出了两行hello,username,最后还返回给调用者username的长度。greeting(xiaoming)就是在调用这个函数,只有实际调用函数时才会执行函数体中的语句,xiaoming这个字符串会赋值给username,那么在greeting这个函数体中的username这个变量的值就是xiaoming了,这个函数会在屏幕上打印两行hello xiaoming,然后使用len(username)计算xiaoming这个字符串的长度,并把这个长度返回给调用者,这里是变量length,最后用print函数输出了xiaoming这个字符串的长度。

   注意:username仅在greeting这个函数中有效,出了这个函数就被销毁了,如果在print(length)后面加一条print(username)的语句会报错。

 

2、None

  像上面的自定义函数有一个return返回值,但并不是每个函数都需要返回值此,像print()函数,这种不需要返回值的函数可以不写return这条语句,python会默认在最后加上return None,None表示什么都没有的意思,NoneNoneType数据类型的值,NoneType和其他数据类型一样,不过仅有一个None值而已。

  

  在交互式shell中输入以上语句,可以证明print()确实返回了None

 

3、关键字参数

   前面定义的函数,当去调用他时,参数和变量是用位置来对应的,例如greeting(xiaoming),xiaoming对应username,也就是第一个参数对应第一个变量。如果greeting还有 一个参数,像这样greeting(username,password),那么调用时为greeting(xiaoming,1234),xiaoming对应username,1234对应password,也就是说第一个参数xiaoming对应第一个变量username,第二个参数1234对应变量password

   除了位置对应外,还有一种使用关键字的对应方法,说的直白点,就是在调用时,可以用凑字字指定把这个参数传递给以关键字命名的这个变量,在交互式shell中实践一下print()函数(print中的关键字参数end指定在输出字符串后,需要在此行末尾加的字符,默认是加换行符):

  

4、变量的作用域

  变量的作用域是指变量在其规定的范围内有效,超过这个范围后,则变量失效(不存在)。目前有两种变量作用域:

  • 全局作用域:没有在任何函数内创建的变量
  • 局部作用域: 在函数内创建的变量,包括函数的参数

  一个程序内可以有多个函数,每个函数都是一个局部作用域,所以一个程序会存在多个局部作用域,但只有一个全局作用域。

  例如下面的代码:

 

  作用域有4条规则

  • 局部作用内的变量不能在全局作用里使用

  

  • 在一个局部任务域内,不能使用另一个域名作用内的变量
def spam():

    eggs = 99

    bacon()

    print(eggs)


def bacon():

    ham = 101

    eggs = 0


spam()

 

   结果是99,说明在bacon函数内的变量eggs并没有对spam函数内的变量eggs造成任何影响,这是因为每个函数都有一个独立的局部作用域,在这个独立的作用域内创建的变量只在这个作用域内有效,而且与其他局部作用域没有任何关系,所以在bacon函数内会新创建eggs变量,bacon函数被调用完成后,这个eggs变量会被丢弃,然后又回到spam的作用域内,因为print(eggs)是在spam的作用域内,所以会使用spam作用域内的eggs变量。

 

  • 局部作用域可以使用全局作用里的变量
def spam():

    print(eggs)

eggs = 42

spam()

print(eggs)

  在spam函数内并没有变量eggs,但可以正确的输出结果,因为在全局作用域内有一个叫eggs的变量。

 

  • 局部变量可以和全局变量同名,此时在函数内局部变量会屏蔽全局变量

 

def spam():

    eggs = 'spam local'

    print(eggs) #  使用spam内的eggs变量



def bacon():

    eggs = 'bacon local'

    print(eggs) # 使用bacon内的eggs变量

    spam()

    print(eggs)# 还是使用bacon内的eggs变量



eggs = 'global'

bacon()

print(eggs) # 这是在全局作用域内,所以所有的局部作用里的变量都不存在了,所以会使用全局变量eggs

 

 

 

  尽管在全局作用域、spam作用域、bacon作用域内都有同名的变量eggs,但一旦程序运行到相应的函数作用域内,其他所有作用域的同名变量就失效了,所以会使用当前函数内的变量。

  那如果我不想在spam函数内新创建一个叫eggs的变量呢,我只想在这个函数内使用全局变量eggs呢,好办,使用global关键字,如下:

def spam():

    global eggs

    eggs = 'spam'



eggs = 'global'

spam()

print(eggs)

 

  此时,在spam函数内,并没有新创建一个变量,而是使用global关键字表示使用在全局作用域定义的变量eggs,所以对eggs变量重新赋值会更改 全局变量eggs的值,所以最后输出了更改后的值spam

 

5、异常处理

  现在我们的程序只要有错误或者异常,就会直接退出,这也太不健壮了,在真实环境中,我们希望我们的程序能够在 发生错误的场景下能自动处理错误,并能继续往下执行,在python中,可以把可能发生 错误的代码放在tryexcept之间,如果发行错误,程序会跳到except后的语句继续执行,except后语句叫做异常捕获。

def spam(divideBy):

    try:

        return 42 / divideBy

    except ZeroDivisionError:

        print('Error: Invalid argument.')

print(spam(2))

print(spam(12))

print(spam(0))

print(spam(1))

 

  当程序执行到print(spam(0))时,spam实际执行的语句是42/0,学过小学数学的都知道,不能被0整除,这会发生错误,引发异常,所以会被异常捕获语句except ZeroDivisionError捕获,所以会执行except ZeroDivisionError下的print语句,其中ZeroDivisionError叫做异常类型,只有发生错误的类型和except后在类型匹配时会被捕获,可以有多条except语句。

 

6、综合实例

import time, sys

indent = 0 # 在一行开始前会有多少个空格

indentIncreasing = True # 当前缩进是否增加还是减少



try:

    while True: # 无限循环

        print(' ' * indent, end='') # ' ' * indent是空格与缩进数目的乘积,end=''表示不使用默认的换行符

        print('********')

        time.sleep(0.1) # 程序暂停0.1秒


        if indentIncreasing: # 如果缩进是增加的,则下面的每一行都会比前一行多一个空格

            indent = indent + 1 # 增加一个空格缩进

            if indent == 20: # 最多20个空格缩进

                indentIncreasing = False # False表示缩进的空格数开始减少

        else:

            indent = indent - 1 # 减少一个空格缩进

            if indent == 0: # 缩进最少是0,不可能有负缩进数

                indentIncreasing = True # True表示增加缩进空格数

except KeyboardInterrupt: # 当用户按下Ctrl + C时,程序会引发KeyboardInterrupt异常,昆except会匹配这个异常,并捕获

    sys.exit() # 捕获异常后,我们自己使用sys.exit()退出程序,如果不捕获异常会打印出一串错误消息,不美观

 

原创文章,转载请注明出处:http://b.nwumba.cn/article/10/