Python-在函数外部创建的对象是否可以在内部完全访问?

时间:2018-07-09 11:05:23

标签: python

我在理解变量范围时遇到一些问题。对于普通变量,我理解这一点,但是如果我定义一个对象,那么事情会使我感到困惑。请看下面的代码:

class test():
    pass

text="hi there"
num=1

p=test()
p.var="good bye"
p.arr = []
p.num = 5

def output_before():
    print "before change: object text " ,p.var
    print "before change: object number ", p.num
    print "before change: basic text " ,text
    print "before change: basic num ", num

def output_after():
    print "after change: object text " ,p.var
    print "after change: object number ", p.num
    print "after change: basic text " ,text
    print "after change: basic num ", num



def change():
    text = "whats up"
    num=5
    p.num=10
    p.var="good night"
    p.arr.append ("sleep well")


output_before()
change()
output_after()

print p.arr

for i in range(5):
    change()
print p.arr

哪个给我这个输出:

before change: object text  good bye
before change: object number  5
before change: basic text  hi there
before change: basic num  1
after change: object text  good night
after change: object number  10
after change: basic text  hi there
after change: basic num  1
['sleep well']
['sleep well', 'sleep well', 'sleep well', 'sleep well', 'sleep well', 'sleep well']

默认情况下,来自类测试的对象似乎是全局的。是这样吗?

谢谢, 安迪

4 个答案:

答案 0 :(得分:1)

简短答案: 在函数外部或全局范围内声明的任何变量(意味着该变量不在任何范围内,例如类,方法,条件语句等)都称为全局变量。

长期调试的答案

实际上,您的对象被声明为全局对象。

logging.get_logger()

在上面的代码段中,<uses-feature android:name="android.hardware.camera" />对象在方法范围之外声明,从而使所有对象都可以访问它。方法也声明在p=test() p.var="good bye" p.arr = [] p.num = 5 类范围之外。实际上,没有什么阻止他们访问它。如果您想调试以便更好地理解,请将p对象移至其中一种方法中,例如:

test

然后重新运行您的代码,它将产生:

p

然后出现以下错误:

  

回溯(最近一次通话最后一次):文件“ t.py”,第35行,在       change()文件“ t.py”,第29行,处于更改中       p.num = 10 NameError:未定义全局名称'p'

但是,如果要从模块或方法内部访问对象,则可以使用关键字def output_before(): p=test() p.var="good bye" p.arr = [] p.num = 5 print "before change: object text " ,p.var print "before change: object number ", p.num print "before change: basic text " ,text print "before change: basic num ", num ,并按照文档建议:

  

这是因为当您对作用域中的变量进行赋值时,该变量将成为该作用域的局部变量,并在外部作用域中隐藏任何类似命名的变量。由于foo中的最后一条语句为x分配了一个新值,因此编译器将其识别为局部变量。因此,当较早的print x尝试打印未初始化的局部变量并导致错误时,您可以通过声明全局变量来访问外部作用域变量

Read More

答案 1 :(得分:1)

这是闭包的工作方式。定义函数output_after时,它将在此函数的变量范围内使用变量text="hi there"。而且只能在函数内部更改此变量。

但是,如果要使用全局变量,则需要使用global构造:

def output_after():
   global text, num
   print "after change: object text " ,p.var
   print "after change: object number ", p.num
   print "after change: basic text " ,text
   print "after change: basic num ", num

众所周知,Python中的所有变量名称都被称为对值的引用。因此,当我们定义函数output_after时,我们将复制所有当前上下文(对text,num,p对象的引用)。您可以使用id函数检查对对象的引用。 当您更改文本和num的值时,引用将被更改,但对于对象p将会相同。

请检查以下内容:

def change():
    print(id(text))
    text = "whats up"
    print(id(text))
    print(id(num))
    num=5
    print(id(text))
    print(id(p))
    p.num=10
    print(id(p))

您可以看到引用的数字和文本已更改。

答案 2 :(得分:0)

这与Python中的其他任何变量一样。该函数首先在本地名称空间中检查变量。由于未在函数内部定义对象,因此它将检查外部命名空间,即您实际定义其的全局命名空间。

对于变量num / text,您正在num = 5中使用change()。这将创建一个名为num的局部变量,并为其分配5。它不会更改全局变量。如果要全局更改,则可以使用global关键字:

def change():
    global text,num
    num = 5  #Global num is changed

答案 3 :(得分:0)

只需将您的对象p视为其他任何原始类型。两者的规则相同。

由于在函数之外声明了对象,因此该对象的范围不受限制。另一方面,如果在函数中声明它,则您将无法访问这些函数之外的对象,因为此对象的范围现在仅限于此函数。 (当然,您可以明确地将此设置为全局。但是,此问题目前可能超出范围)

class test():
    pass

text="hi there"
num=1

def output_before():
    #p is now local
    p=test()
    p.var="good bye"
    p.arr = []
    p.num = 5
    print("before change: object text " ,p.var)
    print("before change: object number ", p.num)
    print("before change: basic text " ,text)
    print("before change: basic num ", num)
    print(b)

def output_after():
    print("after change: object text " ,p.var) #should fail because p is not known
    print("after change: object number ", p.num)
    print("after change: basic text " ,text)
    print("after change: basic num ", num)



def change():
    text = "whats up"
    num=5
    p.num=10
    p.var="good night"
    p.arr.append ("sleep well")


output_before()
change()
output_after()

上面的代码将失败,因为在change()和output_after()中p是未知的。