第三章 函数

def hello():          #1
       print('Howdy!')
       print('Howdy!!!')
       print('hello there!')

hello()           #3
hello()
hello()
#def语句定义了一个名为hello()函数。def语句之后的代码块是函数体,这段代码在函数调用时执行,3处的是函数的调用。

 

返回值和return语句

一般来说,函数调用求值得结果,称为函数的“返回值”。用def语句创建函数时,可以使用return语句指定应该返回什么值。

 

return语句组成

  • return关键字
  • 函数应该返回的值或表达式

 

如果在return语句中使用了表达式,返回值就是该表达式求值得结果.

 

None

在Python中有一个值称为None,他表示没有值。None是NoneType数据类型的唯一值。N必须大写

 

print()函数在屏幕上显示文本,但它不需要返回任何值,返回值为None,这和len()或input()不同。

 

在幕后,对于所有没有return语句的函数定义,Python都会在末尾加上return None。这类似于while或for循环隐式的以continue语句结尾。而且,如果使用不带值的return语句(也就是只有关键字本身),那么就返回None

 

关键字参数和print()

大多数参数是由它们在函数调用中的位置来识别的。但是,"关键字参数"是由函数调用时加在它们前面的关键字来识别的。关键字参数通常用于可选变元。

print('hello')
print('world')
#输出
hello
world
#这2个字符串出现在独立的2行中,因为print()函数自动在传入的字符串末尾添加了换行符。但是,可以设置end关键字参数,将它变成另一个字符串。例如:

print('hello',end='')
print('world')
#输出
hello world  ##输出被打印在一行中,因为在'hello'后面不再打印换行,而是打印了一个空字符串,如果需要禁用加到每一个print()函数调用末尾的换行,这就很有用。

>>>print('zabbix','rabbit','dog')   # 如果向print()传入多个字符串值,该函数就会自动用一个空格分隔它们。
zabbix rabbit dog

>>>print('zabbix','rabbit','dog',sep=',')   #当传入sep关键字参数,替换掉默认的分隔字符串。
zabbix,rabbit,dog

 

局部和全局作用域

  1. 在被调用函数内赋值的变元和变量,处于该函数的"局部作用域"。处于局部作用域的变量,称为"局部变量"
  • 一个函数被调用时,就创建了一个局部作用域。在这个函数内的所有变量,存在于该局部作用域内。该函数返回时,这个局部作用域就被销毁了,这些变量就丢失了。下次调用这个函数,局部变量不会记得改函数上次被调用时它们保存的值。

         2.在所有函数之外赋值的变量,属于"全局作用域"处于全局作用域的变量,称为"全部变量"

特点:

  • 一个变量必是其中一种,不能既是局部的又是全局的!
  • 全局作用域中的代码不能使用任何局部变量
def spam():
      eggs = 33878

spam()
print(eggs)
#输出
Traceback (most recent call last):
  File "C:/Users/huwei/PycharmProjects/python_Reading/1.py", line 7, in <module>
    print(eggs)
NameError: name 'eggs' is not defined
  • 但是局部作用域可以访问全局变量(也就是说全局变量可以在局部作用域中读取)
def spam():
       print(eggs)

eggs =42
spam()
print(eggs)
#输出
42
42

 

  • 一个函数的局部作用域中的代码,不能使用其他局部作用域中的变量
def spam():
      eggs = 99
      bacon()
      print(eggs)

def bacon():
      ham = 101
      eggs = 0

spam()
#输出
99
  • 如果在不同的作用域中,你可以用相同的名字命名不同的变量。
def spam():
      eggs = 'spam local'
      print(eggs)   #prints   'spam local'
 

def bacon():
      eggs = 'bacon local'
      print(eggs)  #prints 'bacon local'
      spam()
      print(eggs)  #prints 'bacon local'

eggs = 'global'
bacon()
print(eggs) #prints 'global'
#输出
bacon local
spam local
bacon local
global

 

