Python "variables" are special.
Other languages have "variables" (🎨 Time to draw!)?
1. Python names are "pointers".
2. Names bound to mutable objects do not change.
3. Names bound to immutable objects can switch.
Here we distinguish two concepts: namespace and scope: A namespace is a mapping from names to objects. A scope is a textual region of a Python program where a namespace is directly accessible.
Namespaces are usefule when deciding the order of resolution of names. Python follows the "LEGB" rule to resolve names:
Local => Enclosed => Global => Built-in
Further examples:
1. Python interpreter searches from smaller namespaces to larger namespaces for a name.
2. The exception is the unbound local names from within a class. They "jump" from local to global namespaces.
3. A subtle point is that our code live in the __main__ module with ONE global space. For multiple .py files, each has its own global.
Here is the official document.
Besides these, also comparisons are:
1. Comparisons involving NaN are all false, except NaN != NaN
2. None is a singleton (only one instance for its class). Use is or is not.
3. x is y should imply x == y.
4. == invokes __eq__(); is invokes id() comparison; in invoke __contains__() method if defined;
Expressions comes first, then parimaries, then arithmatic, then bitwise, then comparison.
See here for reference.
"In interactive mode, if the value is not None, it is converted to a string using the built-in repr() function and the resulting string is written to standard output on a line by itself (except if the result is None, so that procedure calls do not cause any output.)"
1. Name binding constructs
2. Augmented assignment (eval then assign)
Augmented assignment calls different functions: for mutable objects, x+=1 is not equal to x = x + 1. The augmented add (+=) can modify objects in place.
A gotcha is to bring to your attention.
3. The attribute appearing as a name always refer to the instance attribute.
Assertions are primarily for debugging purposes. For a complex code where the bug lies can be difficult to pinpoint. Assertions help by providing checkpoints throughout the code, allowing you to verify that certain conditions hold true as the program executes. If an assertion fails, it raises an AssertionError and provides immediate feedback about where the assumption in the code was violated. This can save time by helping you identify the problematic section of code more quickly.
Note when not debugging, an EAFP style is preferred in the Python language than the LBYL style.
1. Lifecycle of the except ... as ... clause.
2. finally is always executed, even after return.
3. Execution order of except: let's go back to the exception example.