Python教程之三-----深入流程控制
来源:互联网 发布:深圳程序员猝死 编辑:程序博客网 时间:2024/06/05 02:22
除了刚才介绍的while语句之外,Python拥有其他语言也拥有的一些常用的控制流语句,稍微有一点变化
4.1 if 语句
>>> x = int(input("Please enter an integer: "))Please enter an integer: 42>>> if x < 0:... x = 0... print('Negative changed to zero')... elif x == 0:... print('Zero')... elif x == 1:... print('Single')... else:... print('More')...More
4.2 for语句
Python中的for语句和你在C和Pascal中使用的要稍微有点不同。不是总迭代一个等差数列的数字(如Pascal),或者让用户定义迭代步骤和停止条件(如C),Python的for语句迭代任何序列(一个列表或者一个字符串)里的项目,按照它们出现在序列中的顺序。例如:
>>> # Measure some strings:... words = ['cat', 'window', 'defenestrate']>>> for w in words:... print(w, len(w))...cat 3window 6defenestrate 12
如果你需要在循环中修改你正在迭代的序列(例如复制选择的项目),推荐你首先做一个拷贝。迭代一个序列并没有隐式的做一个拷贝。切片表示法使这些变的极为方便:
>>> for w in words[:]: # Loop over a slice copy of the entire list.... if len(w) > 6:... words.insert(0, w)...>>> words['defenestrate', 'cat', 'window', 'defenestrate']
如果使用 for w in words:,那么上述例子将会尝试创建一个无穷大的列表,一遍一遍的插入defenestrate。
4.3 range()函数
>>> for i in range(5):... print(i)...01234
range(5, 10) 5 through 9range(0, 10, 3) 0, 3, 6, 9range(-10, -100, -30) -10, -40, -70
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']>>> for i in range(len(a)):... print(i, a[i])...0 Mary1 had2 a3 little4 lamb
>>> print(range(10))range(0, 10)
>>> list(range(5))[0, 1, 2, 3, 4]
4.4 循环中的break语句和continue语句,还有else子句
>>> for n in range(2, 10):... for x in range(2, n):... if n % x == 0:... print(n, 'equals', x, '*', n//x)... break... else:... # loop fell through without finding a factor... print(n, 'is a prime number')...2 is a prime number3 is a prime number4 equals 2 * 25 is a prime number6 equals 2 * 37 is a prime number8 equals 2 * 49 equals 3 * 3
>>> for num in range(2, 10):... if num % 2 == 0:... print("Found an even number", num)... continue... print("Found a number", num)Found an even number 2Found a number 3Found an even number 4Found a number 5Found an even number 6Found a number 7Found an even number 8Found a number 9
4.5 pass语句
pass语句什么都不做。当在语法上需要一个语句,但是程序不需要动作的时候,就可以使用它。例如:
>>> while True:... pass # Busy-wait for keyboard interrupt (Ctrl+C)...
这个通常用来创建最小的类:
>>> class MyEmptyClass:... pass...
另一个使用pass语句的情况是当你在编写一个新的代码时作为一个函数或条件体充当补位符,允许你在一个更抽象的层次上面思考。pass语句被忽略了。
4.6 定义函数
我们能创建一个函数将斐波那契级数写成一个任意的边界:
>>> def fib(n): # write Fibonacci series up to n... """Print a Fibonacci series up to n."""... a, b = 0, 1... while a < n:... print(a, end=' ')... a, b = b, a+b... print()...>>> # Now call the function we just defined:... fib(2000)0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字def表示一个函数的定义。必须遵循函数名和带括号的形式参数列表。函数体的起始语句要另起一行,并且必须缩进。
函数体的第一个语句可以是一个字符串常量。这个字符串常量是函数的文档字符串,或者docstring。有工具使用docstrings来自动生成在线或者打印文档,或者让用户交互式的浏览代码;在编写的代码中包含docstrings是一个好的方法,因此要养成一个习惯。
函数的执行为函数的局部变量引入了一个新的符号表。更准确的说,函数中说有变量的赋值都储存在本地符号表中;然而变量引用首先查找本地符号表,然后查找封闭函数的本地符号表,然后是全局符号表,最后是内置名称表。因此,全局变量不能直接在函数(除非是一个全局的语句)中赋值,尽管可以被引用。
函数调用的实际参数是在函数调用时在其本地符号表中引入的。因此,参数通过值调用传递(值始终是一个对象的引用,而不是对象的值)。当一个函数调用另一个函数时,将会创建一个新的本地符号表。
函数定义在当前符号表中引入函数名。函数名的值被解释器识别为一个用户定义的函数类型。这个值能被赋值给另外一个名称,那个名称同样也能当成函数使用。这是一个通用的重命名机制:
>>> fib<function fib at 10042ed0>>>> f = fib>>> f(100)0 1 1 2 3 5 8 13 21 34 55 89
用其他语言的经验来说,你可能法对fib不是一个函数而是一个过程因为它并没有返回一个值。事实上,即使函数没有返回语句但它却是有返回一个值,尽管是一个相当乏味的值。这个值称为None(这是一个内置名称)。如果是唯一一个被写的值,那么解释器通常不会禁止:
>>> fib(0)>>> print(fib(0))None
写一个返回斐波那契系列的数字列表的函数,而不是打印它是非常简单的:
>>> def fib2(n): # return Fibonacci series up to n... """Return a list containing the Fibonacci series up to n."""... result = []... a, b = 0, 1... while a < n:... result.append(a) # see below... a, b = b, a+b... return result...>>> f100 = fib2(100) # call it>>> f100 # write the result[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]123
这个例子,和以前一样,演示了一些新的Python特性:
- return语句从一个函数中返回一个值。没有表达式参数返回的时候返回None。函数的末尾,同样也返回None。
- 语句result.append(a)调用一个列表对象result的方法。方法是属于一个对象的函数,命名为obj。methodname,其中obj是某些对象(也可能是一个表达式),并且methodname是由对象类型定义的方法的名称。不同的类型定义不同的方法。不同的类型的方法可能会有同样的名字而不会引起歧义。(可以使用classes来定义你自己的对象类型和方法)上例中的append()方法是为列表对象定义的;它在列表的结尾添加一个新的元素。它等价于result = result + [a],但更效率。
4.7 更多关于定义函数
定义一个可变数量参数的函数也是可以的。总共有3个形式,可以组合使用。
4.7.1 默认参数值
最游泳的形式是为一个或更多的参数指定一个默认值。这可以创建一个比它允许定义的更少的参数的函数。例如:
def ask_ok(prompt, retries=4, reminder='Please try again!'): while True: ok = input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise ValueError('invalid user response') print(reminder)
这个函数能用以下几种形式调用:
- 只给出强制的参数:ask_ok('Do you really want to quit?')
- 给一个给选参数:ask_ok('Ok to overwrite the file?',2)
- 给出所有的参数:ask_ok('OK to overwrite the file?',2,'Come on,only yes or no!'
i = 5def f(arg=i): print(arg)i = 6f()
def f(a, L=[]): L.append(a) return Lprint(f(1))print(f(2))print(f(3))
[1][1, 2][1, 2, 3]
def f(a, L=None): if L is None: L = [] L.append(a) return L
4.7.2 关键字参数
函数同样能使用关键字参数kwarg=value的形式来调用。例如如下的函数:def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ') print("if you put", voltage, "volts through it.") print("-- Lovely plumage, the", type) print("-- It's", state, "!")
parrot(1000) # 1 positional argumentparrot(voltage=1000) # 1 keyword argumentparrot(voltage=1000000, action='VOOOOOM') # 2 keyword argumentsparrot(action='VOOOOOM', voltage=1000000) # 2 keyword argumentsparrot('a million', 'bereft of life', 'jump') # 3 positional argumentsparrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
parrot() # required argument missingparrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argumentparrot(110, voltage=220) # duplicate value for the same argumentparrot(actor='John Cleese') # unknown keyword argument
>>> def function(a):... pass...>>> function(0, a=0)Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: function() got multiple values for keyword argument 'a'123
def cheeseshop(kind, *arguments, **keywords): print("-- Do you have any", kind, "?") print("-- I'm sorry, we're all out of", kind) for arg in arguments: print(arg) print("-" * 40) for kw in keywords: print(kw, ":", keywords[kw])
cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper="Michael Palin", client="John Cleese", sketch="Cheese Shop Sketch")
-- Do you have any Limburger ?-- I'm sorry, we're all out of LimburgerIt's very runny, sir.It's really very, VERY runny, sir.----------------------------------------shopkeeper : Michael Palinclient : John Cleesesketch : Cheese Shop Sketch
4.7.3 可变参数列表
最后,最少使用的选项是指定一个函数可以拥有可变数量的参数。这些参数可以是元祖。在这些可变参数之前,可能出现0个或者更多的正常参数。
def write_multiple_items(file, separator, *args): file.write(separator.join(args))
通常的,这些可变参数将出现在正常参数列表的最后,因为它将手机传递给这个函数的所有剩余的参数。任何出现在*args后面的正常参数都是'唯一关键字参数',意味着他们只能作为关键字而不是位置参数。
>>> def concat(*args, sep="/"):... return sep.join(args)...>>> concat("earth", "mars", "venus")'earth/mars/venus'>>> concat("earth", "mars", "venus", sep=".")'earth.mars.venus'
4.7.4 参数列表的拆分
当这些参数已经在一个元祖或者列表里面但是需要为了一个函数调用需要飞鸽的位置参数拆分时,相反的情况就会发生。例如,内置函数range()需要开始和结束参数。如果他们不能分隔,用*操作符来写函数调用来拆分一个列表或元祖的参数:
>>> list(range(3, 6)) # normal call with separate arguments[3, 4, 5]>>> args = [3, 6]>>> list(range(*args)) # call with arguments unpacked from a list[3, 4, 5]
用同样的方式,字典能用**操作符传递关键字参数:
def parrot(voltage, state='a stiff', action='voom'):... print("-- This parrot wouldn't", action, end=' ')... print("if you put", voltage, "volts through it.", end=' ')... print("E's", state, "!")...>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}>>> parrot(**d)-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
4.7.5 Lambda表达式
可以使用lambda关键字来创建一些小的匿名函数。这个函数返回它2个参数:lambda a,b:a+b的汇总值。不管函数对象是否需要,Lambda函数都能使用。他们在语法上被限制为一个单一语句。在语法上来说,他们就是一个正常函数定义的语法糖。就像嵌套函数定义,lambda函数能引用包含的变量:
>>> def make_incrementor(n):... return lambda x: x + n...>>> f = make_incrementor(42)>>> f(0)42>>> f(1)43
上述例子使用一个lambda表达式返回一个函数。另一个用法是传递一个小函数作为参数:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]>>> pairs.sort(key=lambda pair: pair[1])>>> pairs[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
4.7.6 文档字符串
这里有一些关于文档字符串的内容和格式的约定。
第一行应该是一个简短的对象意图的总结。简短的说,它不应该明确的陈述对象的名称或者类型,因为这可以通过其他方式获得(除非这个名称是描述一个函数操作的动词)。这一行应该以一个大写字母开头,一个句号结尾。
如果在文档字符串中有更多的行,第二行应该留空,显示的将总结与其他描述分开。接下来的应该是描述对象调用约定,和其副作用的一个或者几个段落。
在Python中,Python解释器不会从多行的字符串中去掉缩进,所以如果想要这么做的话,处理文档的工具就必须去掉缩进。以下约定可以达成。紧接第一行的非空行字符串决定了整个文档字符串的缩进量。(我们不能用第一行,是因为它和字符串的引号相邻,所以在字符串中它的缩进不明显)然后从字符串的所有行去除相同的空格。没有缩进的行不应该出现,如果出现了,那么零头的行的空格也应该去掉。使用tabs(一般是8个空格)后最好做一些检查。
以下是一个多行docstring的例子:
>>> def my_function():... """Do nothing, but document it....... No, really, it doesn't do anything.... """... pass...>>> print(my_function.__doc__)Do nothing, but document it. No, really, it doesn't do anything.
4.7.7 函数注解
函数注解是关于用户自定义函数类型的完全可选的元数据信息。
注解作为一个字典储存在函数的属性__annotations__中,并且对函数的其他任何部分没有影响。参数注解是由参数名后面的一个冒号来定义的,然后紧跟着的是对注解评估的表达式。返回注解由字符 ->定义,紧跟的是在参数列表和表示def语句结尾的冒号之间。下面的例子中有一个位置参数,一个关键字参数,并且返回注解的值:
>>> def f(ham: str, eggs: str = 'eggs') -> str:... print("Annotations:", f.__annotations__)... print("Arguments:", ham, eggs)... return ham + ' and ' + eggs...>>> f('spam')Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}Arguments: spam eggs'spam and eggs'123
4.8 插曲:编程风格
既然你即将写更长的,跟复杂的Python代码段,是时候来讨论下编程风格了。大多数语言可以以不同的方式来编写(或者更简洁,格式化);一些比另一些更具有可读性。让别人更容易读懂你的代码始终是一个好的想法,采用一个好的编程风格将会对那有巨大的帮组
在Python中,PEP 8已经成为大多数项目遵循的风格指导方法;使用它可以写出一个非常具有可读性已经养眼的代码。每一个Python开发者都应该找个时间阅读以下;下面是萃取的最重要的几点:
- 使用4空格的缩进,不要tab。 4个空格是在小的缩进(允许更深的嵌套深度)和大的缩进(更容易阅读)之间的一个折中取值。tabs容易引起困惑,最好不要使用
- 每一行最好不要超过79个字符。 这将会对一些小的显示设备有益,并且大的设备可以并排显示多分代码文件
- 使用空行来分隔函数和类,以及函数体内大的代码块
- 如果可以的话,每一行最好有注释
- 使用docstrings
- 在逗号后和操作符前后使用空格,但不是在括弧内:a = f(1,2) + g(3,4)
- 连贯的命名你的类和函数;约定是类使用 骆驼拼写法 ,函数和方法使用带下划线的小写字母。总是使用self作为第一个方法参数的名字。
- 如果你的代码将在国际环境里使用,请不要使用花俏的编码。Python默认是UTF-8,或者甚至是在任何情况下平实的ASCII
- 同样的,即使是只有极少的机会会有不同语言的人来阅读或维护代码,请不要使用非ASCII码字符的标识符。
- Python教程之三-----深入流程控制
- PL/SQL教程之三:流程控制
- 深入 Python 流程控制
- python学习(3)- 深入流程控制
- Python 流程控制之while
- java学习之三大流程控制
- Swift 基本知识点之三流程控制
- PL/SQL之三- 流程控制语句
- Shell编程语法之三:流程控制
- PHP之流程控制(三)
- Python 学习笔记之流程控制
- 深入探析koa之中间件流程控制篇
- (三)python的流程控制及函数定义
- 四.Python流程控制の(三)分支结构switch
- Python自学(三):列表(list)和流程控制
- 《简明Python教程》之控制流
- 三、流程控制
- 流程控制(三)
- oracle创建和使用触发器
- 利用JQuery发送ajax请求进行站内搜索(Hibernate篇——超简单系列)
- 【九度OJ】1185:特殊排序
- linux进行tomcat的监听
- Codeforces
- Python教程之三-----深入流程控制
- Codeforces 849B
- Python Web开发 之Django框架入门学习笔记(一)——安装和初步使用
- 一个简单的Java反射Demo
- Hadoop Left Join
- 支持向量机(SVM)与其理论发展(2):对偶学习
- Qt5注册全局热键
- Hadoop Left Join2
- Linux下C语言多线程学习之一——线程的创建