global语句

如果需要在一个函数内修改全局变量,就使用global语句。

def spam():
      global eggs
      eggs = 'spam'

eggs = 'global'
spam()
print(eggs)
#输出
spam

#因为eggs在spam()的顶部被声明为global,所以当eggs被赋值为'spam'时,赋值发生在全局作用域的spam上。没有创建局部spam变量。

 

如何区分一个变量是处于局部作用域还是全局作用域?

def spam():
      global eggs   #(1)
      eggs = 'spam' #   this is the global,eggs是全局eggs变量,因为在函数的开始处,有针对eggs变量的global语句。

def bacon():
      eggs  = 'bacon' #(2)   this is a local,eggs是局部变量,因为在该函数中有针对它的赋值语句。

def ham():
      print(eggs)   #(3)    this is the global,eggs是全局变量,因为在这个函数中,既没有赋值语句,也没有针对它的global语句。

eggs = 42   #this is the global
spam()
print(eggs)
#输出
spam

 

在一个函数中,如果试图在局部变量赋值之前就使用它,Python就会报错!

def spam():
     print(eggs)  #ERROR
     eggs = 'spam local'

eggs = 'global'
spam()
#输出
Traceback (most recent call last):
  File "C:/Users/huwei/PycharmProjects/python_Reading/1.py", line 9, in <module>
    spam()
  File "C:/Users/huwei/PycharmProjects/python_Reading/1.py", line 2, in spam
    print(eggs)  # ERROR
UnboundLocalError: local variable 'eggs' referenced before assignment
#发生这个错误是因为,Python看到spam()函数中有针对eggs的赋值语句,因此认为eggs变量是局部变量。但是因为print(eggs)的执行在eggs赋值之前,局部变量eggs并不存在。Python不会退回到使用全局eggs变量。

 

异常处理

def spam(divideBy):
     return 42 / divideBy


print(spam(2))
print(spam(12))
print(spam(0))
print(spam(1))
执行结果:
21.0
3.5
Traceback (most recent call last):
  File "C:/Users/huwei/PycharmProjects/python_Reading/1.py", line 9, in <module>
    print(spam(0))
  File "C:/Users/huwei/PycharmProjects/python_Reading/1.py", line 2, in spam
    return 42 / divideBy
ZeroDivisionError: division by zero
#当试图用一个数除以0时,就会发生ZeroDivisionError


#解决方法:错误可以由try和except语句来处理。那些可能出错的语句被放在try子句中。如果错误发生,程序执行就转到接下来的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))
#输出
21.0
3.5
Error: Invalid argument!
None
42.0

如果在try子句中的代码导致一个错误,程序执行就立即转到except子句的代码。在运行那些代码之后,执行照常继续。 

 

 

练习:一个小程序,猜数字

I am thinking of a number between 1 and 20.

take a guess.

10

your guess is too low.

take a guess.

15

your guess is too low.

take a guess.

17

your guess is too high.

take a guess.

16

Good Job! You guessed my number in 4 guesses!

import random

def guess():
    count = 0
    print('I am thinking of a number between 1 and 20.')
    answer_number = random.randint(1,20)
    while True:
          print('take a guess.')
          guess_number = int(input())
          count +=1
          if guess_number < answer_number:
                  print('your guess is too low.')
          elif guess_number > answer_number:
                  print('your guess is too high.')
          elif guess_number == answer_number:
                  print('Good Job! You guessed my number in %d guesses!'%count)
                  break
guess()
View Code

 

 

 

习题:

1.为什么在程序中加入函数会有好处。

答:函数是代码逻辑分组的主要方式,函数可以帮助你组织代码,因为函数中的变量存在于他们自己的局部作用域内,所以一个函数中的代码不能直接影响其他函数中变量的值。这限制了哪些代码才能改变变量的值,对于代码调试时很有帮助的。

 

