python3 陌生的角落(3):条件、迭代、模块、文件输入输出

1.print() sep 参数使用

>>> a=10;b=388;c=98
>>> print(a,b,c,sep='@')
10@388@98

2.while 循环使用 else 语句

在 while … else 在条件语句为 false 时执行 else 的语句块:

实例
#!/usr/bin/python3
 
count = 0
while count < 5:
   print (count, " 小于 5")
   count = count + 1
else:
   print (count, " 大于或等于 5")

执行以上脚本,输出结果如下:

0  小于 5
1  小于 5
2  小于 5
3  小于 5
4  小于 5
5  大于或等于 5

3.使用内置 enumerate 函数进行遍历:

for index, item in enumerate(sequence):
    process(index, item)
实例
>>> sequence = [12, 34, 34, 23, 45, 76, 89]
>>> for i, j in enumerate(sequence):
...     print(i, j)
... 
0 12
1 34
2 34
3 23
4 45
5 76
6 89

4.迭代器

迭代器有两个基本的方法:iter() 和 next()。
字符串,列表或元组对象都可用于创建迭代器:
实例(Python 3.0+)

>>>list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

5.生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
以下实例使用 yield 实现斐波那契数列:

实例(Python 3.0+)
#!/usr/bin/python3
 
import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()

执行以上程序,输出结果如下:

0 1 1 2 3 5 8 13 21 34 55

下一个代码更有利于你理解代码:

import sys

    def fibonacci(n):  # 生成器函数 - 斐波那契
        a, b, counter = 0, 1, 0
        while True:
            if (counter > n):
                return
            # yield a
            a, b = b, a + b
            print(a,"=====",b)
            counter += 1

    f = fibonacci(10)  # f 是一个迭代器,由生成器返回生成

    # while True:
    #     try:
    #         print(next(f), end=" ")
    #     except StopIteration:
    #         sys.exit()

结果如下:

1 ===== 1
1 ===== 2
2 ===== 3
3 ===== 5
5 ===== 8
8 ===== 13
13 ===== 21
21 ===== 34
34 ===== 55
55 ===== 89
89 ===== 144
  • 打个比方的话,yield有点像断点。 加了yield的函数,每次执行到有yield的时候,会返回yield后面的值 并且函数会暂停,直到下次调用或迭代终止;
  • yield后面可以加多个数值(可以是任意类型),但返回的值是元组类型的。
    我们可以得出以下结论:
    一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
    yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。
    如何判断一个函数是否是一个特殊的 generator 函数?可以利用 isgeneratorfunction 判断:
>>>from inspect import isgeneratorfunction 
>>> isgeneratorfunction(fab) 
True

return 的作用
在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。

6.可更改(mutable)与不可更改(immutable)对象-可看可不看

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
**不可变类型**:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

7.不定长参数

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

# 可写函数说明
def printinfo( age=35,name):   # 默认参数不在最后,会报错
    "打印任何传入的字符串"
    print("名字: ", name);
    print("年龄: ", age);
    return;
#!/usr/bin/python3
 
