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

Python-在函数外部创建的对象在函数内部完全可访问?,python,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

我在理解变量范围时遇到一些问题。对于普通变量,我理解它,但如果我定义了一个对象,我会感到困惑。请查看此代码:

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']
默认情况下,类测试中的对象似乎是全局的。是这样吗

谢谢,
安迪

简短回答: 在函数外部或全局范围内声明的任何变量(表示该变量不在任何类型的范围内,例如类、方法、条件语句等)称为全局变量

长时间调试的答案

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

p=test()
p.var="good bye"
p.arr = []
p.num = 5
在上面的代码片段中,
p
对象声明在方法的范围之外,这允许所有方法都访问它。方法也在
测试
类范围之外声明。实际上,没有任何东西阻止他们访问它。如果希望调试更好地理解,请将
p
对象移动到其中一个方法中,如:

然后重新运行代码,这将产生:

before change: object text  good bye
before change: object number  5
before change: basic text  hi there
before change: basic num  1
然后出现以下错误:

回溯(最近一次调用last):文件“t.py”,第35行,在 change()文件“t.py”,第29行,在change中 p、 num=10 name错误:未定义全局名称“p”

但是,如果您想从模块或方法内部访问对象,可以使用关键字
global
,如文档所建议的:

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


闭包就是这样工作的。当您在之后定义函数
output\u时,它会将变量
text=“hi there”
置于该函数的变量范围内。这个变量只能在函数内部更改

但如果您想拥有全局变量,则需要使用
global
construction:

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\u时,我们复制所有当前上下文(对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))

您可以看到num和text的引用已更改。

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

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

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

只需将对象p想象为任何其他基本类型。两者的规则是一样的

由于您在函数之外声明了对象,因此此对象的范围不受限制。另一方面,如果在一个函数上声明它,则无法访问这些函数之外的对象,因为此对象的作用域现在仅限于此函数。(当然,你可以明确地将其全球化。但这可能超出了这个问题目前的范围)


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

因此对象p以及变量text和num都在外部声明。为什么访问my object p时没有全局关键字,但变量必须有全局关键字?您的变量也可以访问。通过在任何方法中打印
文本
num
变量进行调试。感谢您的帮助。我的目标是理解这里的范围。我在外部声明了对象p和变量text和num。为什么访问我的对象p时没有全局关键字,但变量必须有全局关键字?因为p是可变对象,文本和num是不可变的。@xsanders我添加了更多说明。@OleksandrYarushevskyi为什么文本和num是不可变的?@RohithS98 CPython的实现
def change():
    global text,num
    num = 5  #Global num is changed
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()