正确答案:函数减少了重复代码。这让程序更短,更容易阅读,更容易修改。

 

2.函数中的代码何时执行:在函数被定义时,还是在函数被调用时?

答:函数中的代码只有在函数被调用时才会被执行。

 

3.什么语句创建一个函数?

答:def语句创建了一个函数

 

 

4.一个函数和一次函数调用有什么区别?

答:函数是一个开头为def的语句,它包含函数名和函数体。如def hello()

而函数之后的hello()是一次函数调用,只有当代码执行到hello()时,才会调用函数def hello()下面的函数体。

 

 

5.Python程序中有多少全局作用域?有多少局部作用域?

答:多个局部作用域,一个全局作用域

 

正确答案:在调用一个函数时,创建了一个全局作用域和一个局部作用域

 

6.当函数调用返回时,局部作用域中的变量发生了什么?

答:当函数调用返回时,局部作用域中的变量被释放/销毁

 

 

7.什么返回值?返回值可以作为表达式的一部分吗?

答:返回值是函数调用求值的结果,称为函数的“返回值”如用def语句创建函数时,可以用return语句指定应该返回什么值。

如:

return 3或x+1

分两种情况:1.如果在rerurn语句中使用了表达式,返回值就是该表达式求值的结果。2.可以直接返回一个值

 

8.如果函数没有返回语句,对它调用的返回值是什么?

答:如果函数没有返回语句,对它调用的返回值就是None,如print()语句

 

 

9.如何强制函数中的一个变量指的是全局变量?

答:使用global关键字,强制变量为全局变量

 

 

10.None的数据类型是什么?

答:None的数据类型就是NoneType

 

11.import areallyourpetsnamederic语句做了什么?

答:import语句导入了 areallyourpetsnamederic模块

 

 

12.如果在名为spam的模块中,有一个名为bacon()函数,在引入spam后,如何调用它?

答:该函数可以使用spam.bacon()调用

 

 

13.如何防止程序在遇到错误时崩溃?

答:使用try    except语句

 

 

14.try子句中发生了什么?except子句中发生了什么?

答:如果try子句中的代码导致了一个错误,程序执行就立即转到except子句的代码。在运行那些代码之后,执行照常继续。

 

实践项目

 

作为实践,请编写程序完成以下任务

 

1.Collatz序列

      编写一个名为collatz()的函数,它有一个名为number的参数,如果参数是偶数,那么collatz()就打印出number//2,并返回该值。如果number是奇数,collatz()就打印并返回3*number+1

      然后编写一个程序,让用户输入一个整数,并不断对这个数调用collatz(),直到函数返回值1!(令人惊奇的是,这个序列对于任何整数都有效,利用这个序列,你迟早会得到1!既是数学家也不能确定为什么。你的程序在研究所谓的“Collatz序列”,它有时候被称为“最简单、不可能的数学问题”

 

def collatz(number):
    if number % 2 == 0:
         return number // 2
    elif number % 2 == 1:
         return 3 * number + 1

while True:
    type_number = int(input('Pls input your number:'))
    correct_number = collatz(type_number)
    print(correct_number)
    if correct_number == 1:
        break
View Code

 

输入验证

  在前面的项目中添加try和except语句,检测用户是否输入了一个非整数的字符串。正常情况下,int()函数在传入一个非整数字符串时,会产生ValueError错误,比如int('puppy')。在except子句中,向用户输出一条信息,告诉他们必须输入一个整数。

def collatz(number):
    if number % 2 == 0:
         return number // 2
    elif number % 2 == 1:
         return 3 * number + 1

while True:
  try:
    type_number = int(input('Pls input your number:'))
    correct_number = collatz(type_number)
    print(correct_number)
    if correct_number == 1:
       break
  except ValueError:
    print('You must input one int!')
View Code

 2

posted @ 2017-06-13 10:38  Mr.hu  阅读(616)  评论(0编辑  收藏  举报