python中变量作用域的推荐方法

时间:2018-07-16 09:50:01

标签: python scope

在C和变体中,当您遇到类似这样的情况时:

{
  tmp1 <- 5
  tmp2 <- 2
  print(tmp1 + tmp2)
}

将打印出7,但是一旦范围tmp1结束,tmp2}变量将从堆栈中删除。有时我希望在python中使用类似的功能,这样我就不必在某个时间点后清理(许多)临时变量。

在R中,您可以使用local({insert piece of code})来实现此目的。

我们如何在python中获得相似但可读的行为?

5 个答案:

答案 0 :(得分:2)

没有任何特殊的语法,但是您可以通过手动删除变量来实现类似的目的:

tmp1 = 5
tmp2 = 2

print(tmp1 + tmp2)

del tmp1
del tmp2

如果您不喜欢这种语法,则可以使用:

def local(f): 
  f()

@local
def block(): 
  tmp1 = 5
  tmp2 = 2
  print(tmp1 + tmp2)

基本上与:

def block(): 
   ...
local(block)

https://hackernoon.com/decorators-in-python-8fd0dce93c08

但是,这一点确实很简单。

答案 1 :(得分:1)

实际上,您可以实现一些棘手的模拟操作。

import inspect
from contextlib import contextmanager


@contextmanager
def Local():
    enter_locals = set(inspect.currentframe().f_back.f_back.f_locals.keys())
    yield
    exit_locals = set(inspect.currentframe().f_back.f_back.f_locals.keys())
    substract = exit_locals - enter_locals
    for variable in substract:
        del inspect.currentframe().f_back.f_back.f_locals[variable]

with Local():
    a = 1
    b = 2
    print(a + b)

print(a + b)

# 3
# ...
# ----> 6 print(a + b)
#
# NameError: name 'a' is not defined

但实际上不建议这样做。为什么要用Python模拟其他语言? Python是Python,没有块范围,也没有块范围。

答案 2 :(得分:1)

最终确定一个工程解决方案,您仍然可以故意泄漏选定的变量。

from scoping import scoping
a = 2
with scoping():
    assert(2 == a)
    a = 3
    b = 4
    scoping.keep('b')
    assert(3 == a)
assert(2 == a)
assert(4 == b)

https://github.com/l74d/scoping

答案 3 :(得分:0)

请参见https://stackoverflow.com/a/292502/51685,以了解Python可变作用域规则的细致之处。

存在范围的变量将自动清除,但是您也可以使用del关键字删除对它们的引用。

very_large_data = 'x' * 1_000_000_000  # a gigabyte of x!
# do things...
del very_large_data  # that gigabyte will be garbage-collected soon after

如果您担心使调试等操作变得容易的“范围污染”,只需将代码重构为较小的函数和/或类(以便可以将共享状态保存在self.中)

答案 4 :(得分:0)

来自What's the scope of a variable initialized in an if statement?

  

Python变量的作用域是分配给它们的最里面的函数,类或模块。控制块(如if和while块)不计在内,因此在if内分配的变量的作用域仍然是函数,类或模块。

因此,如果您想知道这为何起作用:

for i in range(0, 3):
    a = i
print(a)

>> 2

,为什么a可以在for循环之外访问,那么答案是python而不是c++R。删除它们将是一种非Python的方法,但是您可以通过查看其他答案来明确地这样做