python初级学习(三)

一:生成器

1.为什么需要生成器?


通过列表生成式,我们可以直接创建一个列表,受到内存限
制,列表容量肯定是有限的;

创建一个包含 100 万个元素的列表,占用很大的存储空间;

2.生成器是什么?

• 在循环的过程中不断推算出后续的元素呢?这样就不必创
建完整的 list,从而节省大量的空间。在 Python 中,这种一
边循环一边计算的机制,称为生成器(Generator)

3.怎么创建生成器?

  • 把一个列表生成式的 [] 改成 ()
  • 使用g.next()方法依次读取元素(麻烦)
  • 使用 for 循环(推荐)

4.yield工作原理:

调用g.next()方法时时, 执行函数,遇到yield就停止执行;
再次执行g.next()方法时, 从yield停止的地方继续执行;

5.怎么访问生成器的内容

  • g.next()
  • for循环;
def fib(max):
    n, a, b = 0, 1, 1
    while n < max:
    yield a  # 执行函数时, 遇到yield就停止执行;再次执行函数时, 从yield停止的地方继续执行;
    n += 1
    a, b = b, a+b
g =  fib(10)
g.next()
g.next()
g.next()

6.生成器的其他应用

  • 无缓冲区的生产者-消费者模型: java, php, python
  • 有缓冲区的生产者-消费者模型: java, php, python

(消费) =======【商店】======== (生产)

import time
import random


# 有yield关键字的函数称为生成器函数;
def consumer(name):
    print "%s准备取购买包子......." %(name)
    while True:
        kind = yield
        print "消费者[%s]购买了[%s]口味的包子" %(name, kind)



def producer(name):
    # c1和c2是生成器;
    c1 = consumer("王凯")
    c2 = consumer("刘泳")

    # 第一次执行函数;
    c1.next()
    c2.next()


    print "厨师[%s]正在制作包子......" %(name)
    for i in ['特辣', '麻辣']:
        # 停止0~1秒之间的随机数,用来模拟生产包子;
        time.sleep(random.random())
        print "【%s】正在生产[%s]口味的包子!" %(name, i)
        c1.send(i)
        c2.send(i)

producer("fentiao")

生成器与文本处理

对于大型文件的每一行执行相应操作;

consumer函数有=yield, 是生成器函数;

def consumer():
    while True:
        line = yield   # c.next()停止在这一行;
        print line.upper()   # 打印被操作的文件每一行内容;

producer函数有=yield, 是生成器函数;

def producer():
    with open('/etc/passwd') as f:   # 打开/etc/passwd文件, 返回一个f的文件对象;
        for i in f:                  # 查看文件内容, for i in f, 依次查看文件的每一行;  # i: 第一行文件内容, 2, 3,4
            yield i
            print i

c = consumer()  # c是生成器;
c.next()        # 通过next方法执行consumer函数, 遇到yield停止;
for line in producer():  # producer()是生成器; 生成器是可迭代的, 可以for循环;  # 24行的i给line
    c.send(line)

迷你聊天机器人

def chat_robot():
    res = ''
    while True:
        received = yield res
        if "name" in received or "姓名" in received:
            res =  "你好, 我是微软小冰"
        elif "年龄" in received or 'age' in received:
            res =  "18"
        else:
            res =  "我还在学习中, 不清楚你在说什么."


Chat = chat_robot()

# Chat.next()
next(Chat)

while True:
    send_data = raw_input("A>>:")
    recv_data = Chat.send(send_data)
    print "微软小冰>>:%s" %(recv_data)


