Learning to Program - Advanced Topics - What's in a name?

久々にAlan.Gauld先生の下に帰ってきた。帰ってきました先生!まだLearn Python The Hard Way終わってないけどね^^

Python's approach

In Python there are a total of four possible namespaces (or scopes):

1. Built in scope - names defined within Python itself, these are always available from anywhere in your program.
2. Module scope - names defined, and therefore visible within a file or module, confusingly this is referred to as global scope in Python whereas global normally means visible from anywhere in other languages.
3. Local scope - names defined within a function or a class method
4. Nested scope - a slightly complex topic which I'll come back to in another topic. For now you can pretty much ignore this one!

Note that we don't count def and print as names because they are keywords or commands forming part of the language, if you try to use them as names of variables of functions you will get an error.

Here we look in more detail at exactly how Python locates names, even when the names we are using are not in the immediate namespace. It is resolved as follows, Python will look:

1. within it's local namespace (the current function),
2. within the module scope (the current file),
3. the built-in scope.

If a function refers to a variable called X and there exists an X within the function (local scope) then that is the one that will be seen and used by Python. It's the programmer's job to avoid name clashes such that a local variable and module variable of the same name are not both required in the same function - the local variable will mask the module name.

There is no problem if we just want to read a global variable inside a function, Python simply looks for the name locally, and not finding it will look globally (and if need be at the built-in namespace too). The problem arises when we want to assign a value to a global variable. That would normally create a new local variable inside the function. So, how can we assign a value to a global variable without creating a local variable of the same name? We can achieve this by use of the global keyword:

var = 42
def modGlobal():
   global var  # prevent creation of a local var
   var = var - 21

def modLocal():
   var = 101
   
print var   # prints 42
modGlobal()
print var   # prints 21
modLocal()
print var   # still prints 21

なるほろ。これは打ち込めるので打って実行した。So, how can we assign a value to a global variable without creating a local variable of the same name?なわけね、なるほろ。

Here we see the global variable being changed by the modGlobal function but not changed by the modLocal function. The latter simply created its own internal variable and assigned it a value. At the end of the function that variable was garbage collected and its existence was unseen at the module level.

garbage collected きたー

In general you should minimize the use of 'global' statements, it's usually better to pass the variable in as a parameter and then return the modified variable. Here is the modGlobal function above rewritten to avoid using a global statement:

var = 42
def modGlobal(aVariable):
    return aVariable - 21

print var
var = modGlobal(var)
print var
<<
>>
In this case we assign the return value from the function to the original variable while also passing it in as an argument. The result is the same but the function now has no dependencies on any code outside itself - this makes it much easier to reuse in other programs. It also makes it much easier to see how the global value gets changed - we can see the explicit assignment taking place
<<
まぁ、今はあまり実感できないけど、後々プログラムをまじめに組んでいく時に役立ちそうな幹事はする。というか明示性(わかりやすさ)がPythonの鍵であり重要ないい部分だと思うように僕もなってきた。意識してプログラム書いていけたらと思えている。

>|python|
# variables with module scope
W = 5
Y = 3
 
#parameters are like function variables 
#so X has local scope
def spam(X):
    
   #tell function to look at module level and not create its own W
   global W
   
   Z = X*2 # new variable Z created with local scope
   W = X+5 # use module W as instructed above

   if Z > W:
      # pow is a 'builtin-scope' name
      print pow(Z,W)
      return Z
   else:
      return Y # no local Y so uses module version

最終的にこうなることを理解できた。Pythonのnamespace,Scopeを征服した! かな。最初は戸惑ったけど、なんとか抑えるところを抑えて理解できたかなぁ。という感じ。

ちょっとこれ動くようにしてみたい。raw_inputとそれをintで囲んで、spamファンクション、spam関数を呼び出せばいいわけだ。

# variables with module scope
W = 5
Y = 3

# parameters are like function variables
# So X has local name
def spam(X):

    # tell function to look at module level and not create its own W
    global W

    Z = X * 2 # new variable Z created with local scope
    W = X + 5 # use module W as instructed above

    if Z > W:
        # pw is 'builtin-scope' name
        print pow(Z, W)
        return Z
    else:
        return Y # no local Y so uses module version

Number = int(raw_input("spam(X): "))
Number = spam(Number)
print Number

一応こんな感じで出来ました。別に何か目的があって計算結果出してるわけではないんで、あれなんだけど。Yにそのまま3が入ってきたり間抜けな感じだがそれがいい

VBScript
全く予想通りに問題なく動く。今度は本当にGlobalってところはコツだね。PythonでのGlobalとはちょっと違う。

And JavaScript too
全く問題なし、久々にJavascriptだからちょっと戸惑ったがw

# Python has 3 scopes - file (global), function (local) and built-in.
# VBScript and JavaScript have 2 scopes - file (global) and function (local).

次は正規表現か。Debian周りでも色々とというか、今後色々と使えるかな。今日一日でこれ終わっちゃったのはすごかったなぁ。