del a => (1, 2, 3) print(a)# => NameError: name 'a' is not defined The first three statements show dynamic binding in action. The variable a is bound to a string, then to a float, then to another variable which in turn is assigned a tuple of value (1, 2, 3). The del statement then unbinds the variable a from the tuple object which effectively deletes the a variable (if there were no other references to the tuple object it too would have been deleted because an object with zero references is marked for garbage collection (but is not necessarily actually deleted immediately)). But in this case we see that b is still referencing the tuple object so the tuple is not deleted. The final statement above shows that an exception is raised when an unbound variable is referenced. The way in Python dynamically binds and rebinds variables is a source of some confusion to new programmers and even experienced programmers who are used to static binding where a variable is permanently bound to a single memory location. The Python language, by design, allows for dynamic binding and rebinding. Because Python performs a syntactic analysis and not a semantic analysis (with one exception which is covered in Applicability to language) and because of the dynamic way in which variables are brought into a program at run-time, Python cannot warn that a variable is referenced but never assigned a value. The following code illustrates this: if a > b: import x else: import y Depending on the current value of a and b, either module x or y is imported into the program. If x assigns a value to a variable z and module y references z then, dependent on which import statement is executed first (an import always executes all code in the module when it is first imported), an unassigned variable reference exception will or will not be raised. .2 Guidance to language users Avoid rebinding except where it adds value; Ensure that when examining code that you take into account that a variable can be bound (or rebound) to another object (of same or different type) at any time; and Variables to a function are deleted automatically when the encompassing function is exited but, though not a common practice, you can also explicitly delete variables using the del statement when they are no longer needed. Unused Variable [YZS] The applicability to language and guidance to language users sections of the write-up are applicable here.
Inheritance [RIP] .1 Applicability to language Python supports inheritance through a hierarchical search of namespaces starting at the subclass and proceeding upward through the superclasses. Multiple inheritance is also supported. Any inherited methods are subject to the same vulnerabilities that occur whenever using code that is not well understood. .2 Guidance to language users Inherit only from trusted classes; and Use Python’s built-in documentation (such as docstrings) to obtain information about a class’ method before inheriting from it. Extra Intrinsics [LRM] .1 Applicability to language Python provides a set of built-in intrinsics which are implicitly imported into all Python scripts. Any of the variables and functions can therefore easily be overridden: x = 'abc' print(len(x))#=> 3 def len(x): return 10 print(len(x))#=> 10 If the example the built-in len function is overridden with logic that always returns 10. Note that the def statement is executed dynamically so the new overriding len function has not yet been defined when the first call to len is made therefore the built-in version of len is called in line 2 and it returns the expected result (3 in this case). After the new len function is defined it overrides all references to the builtin-in len function in the script. This can later be “undone” by explicitly importing the built-in len function with the following code: from builtins import len print(len(x))#=> 3 It’s very important to be of name resolution rules when overriding built-ins (or anything else for that matter). In the example below, the overriding len function is defined within another function and therefore is not found using the LEGB rule for name resolution (see ): x = 'abc' print(len(x))#=> 3 def f(x): def len(x): return 10 print(len(x))#=> 3