gpt4 book ai didi

python - Python 中的 RAII - 离开作用域时自动销毁

转载 作者:IT老高 更新时间:2023-10-28 22:07:10 24 4
gpt4 key购买 nike

我一直在寻找 RAII在 Python 中。
资源分配是初始化是 C++ 中的一种模式,由此
对象在创建时被初始化。如果失败,则抛出
一个异常(exception)。这样,程序员就知道
对象永远不会处于半构建状态。 Python
可以做这么多。

但 RAII 也适用于 C++ 的范围规则
以确保对象的及时销毁。只要变量
从堆栈中弹出它被销毁。这可能发生在 Python 中,但仅限于
如果没有外部或循环引用。

更重要的是,一个对象的名字仍然存在,直到它被调用
在导出(有时更长)。模块级别的变量将
坚持模块的生命周期。

如果我做这样的事情,我想得到一个错误:

for x in some_list:
...

... 100 lines later ...

for i in x:
# Oops! Forgot to define x first, but... where's my error?
...

我可以在使用后手动删除名称,
但这会很丑陋,需要我努力。

在这种情况下,我希望它按我的意思去做:
for x in some_list:
surface = x.getSurface()
new_points = []
for x,y,z in surface.points:
... # Do something with the points
new_points.append( (x,y,z) )
surface.points = new_points
x.setSurface(surface)

Python 做了一些范围界定,但不是在缩进级别,只是在
功能层面。要求我创建一个新函数似乎很愚蠢
只是为了确定变量的范围,以便我可以重用名称。

Python 2.5 具有 "with" statement
但这要求我明确输入 __enter____exit__职能
并且通常似乎更倾向于清理文件等资源
和互斥锁与退出向量无关。它对范围界定没有帮助。
或者我错过了什么?

我搜索了“Python RAII”和“Python 范围”,但找不到任何
直接和权威地解决了这个问题。
我已经查看了所有 PEP。这个概念似乎没有得到解决
在 Python 中。

我是一个坏人,因为我想在 Python 中使用范围变量吗?
是不是太不 Pythonic 了?

我不是在摸索吗?

也许我试图剥夺语言动态方面的好处。
有时想要强制执行范围是自私的吗?

我是否因为想要编译器/解释器而懒惰
捕获我疏忽的变量重用错误?嗯,是的,我当然很懒,
但我是不是很懒惰?

最佳答案

tl;博士 RAII 是不可能的,您通常将其与范围界定混为一谈,当您错过那些额外的范围时,您可能正在编写错误的代码。
也许我没有明白你的问题,或者你没有得到关于 Python 的一些非常重要的东西......首先,在垃圾收集语言中,与作用域相关的确定性对象销毁是不可能的。 Python 中的变量只是引用。你不会想要一个 malloc 'd 内存块是 free 'd 一旦指向它的指针超出范围,你会吗?如果您碰巧使用引用计数,则在某些情况下会出现实际异常——但没有一种语言足够疯狂,可以一成不变地设置确切的实现。
即使你有引用计数,就像在 CPython 中一样,它也是一个实现细节。通常,包括在具有各种不使用引用计数的实现的 Python 中,您应该编写代码,就好像每个对象都卡在内存用完之前一样。
对于函数调用的其余部分存在的名称:您可以通过 del 从当前或全局范围中删除名称。陈述。但是,这与手动内存管理无关。它只是删除了引用。这可能会也可能不会触发引用的对象进行 GC,这不是练习的重点。

  • 如果您的代码足够长而导致名称冲突,您应该编写更小的函数。并使用更具描述性、不太可能发生冲突的名称。嵌套循环覆盖输出循环的迭代变量也是如此:我还没有遇到这个问题,所以也许你的名字不够描述或者你应该把这些循环分开?

  • 你说得对, with与范围界定无关,仅与确定性清理有关(因此它最终与 RAII 重叠,但不与方法重叠)。

    Perhaps I'm trying to take away the benefits of the dynamic aspects of the language. Is it selfish to sometimes want scope enforced?


    不。体面的词汇范围是一个独立于动态/静态的优点。诚然,Python(2 - 3 几乎解决了这个问题)在这方面有弱点,尽管它们更多地处于闭包领域。
    但是要解释“为什么”:Python 必须对它从何处开始一个新的作用域持保守态度,因为如果没有声明另有说明,对名称的赋值使其成为最内部/当前作用域的局部。所以例如如果 for 循环有它自己的作用域,你就不能轻易地修改循环外的变量。

    Am I lazy for wanting the compiler/interpreter to catch my negligent variable reuse mistakes? Well, yes, of course I'm lazy, but am I lazy in a bad way?


    再一次,我认为意外重用一个名字(以引入错误或陷阱的方式)是罕见的,无论如何都是小事。
    编辑:再次尽可能清楚地说明这一点:
  • 不能在使用 GC 的语言中进行基于堆栈的清理。 根据定义,这是不可能的:变量是对堆上对象的许多潜在引用之一,它们既不知道也不关心变量何时超出范围,并且所有内存管理都掌握在 GC 手中,GC 会在它运行时运行喜欢,而不是弹出堆栈帧时。资源清理的解决方式不同,见下文。
  • 确定性清理通过 with 发生陈述。 是的,它没有引入新的范围(见下文),因为这不是它的用途。托管对象绑定(bind)的名称没有被删除无关紧要 - 尽管如此,清理还是发生了,剩下的是“不要碰我,我无法使用”对象(例如,关闭的文件流)。
  • Python 对每个函数、类和模块都有一个作用域。时期。 无论您喜欢与否,这就是语言的工作方式。如果您想要/“需要”更细粒度的范围,请将代码分解为更细粒度的函数。您可能希望进行更细粒度的范围界定,但没有 - 由于本答案前面指出的原因(“编辑:”上方的三段),这是有原因的。不管喜欢与否,但这就是语言的工作方式。
  • 关于python - Python 中的 RAII - 离开作用域时自动销毁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5071121/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com