# g.next() | next(g): 运行生成器函数, 遇到yield停止; 再次next(), 从yield停止的地方继续执行;
# g.send(): 给生成器函数传值, 实现与生成器的交互, 在函数的yield前面可以通过一个变量接收值;
# close:关闭生成器, 不能再调用next方法, 否则报错StopIteration;
# throw:
"""
g = (i**2 for i in range(10))
g
Out[3]: <generator object <genexpr> at 0x3a5e500>
g.next()
Out[4]: 0
g.next()
Out[5]: 1
g.next()
Out[6]: 4
g.close()
g.next()
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/IPython/core/interactiveshell.py", line 2882, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-8-7dbbdfed0980>", line 1, in <module>
    g.next()
StopIteration

生成器的throw方法

throw方法:给生成器发送一个异常;

def fun():
    while True:
        yield  'a'
        yield  'b'
g = fun()
print next(g)
g.throw(StopIteration)

什么是异常?

# NameError,ZeroDivisionError,IndexError,KeyError

二:高级函数

1.什么是高级函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另
一个函数作为参数,这种函数就称之为高阶函数。

# def fun(f):
#     return f()
#
# def hello():
#     return "hello world"
#
# print fun(hello)


# def fun():
#     def hello():
#         return "hello world"
#     return hello
# f = fun()
# print f()

2.map函数

map() 函数接收两个参数,一个是函数,一个是序列, map 将传入的函数依
次作用到序列的每个元素,并把结果作为新的 list 返回。
不需要 map() 函数,写一个循环,也可以计算出结果.
map() 作为高阶函数,把运算规则抽象了.

# def f(x):
#     return x**2
#
# # map函数至少需要两个参数, 第一个参数是函数名, 第2个参数是序列(str, list, tuple);
# # map的功能: 把序列中的每一个元素作为参数, 传给函数进行处理;
# print map(f, [1,2,3,4,5])
# print map(int, ['1', '2', '3', '4'])

3.reduce函数

reduce 把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接
收两个参数,reduce 把结果继续和序列的下一个元素做累积计算。

def add(x, y):
    return x + y


# reduce函数至少需要两个参数, 第一个参数是函数名<注意, 函数名必须传递两个参数>, 第2个参数是序列(str, list, tuple);
# reduce的功能: 把序列中的前2个元素作为参数(add(1,2)), 传给函数进行处理;然后将add(1,2)的结果作为参数, 继续传递add(add(1,2),3);
print reduce(add, range(1, 1001))  # add(add(add(1,2),3),4)

4.filter函数

filter() 也接收一个函数和一个序列。和 map() 不同的时,
filter() 把传入的函数依次作用于每个元素,然后根据返回值是 True
还是 False 决定保留还是丢弃该元素。

# filter函数至少需要两个参数, 第一个参数是函数名<注意, 函数的返回值必须是True或者False>, 第2个参数是序列(str, list, tuple);
# filter的功能: 把序列中执行函数的返回值为True的保留, 为False的丢弃;
def isodd(x):
    return x % 2 == 0

print filter(isodd, range(1, 10))

找出指定范围的所有素数;

def isPrime(num):
    # 2是最小的质数;
    if num == 2: return True
    # 负数或者能被2整除的数, 不是质数;
    if num <= 1 or num%2 == 0: return False
    for i in range(3,num,2): ## 3~num-1
        # 如果num能被1或者它本身的其他数整除, 则不是质数;
        if num % i == 0:
            return False
    # 一直从3~num-1判断, 都没有被整除, 则是质数;
    else:
        return  True


print filter(isPrime, range(1, 101))

阶乘

def fun(x, y):
    return x * y

# 1000阶乘的结果
res =  reduce(fun, range(1, 1001))
print res


#统计阶乘结果有多少个0;
res_s = str(res)
print res_s.count('0')

名称规范

names = ['adam', 'LISA', 'barT', 12]
def title(x):
    if isinstance(x, str):
        return x.title()
    return x
    # else:
    #     return x

print map(title, names)

删除素数

def isPrime(num):
    # 2是最小的质数;
    if num == 2: return True
    # 负数或者能被2整除的数, 不是质数;
    if num <= 1 or num%2 == 0: return False
    for i in range(3,num,2): ## 3~num-1
        # 如果num能被1或者它本身的其他数整除, 则不是质数;
        if num % i == 0:
            return False
    # 一直从3~num-1判断, 都没有被整除, 则是质数;
    else:
        return  True

def isNotPrime(num):
    return not isPrime(num)

print filter(isNotPrime, range(1, 101))

5.sorted函数

  • • 排序也是在程序中经常用到的算法。 无论使用冒泡排序还是快速 排序,排序的核心是比较两个元素的大小。通常规定如下:
x < y, return -1
x == y, return 0
x > y, return 1
li.sort(): 只针对于列表排序;
sorted():
import random

li = range(100)
# 打乱序列的顺序;
random.shuffle(li)
# print li

# 默认情况, 由小到大进行排序;
print sorted(li)

# reverse=True时, 由大到小进行排序;
print sorted(li, reverse=True)

# # cmp如果a>b, 返回1; a=b, 返回0; a<b, 返回-1;
# print cmp(1, 2)
# print cmp(2, 1)
# print cmp(1, 1)



users = ['abx', 'Alice', 'bob', 'Harry', 'hub']


def ignore_case_cmp(x, y):
    return cmp(x.lower(), y.lower())


# cmp=后面跟的函数要求:
#       1). 函数需要传递两个参数;
#       2). 函数要么返回1, -1或者0;
print sorted(users, cmp=ignore_case_cmp)

典例

goods = [
    ['computer', 230, 4000],
    ['apple', 2000, 4],
    ['xiaomi', 23, 1999],
    ['mp3', 2, 40]
]


# 把goods[0]传给 key=lambda x: x[2];  4000
# 把goods[1]传给 key=lambda x: x[2];  4
# 把goods[2]传给 key=lambda x: x[2];  1999
# 把goods[3]传给 key=lambda x: x[2];  40

# # 找出价格最高的商品名称;
# price_sort_goods = sorted(goods, key=lambda x: x[2])
# print price_sort_goods[-1][0]
#

# 找出商品数量最少的商品名称和商品数量;
count_sort_goods = sorted(goods, key = lambda x:x[1])
print count_sort_goods
# print count_sort_goods[0][:2]


#
# goods_dict = {
#     '001': {
#         'name': 'computer',
#         'price': 4000,
#         'count': 20,
#     },
#     '002': {
#         'name': 'apple',
#         'price': 2,
#         'count': 100
#     },
#     '003': {
#         'name': 'xiaomi',
#         'price': 2999,
#         'count': 10
#     }
# }
#
# # 找出价格最高的商品名称;
# price_sort_goods_dict = sorted(goods_dict.values(), key=lambda x: x['price'])
# print price_sort_goods_dict[-1]['name']
#
# # 找出商品数量最少的商品名称和商品数量;
# count_sort_goods_dict =  sorted(goods_dict.values(), key=lambda x: x['count'])
# print count_sort_goods_dict[0]['name'],  count_sort_goods_dict[0]['count']

6.匿名函数

def add(x, y):
    return x + y


print add(1, 2)

匿名函数的格式: lambda 形式参数:返回值

f = lambda x, y: x + y
print f(2, 3)

求10的阶乘;

print reduce(lambda x, y: x * y, range(1, 11))

求1~10之间所有的偶数;

print filter(lambda x: x % 2 == 0, range(1, 11))

匿名函数的默认参数;

f = lambda x, y=2: x ** y
print f(2)
print f(2, 4)

匿名函数的可变参数;

f = lambda *args: sum(args)
print f(1,2,2,43,4)
print f(1,2,2)

匿名函数的关键字参数;

f = lambda **kwargs: kwargs.keys()
print f(name="fentiao", age=5)

携程2018笔试编程题: 题目内容看群图片

nums = [0, 7, 0, 1, 2, 1, 5,1, 7, 8, 0, 67, 1, 3, 4]

默认排序时; 0, 1

print sorted(nums, key=lambda x: 0 if x == 0 else 1, reverse=True)

三:装饰器

1.什么是装饰器

  • 装饰器就是用来装饰函数。

    • 想要增强原有函数的功能;
    • 但不希望修改now()函数的定义;
    • 在代码运行期间动态增加功能的方式;
    

•定义的装饰器实质是返回函数的高阶函数。(试试下面的装饰器)

import time
def timeIt(func):
def warp(arg):
start = datetime.datetime.now()
func(arg)
end = datetime.datetime.now()
cost = end - start
print "execute %s spend %s" % (func.__name__,cost.total_seconds())
return warp
@timeIt # 这里是 python 提供的一个语法糖
def func(arg):
time.sleep(arg)
func(3)
import  time
import random


def Timer(f):
    def wrapper():
        start_time = time.time()
        f()
        end_time = time.time()
        print "程序运行时间为%s" %(end_time-start_time)
    return wrapper


@Timer
def fun1():
    print "fun1....."
    time.sleep(random.random())

@Timer
def fun2():
    print "fun2....."
    time.sleep(random.random())

def fun3():
    print "fun3....."
    time.sleep(random.random())

fun1()
fun2()
fun3()
    # 此处省略100个函数

闭包: 在函数里面嵌套一个函数

装饰器: 器,指的就是函数; 用来装饰函数的函数;

产品经理, 开发人员

import time


# def addWelcome():
#     # print "七一建党节快乐!"
#     start_time = time.time()
#     return start_time
#
#
#
# def afterWelcome():
#     end_time = time.time()
#     return end_time

# def saveMoney():
#     start_time = addWelcome()
#     print "存钱......"
#     end_time = afterWelcome()
#     print end_time-start_time




def Timer(f):  # f = saveMoney
    def wrapper():
        start_time = time.time()
        f()   # saveMoney()
        end_time = time.time()
        print "%s执行时间为%s" %(f.__name__, end_time-start_time)
    return  wrapper   #

@Timer   # saveMoney = Timer(saveMoney)     # saveMoney = wrapper
def saveMoney():
    print "存钱......"
saveMoney()  #

@Timer  # transferMoney = Timer(transferMoney)
def transferMoney():
    print "转账......"

transferMoney()
# print saveMoney.__name__
# transferMoney()



# 编写装饰器is_admin, 如果是管理员用户, 则执行函数, 如果不是管理员, 则报错;
def is_admin(f):
    def wrapper(name):
        if name == 'admin':
            f(name)
        else:
            print "Error: not admin user"
    return wrapper

@is_admin
def fun(name):
    print "fun......"

fun('admin')

装饰器模版

import time
import functools

def Timer(f): # f=add
    # 为什么装饰器中嵌套函数? 为了不改变原有函数的调用方式;
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        """\twrapper\t"""
        start_time = time.time()
        tmp = f(*args, **kwargs)   # add(*args, **kwargs)
        end_time = time.time()
        print end_time-start_time
        return tmp
    return wrapper


@Timer
def add(*args):
    return sum(args)

print add(1,2,3,4,5,56)


@Timer   #login = Timer(login)
def login():
    """\tlogin\t"""
    print "login......"

解析装饰器

import time

def Timer(fun):   # fun=login
    def wrapper(*args, **kwargs):   # *args, **kwargs是接收值;  args = (user, passwd)
        start_time = time.time()
        fun(*args, **kwargs)        # *args, **kwargs是对于元组和字典解包;
        end_time = time.time()
        print "%s runs %ss" %(fun.__name__, end_time-start_time)
    return wrapper   # 返回wrapper

@Timer      # login=Timer(login)   ====> login=wrapper
def login(name, passwd):
    if name=='root' and passwd == 'redhat':
        print "login ok"
    else:
        print "login fail"

login('root', 'westos')   # wrapper('root', 'westos')

装饰器_原有属性保留

# 想要被装饰的函数保留原有属性, 必须对装饰器;里面嵌套的函数加@functools.wrap(f)
import time
import functools

def Timer(f): # f=add
    # 为什么装饰器中嵌套函数? 为了不改变原有函数的调用方式;
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        """\twrapper\t"""
        start_time = time.time()
        tmp = f(*args, **kwargs)   # add(*args, **kwargs)
        end_time = time.time()
        print end_time-start_time
        return tmp
    return wrapper


@Timer
def add(*args):
    return sum(args)

print add(1,2,3,4,5,56)


@Timer   #login = Timer(login)
def login():
    """\tlogin\t"""
    print "login......"

login()
# 默认情况下, 装饰的函数, 名称和帮助文档是wrapper的;
# 如何保留原有函数的所有属性? 对包装的函数加一个装饰器 @functools.wraps(f);
print login.__name__
print login.__doc__



#
# def fun():
#     """ fun: 打印信息"""
#     print "fun....."
# # 打印函数名;
# print fun.__name__
# # 打印函数的帮助文档;
# print fun.__doc__

获取函数参数

# is_admin:判断调用函数的用户是否为管理员admin;
#       如果是admin, 执行函数;
#       如果不是admin,则报错;
import inspect


def is_admin(f):
    def wrapper(*args, **kwargs):
        # inspect.getcallargs将串的参数封装为一个字典,
        # 字典的key值为形式参数,value值为真正传的值;
        fun_args = inspect.getcallargs(f, *args, **kwargs)
        print fun_args
        # fun_args = {'username': 'admin', 'money': 100}
        if fun_args.get('username') != 'admin':
        # if kwargs.get('username') != 'admin':
            return "不是admin用户"
        return f(*args, **kwargs)

    return wrapper


@is_admin  # transfer = is_admin(transfer)
def transfer(username, money):
    print "%s transfer %s......." % (username, money)

transfer('admin', 100)

示例

编写#装饰器required_ints, 条件如下:
1). 确保函数接收到的每一个参数都是整数; # 如何判断变量的类型? type(s), isinstance(s,str)
2). 如果参数不是整形数, 抛出异常raise TypeError(“参数必须为整形”)
“”“

import functools


def required_ints(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        # args:元组; 判断元组里面的每一个元素是否为整数;
        # kwargs:字典, 判断字典的每一个value值是否为整形数;
        for arg in args + tuple(kwargs.values()):
            if not isinstance(arg, int):
                raise TypeError("参数必须为整形")   # 抛出异常
        # 当判断完所有的参数, 没有一个不是整形,则执行被装饰的函数;
        else:
            return f(*args, **kwargs)

    return wrapper

@required_ints
def add(*args):
    return sum(args)

print add(1,2,3,67,89, 1.0)

装饰器包含参数

import functools

# 如果要给装饰器传参数, 如何操作?
def required_type(*args_type):
    def required(f):
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
            # args:元组; 判断元组里面的每一个元素是否为整数;
            # kwargs:字典, 判断字典的每一个value值是否为整形数;
            for arg in args + tuple(kwargs.values()):
                if not isinstance(arg, args_type):
                    raise TypeError("参数必须为%s" %(args_type))    # 抛出异常
            # 当判断完所有的参数, 没有一个不是整形,则执行被装饰的函数;
            else:
                return f(*args, **kwargs)

        return wrapper
    return required

@required_type(int, float)
def add(*args):
    return sum(args)


@required_type(str)
def data(*args):
    return [i.title() for i in args]

装饰器总结

1. 编写装饰器的框架:

import functools

def 装饰器名称(f):
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        pass
    return wrapper

2. pass里面需要的几个框架: 装饰器里面内容

2-1.

     执行函数之前做的操作
            res = f(*args, **kwargs)
            执行函数之前做的操作
            return res

2-2.

    if 满足条件:
                执行函数
                res = f(*args, **kwargs)
                return res
            else:
                print "报错"

3. 装饰器的装饰器

@装饰器名称      # 函数名 = 装饰器名称(函数名)
def 函数名():
    pass


函数名()        # 实质在调用wrapper函数

4.

@functools.wrap(f)
inspect.getcallargs()           inspect.getcallargs将串的参数封装为一个字典

四:模块

1.什么是模块

在 Python 中,一个.py文件就称之为一个模块(Module)。

  • •大大提高了代码的可维护性;
  • •编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用;
import sys
def test():
args = sys.argv
if len(args) == 1:
print 'Hello world'
elif len(args) == 2:
print 'Hello %s!' %args[1]
else:
print 'Too many arguments!'
if __name__ == '__main__':
test()

调用模块时用import xxx

2.模块的分类

内置模块

from future import print_function

from future import division
import random
import time
import os
from collections import Iterable

自定义模块

import add

直接调用模块里面的变量名;

print add.a

直接调用模块里面的函数;

第一个add: 模块名

第二个add: 函数名

print add.add(1,2,3,4,5)

第三方模块: 别人写的优秀的python代码,上传到pypi;

eg: itchat, 使用时, 必须pip install itchat

import itchat

第三方模块安装:

1). pip install 第三方模块名称

2). pycharm里面设置中可以安装;

python模块的默认搜索路径的查找方式:

import sys

print sys.path

添加默认的搜索路径到列表最后;

sys.path.append(‘/home/kiosk’)
print sys.path

添加默认的搜索路径到列表最前面;

sys.path.insert(0, ‘/home/kiosk/Desktop’)
print sys.path

3.导入模块

  1. 建议优先使用第一种方式;
  2. import 模块名
import add
print add.a
print add.add(1,2,3,4)

2.

from 模块名 import 变量名
from 模块名 import 函数名
from add import a
from add import add
print a
print add(1,2,3,4)
  1. 不建议使用, 会导致命名空间的污染;
from add import *
b = 10
print a
print add(1,2,3)
print b

导入模块的过程就是加载模块吗内容并执行的过程;

import add

如果不同的人编写的模块名相同怎么办?

为了避免模块名冲突,Python 又引入了按目录来组织模块的方法,称为包(Package)包

创建包的步骤:

创建一目录为包名;
在该文件夹下创建init.py文件存放包的信息,该文件
可以为空;
根据需要存放脚本文件,已编译的扩展及子包;
可以用import,import as,from import等语句导入模块
和包;

五:文件操作

文件读写

• Python 内置了读写文件的函数,用法和 C 是兼容的。 • 操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操
作系统打开一个文件对象(又称文件描述符),然后,通过操作系统提供的接 口从这个文件对象操作;

1)打开文件

f = open(‘/root/hello’)
print f #f是文件对象

如果文件不存在, open() 函数就会抛出一个 IOError 的错误,并且

给出错误码和详细的信息告诉你文件不存在;

2)阅读模式

f.read()

如果文件打开成功,接下来,调用 read() 方法可以一次读取文件的

全部内容;

3)关闭文件

f.close()

文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源。

读取文件的一行内容, 以字符串返回;

print f.readline()
print f.readline()
print f.readline()

读取文件每一行内容, 以列表方式返回;

print f.readlines()

print f.write(‘hello’)

文件对象是可迭代的, 如果只是几百兆的文件直接read方法读取;

如果xG文件, 建议使用for循环遍历, 底层是迭代器, 节省内存;

# for i in f:
#     print i.rstrip()

• 二进制文件
要读取二进制文件,比如图片、视频等等,用 ‘rb’ 模式打开文件即可

f = open(‘/root/test.jpg’, ‘rb’)
f.read()
‘\xff\xd8\xff\xe1\x00\x18Exif\x00\x00…’ # 十六进制表示的字节

open函数的模式

r 以读的方式打开,定位到文件开头 , 默认的 mode
r+ 以读写的方式打开,定位文件开头 , 可以写入内容到文件
w 以写的方式打开,打开文件的时候会清空文件的内容,并且不能读
w+ 以读写的方式打开,定位到文件头,并且打开文件的时候也会清空文件的内容
a 以写的方式打开,定位到文件的末尾,是一个追加的操作 , 但并不允许读
a+ 以读写的方式打开,定位到文件的末尾,追加的方式。
在使用以上 mode 打开文件的时候,如果增加了b 模式,表示以二进制方式打开

文件的其它操作

  • f.flush()函数,将缓冲区的内容写入到硬盘中
  • f.seek(offset[,whence]),offset 表示移动多少字节, whence 为 1 的时候表
    示相对于当前位置移动的;当 2 的时候从文件的末尾往后移动,但不一定所有 的平台都支持;默认为 0 表示从文件开头往后移动
  • f.tell()函数,返回当前文件指针的偏移量:文件的其它操作
  • fileno() 函数,返回当前的文件描述符,一个数字
  • isatty() 函数,当前打开的文件是否是一个终端设备
  • closed 属性,当前文件是否关闭 ,|True,False, f.closed
  • file 对象是一个迭代器:
  • next() 方法 , 一行一行的读 , 每次读取一行

with语法

一般情况打开一个文件,经过操作之后,都要显式的执行xx.close() 将文件关
闭 .with 用于需要打开、关闭成对的操作,可以自动关闭打开对象 .
with expression as obj:# 将打开的对象赋值给 obj
expression
obj 的作用域只在 with 语句中

with语句会在代码块执行结束自动关闭文件对象;

with open('/etc/passwd') as f:
    f.read()

    print "in with:",  f.closed

print "out with:", f.closed

猜你喜欢

转载自blog.csdn.net/liuyong1_/article/details/79881366