我一直试图在Python中找到RAII。资源分配即初始化是C
++中的一种模式,通过该模式可以在创建对象时对其进行初始化。如果失败,则抛出异常。这样,程序员便知道该对象永远不会处于半构建状态。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”语句,
但是它要求我显式地放入__enter__
和__exit__
函数,并且通常看起来更倾向于清理文件和互斥锁之类的资源,而与退出向量无关。它没有作用域。还是我错过了什么?
我已经搜索了“ Python RAII”和“
Python范围”,但找不到任何直接且权威地解决该问题的方法。我已经查看了所有PEP。该概念似乎在Python中未得到解决。
我是一个坏人,因为我想在Python中使用作用域变量吗?难道这是非Pythonic的吗?
我不傻吗?
也许我正在尝试摆脱语言动态方面的好处。有时想要扩大范围是否自私?
我是否懒于想要编译器/解释器捕获我的疏忽变量重用错误?好吧,是的,我当然很懒,但是我会以一种不好的方式懒惰吗?
tl; dr RAII是不可能的,通常将其与作用域混合使用,而当您错过这些额外的作用域时,则可能是在编写错误的代码。
也许我没有收到您的问题,或者您没有获得关于Python的一些非常重要的知识……首先,在垃圾回收语言中,与范围相关的确定性对象破坏是 不可能的
。Python中的变量仅是引用。您不希望在指向该malloc
内存free
的指针超出范围时立即对其进行存储,对吗?在 某些
情况下,如果您碰巧使用引用计数,则是实际的例外-但没有一种语言足以使确切的实现陷入僵局。
而且, 即使 您像CPython中那样具有引用计数,它也是实现细节。通常,包括在Python中有各种 不
使用引用计数的实现在内,您应该编写代码,就像每个对象都在周围徘徊,直到内存用尽。
至于在其余函数调用中存在的名称:您 可以
通过该del
语句从当前或全局范围中删除名称。但是,这与手动内存管理无关。它只是删除参考。这可能会或可能不会触发被引用对象进行GC,这不是练习的重点。
您是正确的,with
与确定范围无关,仅与确定性清理无关(因此,它最终与RAII重叠,但与手段无关)。
也许我正在尝试摆脱语言动态方面的好处。有时想要扩大范围是否自私?
不能。体面的词法作用域是独立于动态/静态的优点。诚然,Python(2-3个已基本解决)在这方面有弱点,尽管它们更多地存在于闭包领域。
但是要解释“为什么”:Python 必须
在开始新作用域的位置上保持保守,因为无需声明,否则,对名称的赋值会使它成为最内部/当前作用域的局部名称。因此,例如,如果for循环具有自己的作用域,则无法轻松地在循环外部修改变量。
我是否懒于想要编译器/解释器捕获我的疏忽变量重用错误?好吧,是的,我当然很懒,但是我会以一种不好的方式懒惰吗?
同样,我认为偶然重用名称(以引入错误或陷阱的方式)很少而且反而很少。
编辑:要尽可能清楚地再次声明:
with
语句进行。是的,它没有引入新的作用域(请参阅下文),因为这不是它的用途。它不会删除托管对象绑定的名称也不会删除-尽管如此,清理仍在进行,剩下的就是“别碰我,我不可用”对象(例如,关闭的文件流)。问题内容: 当前正在从事一个项目,在该项目中,当我们不从被破坏的示波器中清除广播订阅时,会发现大量内存泄漏。以下代码已解决此问题: 这种做法也应该用于手表吗? 下面的代码示例: 问题答案: 不,您不需要删除,因为一旦销毁范围,它们将被有效删除。 从角的源代码(v1.2.21),的方法: 因此,将清空该数组(并且将范围从范围层次结构中删除)。 无论如何,从阵列中删除都是注销功能所要做的: 因此,取消
问题内容: 我一直在考虑向Java语言架构师发送建议。 在同步块中 在线程离开同步块之后,它不能再调用lock.notifyAll()/ lock.notify()而不会发生异常。 忘记通知其他线程监视器持有者可能永远使他们(其他线程)等待(除非他们在其wait方法中放置了一些超时)。 我无法想象这种情况(在没有显式通知的情况下在同步块的末尾插入隐式通知)是不理想的。 相同的方法可以应用于同步方法
问题内容: 如何更改phpmyadmin自动注销时间? 它会在1440秒后自动注销,这对我来说非常低。如何更改选项或完全删除登录请求? 问题答案: 创建或编辑文件并在其中设置此变量值: 整数以秒为单位。500000秒是5.7天。然后重新启动apache。
问题内容: 自从我使用Java以来已经有5年了,那时,每当您想分配需要清理的对象(例如套接字,DB句柄)时,都必须记住添加一个块并在其中调用cleanup方法。那里。 相比之下,在C++(或确定对象生存期的其他语言,例如Perl)中,类实现程序将定义一个析构函数,该函数在该类的对象超出范围时执行清除。这种方法的优点是对象的用户不会忘记清理它- 即使抛出异常,析构函数也会被自动调用。这种方法用R
问题内容: 我在游戏中使用了摇摆计时器,但是当游戏运行时,它似乎有平稳运行的时刻和减速的时刻。 为什么时间在波动? 我该如何解决? 这是我的代码示例。在我的实际程序中,我正在绘制图像,而不仅仅是矩形。还有很多碰撞检测和其他小的计算正在发生。 另外,这是游戏的Jar文件的链接,因此您可以运行它,(满是)明白我的意思。http://dl.dropbox.com/u/8724803/Get%20To%2
由于我注意到一旦用户使用电子邮件和密码登录,在重新打开应用程序时,会话不会过期,也不需要进行新的身份验证,我希望避免这种情况。