# 可写函数说明
def printinfo( arg1, *vartuple ):
   "打印任何传入的参数"
   print ("输出: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return;
 
# 调用printinfo 函数
printinfo( 10 );
printinfo( 70, 60, 50 );
#以上实例输出结果:
输出:
10
输出:
70
60
50

8.变量作用域

以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

x = int(2.9)  # 内建作用域
 
g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域

###全局变量global 和局部变量nonlocal

  • 当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了。
    以下实例修改全局变量 num:
num = 1

def fun1():
    #global num  # 需要使用 global 关键字声明
    num =123 
    print(num)   # 123
    f = 123 + num 
    print(f)  # 124

fun1()
print(num)  # 1

添加后global 关键字后。

num = 1

def fun1():
    global num  # 需要使用 global 关键字声明
    num =123
    print(num)   # 123
    f = 123 + num
    print(f)  # 124

fun1()
print(num)  # 123
  • 如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

输出结果:

100
100

屏蔽nonlocal关键字后,看一下效果。

def outer():
    num = 10
    def inner():
        #nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

结果如下:

100
10
  • 特殊情况
a = 10
def test():
    c = a + 1
    print(c)
test()

结果:11。


a = 10
def test():
    a = a + 1
    print(a)
test()

报错:

Traceback (most recent call last):
  File "D:/depthStudyWorks/18FirstYear/code/test.py", line 75, in <module>
    test()
  File "D:/depthStudyWorks/18FirstYear/code/test.py", line 73, in test
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。(等号右边的a没有定义)

9.列表推导式

列表推导式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个序列的每个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列。

>>> vec = [2, 4, 6]
>>> [3*x for x in vec]
[6, 12, 18]
#现在我们玩一点小花样:
>>> [[x, x**2] for x in vec]
[[2, 4], [4, 16], [6, 36]]

我们可以用 if 子句作为过滤器:

>>> [3*x for x in vec if x > 3]
[12, 18]
>>> [3*x for x in vec if x < 2]
[]

以下是一些关于循环和其它技巧的演示:

>>> vec1 = [2, 4, 6]
>>> vec2 = [4, 3, -9]
>>> [x*y for x in vec1 for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>> [x+y for x in vec1 for y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
>>> [vec1[i]*vec2[i] for i in range(len(vec1))]
[8, 12, -54]
  • 嵌套列表解析
>>> matrix = [
...     [1, 2, 3, 4],
...     [5, 6, 7, 8],
...     [9, 10, 11, 12],
... ]
以下实例将3X4的矩阵列表转换为4X3列表:
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

层叠式循环推导式:

l = []
    for x in range(1, 5):
        if x > 2:
            for y in range(1, 4):
                if y < 3:
                    l.append(x * y)
    print(l)
    print([x * y for x in range(1, 5) if x > 2 for y in range(1, 4) if y < 3])

结果:

[3, 6, 4, 8]
[3, 6, 4, 8]
  • 关于嵌套列表解析
    从左到右的for语句顺序对应的是从外到里的层次关系。上面有些笔记是用优先级来解析,这样是不太合理的,不便于理解。
    最左侧的表达式可以直接使用后面出现的变量,而不是只限于相连的for,所以结合上面的结论。例子还可以写 [row[i] for i in range(4) for row in matrix],效果一样。
    例子为何不用()来改变嵌套的层次关系而用 [],因为 python 解析器会把 (row[i] for row in matrix) 解析为一个 生成器 generator。这里举一个例子
>>> (i for i in range(4))
<generator object <genexpr> at 0x110114360>
>>> [i for i in range(4)]
[0, 1, 2, 3]
>>> a = (i for i in range(4))
>>> next(a)
0
>>> next(a)
1
>>>

10.遍历技巧

在序列中遍历时,索引位置和对应值可以使用 enumerate() 函数同时得到:

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
0 tic
1 tac
2 toe

在字典中遍历时,关键字和对应的值可以使用 items() 方法同时解读出来:

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
...
gallahad the pure
robin the brave

同时遍历两个或更多的序列,可以使用 zip() 组合:

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('what is your %s? it is %s' % (q, a))
        print('--------------------------')
        print('what is your {0}? it is {1}'.format(q, a))
...
what is your name? it is qinshihuang
--------------------------
what is your name? it is qinshihuang
what is your quest? it is the holy
--------------------------
what is your quest? it is the holy
what is your favorite color? it is blue
--------------------------
what is your favorite color? it is blue

11.输出格式美化

如果你希望输出的形式更加多样,可以使用 str.format() 函数来格式化输出值。
如果你希望将输出的值转成字符串,可以使用 repr() 或 str() 函数来实现。

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # 注意前一行 'end' 的使用
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

这个例子展示了字符串对象的 rjust() 方法, 它可以将字符串靠右, 并在左边填充空格。
还有类似的方法, 如 ljust() 和 center()。

>>> print('{0} 和 {1}'.format('Google', 'Runoob'))
Google 和 Runoob
>>> print('{1} 和 {0}'.format('Google', 'Runoob'))
Runoob 和 Google
#如果在 format() 中使用了关键字参数, 那么它们的值会指向使用该名字的参数。
>>> print('{name}网址: {site}'.format(name='菜鸟教程', site='www.runoob.com'))
菜鸟教程网址: www.runoob.com
#位置及关键字参数可以任意的结合:
>>> print('站点列表 {0}, {1}, 和 {other}。'.format('Google', 'Runoob',
                                                       other='Taobao'))
站点列表 Google, Runoob, 和 Taobao。

12.pickle 模块

python的pickle模块实现了基本的数据序列和反序列化。
通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。
基本接口:

pickle.dump(obj, file, [,protocol])
#有了 pickle 这个对象, 就能对 file 以读取的形式打开:
x = pickle.load(file)

这里不详细,以后添加。。。

13.File writelines() 方法

writelines() 方法用于向文件中写入一序列的字符串。
这一序列字符串可以是由迭代对象产生的,如一个字符串列表。
换行需要制定换行符 \n。
语法
writelines() 方法语法如下:

fileObject.writelines( [ str ])

参数
str – 要写入文件的字符串序列。

##实例
##以下实例演示了 writelines() 方法的使用:
#!/usr/bin/python3

# 打开文件
fo = open("test.txt", "w")
print ("文件名为: ", fo.name)
seq = ["菜鸟教程 1\n", "菜鸟教程 2"]
fo.writelines( seq )

# 关闭文件
fo.close()

#以上实例输出结果为:

#文件名为:  test.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值