Python: Regarding variable scope. Why don't I

2019-06-17 08:13发布

Consider the following code, why don't I need to pass x to Y?

class X:    
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

class Y:        
    def A(self):
        print(x.a,x.b,x.c)

x = X()
y = Y()
y.A()

Thank you to the top answers, they really helped me see what was the problem, namely misunderstanding regarding variable scope. I wish I could choose both as correct answer as they are enlightening in their own way.

5条回答
来,给爷笑一个
2楼-- · 2019-06-17 08:25

It takes it from current scope. If you remove x = X() it will throw a error.

You can use variables from current scope and variable from all parent scopes inside a function.

def A():
   a = 1

   def B():
       b = 2

       def C():
          c= 3
          print(a,b,c)

For details on how scope is defined check python language reference on Naming and Binding

Also, since you are not changing x it works just fine. But if you would've try to change variable from parent scope it would throw error:

g= 0
def A():
   a = 1
   g = 2 #throws error
   def B():
       b = 2

       def C():
          c= 3
          print(a,b,c,d)

In such case you need to use global keyword:

g= 0
def A():
   a = 1

   global g
   g = 2 #does not throw error

   print(a,g)


A()
查看更多
等我变得足够好
3楼-- · 2019-06-17 08:35

From The Python Tutorial:

Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:

  • the innermost scope, which is searched first, contains the local names
  • the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also
  • non-global names the next-to-last scope contains the current module’s
  • global names the outermost scope (searched last) is the namespace containing built-in names

In your case x=X() puts x into the global namespace. Since you did not define x locally in Y.A (innermost scope), python searches for the variable definition using the above rules and finds that 'x' is defined in the outermost scope. Therefore when you reference x.a in Y.A it resolves just fine.

查看更多
手持菜刀,她持情操
4楼-- · 2019-06-17 08:36

Python looks up variables by first looking in the local scope (i.e. within a function) and if does not find it, it will use the variable from the global scope, if it exists. After that it will look for Python built-in names.

When the statement y = Y() is reached, x has already been declared in the global scope. This means that when the function A(self) is called, x can be looked up in the global scope.

More information about variable scope can be found here: Short Description of the Scoping Rules?

查看更多
祖国的老花朵
5楼-- · 2019-06-17 08:40

It's because you've instantiated x=X(), so that x.a, x.b, and x.c can be accessed. If you try z=X(), you'll notice it doesn't work.

查看更多
闹够了就滚
6楼-- · 2019-06-17 08:45

When python compiles a def into a function, it tries to figure out if the things you are referencing are locals - and if they're not, you must be referring to a global. For example:

def f():
    print(x)

Well, you haven't defined x within the scope of f, so you must be referring to a global.

This is all that's happening in your above code. You haven't defined x within the scope of A, so x must be a global. As it happens, you define the global:

x = X()

before you call it:

y = Y()
y.A()

so everything works out okay.

In case you are going "hm, I'm not sure if I believe you, roippi" just look at the bytecode:

dis.dis(Y.A)
  3           0 LOAD_GLOBAL              0 (print) 
              3 LOAD_GLOBAL              1 (x) # aha
              6 LOAD_ATTR                2 (a) 
              9 LOAD_GLOBAL              1 (x) # aha!
             12 LOAD_ATTR                3 (b) 
             15 LOAD_GLOBAL              1 (x) # aha!!
             18 LOAD_ATTR                4 (c) 
             21 CALL_FUNCTION            3 (3 positional, 0 keyword pair) 
             24 POP_TOP              
             25 LOAD_CONST               0 (None) 
             28 RETURN_VALUE     

aha.

查看更多
登录 后发表回答