V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
northisland
V2EX  ›  Python

问 2 个关于 Python 的简单问题。困扰我很久

  •  1
     
  •   northisland · 2017-10-17 15:32:11 +08:00 · 4732 次点击
    这是一个创建于 2592 天前的主题,其中的信息可能已经有所发展或是发生改变。

    操作 json 文件相关的。

    我要读文件进来,

    第一种写法

    json_obj=None
    with open(path) as f:
      json_obj=json.loads(f.read())
    

    第二种写法

    json_obj=json.loads(open(path).read())
    

    问题 1:

    第一种写法里,第一行能否删掉?

    换言之,就是 with 里的变量 json_obj 能否自动 with 在这个过程后存在?

    问题 2:

    第二种写法,是否正确?临时变量 open(path)在结束时,是否释放了文件句柄?

    提前谢谢各位帮助答疑解惑

    25 条回复    2017-10-26 17:58:41 +08:00
    WhoAmI233
        1
    WhoAmI233  
       2017-10-17 15:40:17 +08:00   ❤️ 1
    第一种写法第一行不能删,第二种写法正确的,open(path)在结束时肯定释放了。
    whx20202
        2
    whx20202  
       2017-10-17 15:46:56 +08:00
    第一种为什么不能删啊
    WhoAmI233
        3
    WhoAmI233  
       2017-10-17 15:48:10 +08:00
    @whx20202 删了,那你定义这个变量有何作用啊?思考一下变量的作用域
    mgna17
        4
    mgna17  
       2017-10-17 15:49:09 +08:00
    第一种:第一行可以删,with 中用到的变量在退出 with 之后可以继续使用

    第二种:python3 的文件对象有个 __del__ 函数,应该会自动释放的。python2 没有这个 __del__ 函数,不清楚
    XIVN1987
        5
    XIVN1987  
       2017-10-17 15:51:37 +08:00
    json_obj=None 可以删掉

    第二个问题文件应该不会被自动 close(),我试了在 ipython 命令行中执行 open('test.txt'),然后去删除 test.txt ,,系统报错说 test.txt 文件已经被打开了,,不让删除,,所以应该在你的软件执行完退出后文件句柄才能被释放
    ChristopherWu
        6
    ChristopherWu  
       2017-10-17 15:54:07 +08:00
    其实,第一行可以删。
    不过加了 json_obj=None, 是保证代码即便出现错误时,json_obj 也会有初始值。
    Yinz
        7
    Yinz  
       2017-10-17 15:54:28 +08:00   ❤️ 1
    第一种,可以删掉第一行。
    第二种,以前写爬虫的时候试过这么写然后跑光了句柄,程序卡死,但是不记得当时是用的 PY2 还是 PY3 了
    XIVN1987
        8
    XIVN1987  
       2017-10-17 15:57:05 +08:00
    更正下,,刚才说错了

    如果是在函数内打开的文件,比如
    def test(): open('test.txt')

    在命令行中执行 test()

    之后可以立即在文件浏览器中删掉 test.txt 这个文件,,

    说明函数退出后文件句柄就被释放了
    justou
        9
    justou  
       2017-10-17 15:57:24 +08:00
    with 是上下文管理器语法, 它保证它经手的资源在退出 with 块后被正确释放, 即使发生了异常.

    如果没有发生异常, 第一种情形可以不用 json_obj=None, 退出 with 块后 json_obj 继续存在;

    如果发生了异常, 第一种情形 json_obj 未定义, 但是文件会被正确关闭. 但是第二种情形文件不会被正确关闭(json_obj 同样未定义), 直到程序结束.
    BBCCBB
        10
    BBCCBB  
       2017-10-17 16:00:14 +08:00
    第一行那个可以删, Python 作用域和其他的不太同, 和 js 的很像,

    我也不知道第二种对不对, 也不想尝试... 推荐使用 with, 显示释放
    tamlok
        11
    tamlok  
       2017-10-17 16:04:42 +08:00 via Android   ❤️ 1
    标题写法应该是“两”,不是“ 2 ”😁
    ChristopherWu
        12
    ChristopherWu  
       2017-10-17 16:06:39 +08:00   ❤️ 1
    第二种严格来说可以不关掉。
    可以自己测试一下:
    ```
    import json
    # json_obj=None
    json_obj=json.loads(open("/Users/yonghaohu/a").read())
    open("/Users/yonghaohu/te/a")
    while(1):
    pass
    ```

    运行程序后,lsof -p 该程序, 查看打开的文件, 是没有打开任何 a 文件的。

    如果你在 while 里, 不断调用 open,lsof -p 则会看到该文件。

    Python 85861 yonghaohu 3r REG 1,4 7 108089581 /Users/yonghaohu/te/a
    ChristopherWu
        13
    ChristopherWu  
       2017-10-17 16:18:49 +08:00
    接上,gc 删掉打开的文件对象时, 会自动删掉掉句柄。但是这个过程是不可控的,最好还是自己手动 close
    SuperMild
        14
    SuperMild  
       2017-10-17 16:21:02 +08:00   ❤️ 1
    不懂 python,但是,不是自己实际测试一下就能确定吗?
    xlui
        15
    xlui  
       2017-10-17 16:27:40 +08:00 via iPhone   ❤️ 1
    第一行可以删,with 块跟函数和模块不同,没有定义新作用域。
    第二个临时变量在语句结束时丢失引用被垃圾回收,CPython 和 IPython 会刷新并且关闭文件。而 PyPy 和 JPython 采用不同的垃圾回收机制所以会有不同的情况出现。
    虽然 CPython/IPython 会在文件对象丢失引用时刷新并关闭,还是推荐使用 with 语句。
    这两个问题我记得 流畅的 Python ( fluent python ) 上都有简单的提到,这本书真的太好了。
    enenaaa
        16
    enenaaa  
       2017-10-17 16:38:23 +08:00
    @justou 第 2 种写法里,如果发生异常。 并不是直到程序结束才释放, 而是直到该异常被处理后才释放。
    刚刚试过。
    dongxiaozhuo
        17
    dongxiaozhuo  
       2017-10-17 16:41:01 +08:00 via iPhone
    py2 的话,第一种情况,第一行可以删除。不过为啥不用 json.load 方法,直接读取文件对象,不是更好?
    strahe
        18
    strahe  
       2017-10-17 17:07:17 +08:00   ❤️ 1
    一楼瞎说, 1, 第一行可以删, 而且建议删,
    第二种不建议这么写, open 以后要主动 close
    stebest
        19
    stebest  
       2017-10-17 17:10:24 +08:00
    同认为第一行可以删,Python 不需要预先定义。
    oroge
        20
    oroge  
       2017-10-17 17:23:00 +08:00 via iPhone
    https://stackoverflow.com/questions/38660609/when-how-does-an-anonymous-file-object-close

    上面说“测试一下不就行了”的人不怕遇到 undefined behavior ?
    linuxchild
        21
    linuxchild  
       2017-10-17 17:31:44 +08:00
    with 就是用来自动释放的 - -。没有 with 咋个释放
    zmj1316
        22
    zmj1316  
       2017-10-17 18:25:08 +08:00 via Android
    GC 的时候会 close 掉的
    honmaple
        23
    honmaple  
       2017-10-18 09:39:57 +08:00
    第一种第一行肯定可以删,假设 with 语句出错了,想要捕捉错误可以用 try...except,json_obj 就可以另外定义到 except 里,如果 with 出错了不捕捉,预先定义好的 json_obj 又有什么用
    siteshen
        24
    siteshen  
       2017-10-19 13:03:55 +08:00
    1. 不知道是否可以删。我的建议是不要删,这样就不用关心 with 的作用域的问题;
    2. open(path).read() 肯定不会自动 close 文件,和 python 哲学 "Explicit is better than implicit" 冲突。

    ps: 可以使用函数 `json.load` 少敲几个字符。
    wangdaqiao
        25
    wangdaqiao  
       2017-10-26 17:58:41 +08:00   ❤️ 1
    第一种,可以简化一点点

    with open(path) as f:
    json_obj=json.load(f)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3410 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 10:49 · PVG 18:49 · LAX 02:49 · JFK 05:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.