x = 10but limiting dynamism to untyped variables only would be missing the point.
x = "ten"
print(x) # prints ten
Like with many "scripting" languages a Python program is started by passing the name of its main module to the "interpreter", such as
c:> python main.pyThe transition of Python source code to an actually executed program begins with loading and parsing the module file. This step succeeds as soon as the module does not contain any syntax errors fatal for the parser. Successful parsing only guarantees that the module is not totally broken - a weak guarantee, only useful for checking for unbalanced parentheses and such.
What happens next is magic - the parsed module file is executed as though it was just a chunk of a source code. Wait a minute ! It is a chunk of a source code ! Anyway, execution of every module at its first import is the major part of Python program run. This process is identical no matter if the module being loaded is the program's main module or some other module explicitly imported by demand.
I have arrived to Python from C++, it took me a long time to change the perspective and the change is this - in Python you should look at everything as though it is an executable statement, because it really is. To illustrate this principle, consider definitions vs. declarations.
In statically typed languages, declarations exist for the sake of separate compilation - for the compiler to be able to tell whether one part of code is compatible with another without having to dig through the entire program. In Python, which is a dynamic language, there is no compilation stage, therefore declarations are useless, and what's left only looks like definitions.
For example, where in C++ you have two files (if you do it properly)
// foo.h // foo.cppthe .h file is a declaration - your promise to the compiler that you will provide the matching implementation and the .cpp file is that promise fulfilled. In Python there is no compiler so you don't have to feel obliged. Identical code in Python would be
class Foo int Foo::GetX(void) const
private: return x;
int x; }
int GetX(void) const;
class Foo:What you see in this Python code is neither a declaration nor a definition. It is a piece of executable code, which, when executed, introduces a new class to the containing module's namespace. Rewritten to its actual effect in pseudocode it would look like this:
class Foo: temp1 = new class()What you just saw was an illustration that a Python class definition is an executable statement, just like anything else and it executes once when the module is first imported. For example, it is possible to do something like C++'s conditional compilation:
def get_x(self): temp2 = new method()
return self.x temp2.__code__ = return self.x
temp1["get_x"] = temp2
module["Foo"] = temp1
class Foo:The effect of the above code is that when the module is imported, the compiled version of class Foo will contain method do_it matching the current environment. It is not the same as the straightforward approach, where the check would have been performed upon each call to do_it:
if os.platform == "win32":
def do_it(self): # windows way
def do_it(self): # unix way
class Foo:In a similar vein, your class definition could fail to execute:
if os.platform == "win32": # windows way
else: # unix way
class Foo:and the module will fail to import, throwing an exception to the caller.
1 / 0 # this throws at import time
Now it should not surprise you the least that when one module imports the other it is again not a declaration. When module foo does
import barthe described process repeats for module bar, unless it has already been imported, in which case the import statement does nothing (from the discussed point of view). Similarly, you can import modules as you need them at runtime:
if need_time:Python therefore does not have any declarative semantics, only executional - ask yourself - what does it do when executed ?
To be continued...