百度空间 | 百度首页 
 
查看文章
 
Some Thoughts on Python's Scope and Binding Rules (1)
2008-08-18 12:15
Basically Python is lexically scoped like almost all other mainstream languages, that is, certain language facilities like the 'class', 'def' statements will create a new scope for their own code blocks. And when names are looked up, the intepreter goes up the nested scope levels and stop at the first one it encounters. It sounds fine, but things would go a little confusing when we bind values to variables.

Which scope will the newly binded variable be in?

The answer is actually simple, python ALWAYS creates bindings in the local scope if the valuable is not declared explicitly as 'global'.

Sounds sweet and pythonic (and I am rather fond of capitalizing ALWAYS here and there :P), so what's the tricky part?

Let's take a look at the following code sample:

X = 99

def fun1(Y):
    Z = X + Y
    return Z

print fun1(1)

As expected, we get 100 as the output, because the intepreter refers to the global X according to name resolution rules.

No surprise? Then take that instead:

X = 99

def fun2(Y):
    Z = X + Y
    X = 200
    return Z

print fun2(1)

At the first glance we may assume the output to be 100 too, and even believe that the global X is now 200. But actually, the program will be terminated by an error saying that X is used before binded!

Though somewhat strange, this reaction is intentional.

According to the binding rules, the X in "X = 200" is ALWAYS a local X, not the global one. (Remember that assignments in python ALWAYS creates new bindings, no in-place mutation will happen.)

Now the question is, which X is the one in 'Z = X + Y'?

Someone might prefer the 'flow model', that before the local X is created by 'X = 200', all references of X in fun2 would be referencing the global one. Thus no error would pop up and everyone will be happy with an answer of 100.

For the sample above, this attitude might work well, but once the function grows and control structures are involved, things will become a lot more complcated and you are likely to have maintaince nightmare. (For instance, if in a if statement, X is assigned in a branch but not in the other, you will not be quite pleased.)

After all, naming two completely different things with the same name in a single scope is A BAD IDEA (tm).

So the policy of python is like this:

In a given scope,

(1) if one variable is not assigned anywhere, it refers the one found by resolution rules.

(2) otherwise, it will ALWAYS refer the local one, no matter the reference comes before or after the assignment. ( And we may meet lovely error messages. )

The policy is actually clear, but the result is confusing (adding an assignment would alter the meaning of a name), so you may ask:

Why does the bindings are ALWAYS local (by default) IN THE FIRST PLACE?

IMHO this choice is to avoid name collision of local variables and global ones, eliminating unintentional coupling of a function and its surrounding environment (That a global variable is accidentally modified inside a function).

This collision problem is not present in languages like C/C++/Java where variable declaration are forced. (Every declaration means a different variable, no declaration, no new variables.)

Other languages has different approachs:

PHP: In functions, PHP favors local bindings and globals must be declared, no matter the name is to be assigned or not.

Ruby: Has all fancy variable prefixes like $, @, @@ etc to mark variables with different scopes.

Lua: The default is the first hit in the resolution chain, locals must be declared.

Each has pros and cons which I am not to talk about further here. However it seems the PHP approach is similiar to the python one, but more consistent.

So why does python work this way?

The PHP approach distinguishs between 'builtins' (which is universally accessable) and 'globals' (which must be declared to use in certain places), but Python do not. All python builtins are 'normal' variables that follow the same resolution rule, which means they can be shadowed just like any other python variable, no special statements are needed. It may be a trap or a feature depending on how you utilize it, and the intepeter will warn you if you do so.

(Actually, the 'global' in python means 'module scope' or 'file scope', and the only thing in the 'universal' scope which spread across all modules are the builtins. While residing in the '__builtin__' module, they are implicitly imported. And this is the only difference between them and other variables.)

Nevertheless the scopes in python is maybe the 'messiest' part of the language I encountered so far. [Ah, PHP (and C) has 'messy' rules as well, such as functions create scopes for local variables but not for nested functions, etc.]

In Part 2 of this post I will discuss something about nested functions, lambda expressions and closures as I go along with the language.


类别:函数阴阳 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu