Skip to content

Python Note

目录

  1. C Compilation Process (Overall)

  2. Compiling Java

  3. Running Java

  4. Interpreting a Program

  5. Variables (Python Context)

  6. Static Typing

  7. Dynamic Typing

  8. Python Documentation (Docstrings)

  9. Python Type Hints

  10. Equal function (== vs is)

  11. Argument Passing in Python ("Pass by Object Reference" / "Pass by Assignment")

  12. Collections in Python

  13. Python Modules

  14. Function Overloading (Python context)

  15. Command-Line Arguments (Python)

  16. Object-Oriented Programming (OOP) – Introduction

  17. Python Classes

  18. Abstract Data Types (ADTs)

  19. Abstract Classes (Python)

  20. Multiple Classes per Module (Python)

  21. Name Mangling / Convention for "Private" Attributes (Python)

Introduction of Python

  • Known for its readability, which means code is easier to write, understand and maintain.
  • Backed by library support, so we don’t have to build everything from scratch, there’s probably a library that already does what we need.

  • Interpreted Language: Python code is executed line by line by the Python interpreter, which means no separate compilation step is needed. You can run Python programs immediately after writing them, making development faster and more interactive.

  • Dynamic Typing: Variables in Python don't need explicit type declarations. The interpreter automatically determines the data type at runtime, allowing for more flexible and concise code writing.
  • Interactive Shell (REPL) : Python provides an interactive command-line interface where you can test code snippets, experiment with functions, and get immediate feedback. This makes learning and debugging much easier.
  • Cross-Platform Compatibility: Python runs seamlessly on Windows, macOS, Linux, and many other operating systems without requiring code modifications, making it truly portable across different environments.
  • Multiple Programming Paradigms: Python supports procedural, object-oriented, and functional programming styles, allowing developers to choose the most appropriate approach for their specific problem or combine different paradigms within the same project.
  • Indentation-Based Syntax: Unlike many languages that use braces or keywords, Python uses indentation to define code blocks. This enforces clean, readable code structure and eliminates common syntax errors.
  • Duck Typing: Python follows the principle "if it walks like a duck and quacks like a duck, it's a duck." Objects are used based on their behavior rather than their explicit type, providing flexibility in how code interacts with different objects.
  • Automatic Memory Management: Python handles memory allocation and garbage collection automatically, freeing developers from manual memory management tasks and reducing memory-related bugs.
  • Easy Integration: Python can easily integrate with other programming languages like C, C++, Java, and .NET, allowing developers to leverage existing code and optimize performance-critical sections when needed.

1. C Compilation Process (Overall)

  • Definition: The multi-stage process of transforming human-readable C source code into a machine-executable program.
  • Points to Note:

  • Involves several distinct steps: Pre-processing, Compiling, Assembling, and Linking.

  • Each step takes an input file and produces an output file, often with a different extension and format.
  • Simple Example: The entire pipeline from hello.c to the executable hello.

1.1. Source Program (C)

  • Definition: The original C code written by the programmer.
  • Points to Note:

  • Stored as a text file.

  • Human-readable.
  • Simple Example: A file named hello.c containing C code.

1.2. Pre-processor (cpp)

  • Definition: A program that processes the source code before the main compilation step.
  • Points to Note:

  • Handles directives like #include (to include header files) and #define (to expand macros).

  • Input: Original source code (e.g., hello.c).
  • Output: Modified source program, still in text form (e.g., hello.i).
  • Simple Example: cpp processes hello.c containing #include <stdio.h> to produce hello.i where the content of stdio.h is effectively inserted.

1.3. Compiler (cc1 - a common name for the compiler proper)

  • Definition: A program that translates the pre-processed source code (high-level language) into assembly language.
  • Points to Note:

  • Input: Modified source program (e.g., hello.i).

  • Output: Assembly language code, in text form (e.g., hello.s).
  • The assembly code is specific to the target machine's architecture.
  • Simple Example: cc1 translates hello.i into hello.s, which contains assembly instructions like mov, add, etc.

1.4. Assembler (as)

  • Definition: A program that converts assembly language code into machine code (binary).
  • Points to Note:

  • Input: Assembly language code (e.g., hello.s).

  • Output: A relocatable object program, in binary format (e.g., hello.o).
  • This object file contains machine instructions but isn't fully executable as addresses for external references (like library functions) are not yet resolved.
  • Simple Example: as converts hello.s into hello.o.

1.5. Linker (ld)

  • Definition: A program that combines one or more relocatable object programs and necessary libraries to produce a final executable object program.
  • Points to Note:

  • Input: Relocatable object program(s) (e.g., hello.o) and libraries (e.g., stdlib.so - a shared object library).

  • Resolves external references (e.g., function calls to library functions).
  • Output: A final executable object program, in binary format (e.g., hello).
  • This executable is ready to be run by the operating system.
  • Simple Example: ld combines hello.o with stdlib.so (if printf from stdio.h was used, it would link against the C standard library) to create the executable hello.

2. Compiling Java

  • Definition: The process of translating Java source code (.java files) into Java bytecode (.class files) using the Java compiler.
  • Points to Note:

  • The Java compiler is typically javac.

  • It recursively finds any used class:

    • First, checks if it's defined in the Java Standard Library.
    • If not, it searches all directories given by the -cp (classpath) flag; by default, this is the current directory.
    • If a .class file for a used class is found, it will use it.
    • If a .java source file is found (and typically if it's newer than any existing .class file or no .class file exists), it will compile it.
    • The compiler performs static type checking (verifies types at compile time).
    • Simple Example: javac SweetProgram.java compiles SweetProgram.java into SweetProgram.class.

3. Running Java

  • Definition: Executing Java bytecode using a Java Virtual Machine (JVM).
  • Points to Note:

  • The JVM is typically invoked using the java command.

  • The JVM recursively finds any used class (as .class files) similarly to the compiler, using the classpath.
  • The JVM performs dynamic type checking (verifies types at runtime, e.g., for casts).
  • Simple Example: java SweetProgram executes the bytecode in SweetProgram.class.

4. Interpreting a Program

  • Definition: A process where program instructions are read and executed one by one, potentially modifying or using the program's state with each instruction.
  • Points to Note:

  • The "state" can include defined variables, functions, and other data structures.

  • When an instruction is interpreted, the state can be:

    • Used (e.g., reading a variable's value).
    • Modified (e.g., assigning a new value to a variable, defining a function).
    • Or both.
    • Some instructions may produce output (e.g., PRINT) without necessarily changing the core state definitions.
    • Simple Example:
DEFINE FOO          // State now includes FOO definition
PRINT("Hello")      // Uses implicit state (program counter), produces output
DEFINE A = 42       // State now includes A=42
PRINT(A)            // Uses state (value of A), produces output

5. Variables (Python Context)

  • Definition: In Python, a variable is a name that refers to an object stored in memory. The object has a value and an identity (memory address).
  • Points to Note:

  • Assignment (=) binds a name to an object.

  • id(variable_name) returns the unique identifier (memory address) of the object the variable refers to.
  • Changing the value of an immutable type variable (like an integer) often means the variable name now refers to a new object in memory.
  • Simple Example:
amount = 50
print(amount)       # Output: 50
print(id(amount))   # Output: e.g., 0x1000 (a memory address)

6. Static Typing

  • Definition: A type system where variable types are explicitly declared and checked by the compiler before the program is run (at compile-time).
  • Points to Note:

  • The type of a variable is fixed once declared.

  • Attempting to assign a value of an incompatible type to a variable will result in a compile-time error.
  • Languages like C and Java are statically typed.
  • Simple Example (C/Java):
int amount = 1000;  // 'amount' is declared as an integer
// amount = "hello"; // This would cause a compile-time error

7. Dynamic Typing

  • Definition: A type system where variable types are checked during program execution (at runtime).
  • Points to Note:

  • Variables do not have fixed types; their type is determined by the object they currently refer to.

  • A variable can refer to objects of different types during the program's execution.
  • Python is a dynamically typed language.
  • Simple Example (Python):
amount = 1000      # 'amount' currently refers to an integer object
print(amount)
amount = "string"    # 'amount' now refers to a float object
print(amount)

8. Python Documentation (Docstrings)

  • Definition: A string literal that occurs as the first statement in a module, function, class, or method definition, used to document its purpose, arguments, and return values.
  • Points to Note:

  • Enclosed in triple quotes ("""Docstring content""").

  • Accessible at runtime via the __doc__ attribute of the object.
  • Conventions exist for formatting (e.g., reStructuredText, Google style) to describe parameters (:param:), return values (:return:), etc.
  • Simple Example:
def is_prime(value: int) -> bool:
    """
    Checks whether an integer value is a prime number or not.

    :param value: the value to check
    :return: 'true' iff 'value' has only 2 divisors (1, and 'value')
    """
    # ... implementation ...
    pass
print(is_prime.__doc__)

from typing import TypeVar, Generic

T = TypeVar('T')

class Optional(Generic[T]):

    def __init__(self: 'Optional', value: T = None):
        self.__value = value

    def is_present(self: 'Optional') -> bool:
        return self.__value is not None

    def get_value(self: 'Optional') -> T:
        assert(self.is_present())
        return self.__value

    def set_value(self: 'Optional', new_value: T):
        self.__value = new_value

    def __str__(self: 'Optional'):
        return "Optional(" + str(self.__value) + ")" if self.is_present() else "Empty"


if __name__ == "__main__":
    int_optional: Optional[int] = Optional("Hello")
    print(int_optional)

At runtime, Python does not enforce Optional[int]int. You can write

int_optional: Optional[int] = Optional("Hello")

and it will run just fine. The code will print:

Optional(Hello)

because Python never checks “is this really an int?” at runtime.

In other words, the Generic[T] and TypeVar('T') machinery is purely for static analysis. Once you execute the script, the interpreter treats Optional(...) exactly like any other class, ignoring its “[int]” annotation.

9. Python Type Hints

  • Definition: Optional annotations that suggest the expected types of variables, function parameters, and function return values.
  • Points to Note:

  • Introduced in Python 3.5+.

  • Do not enforce type checking at runtime by Python itself; they are for static analysis tools (like MyPy) and improving code readability.
  • Syntax: variable: type, def func(param: type) -> return_type:.
  • Simple Example:
def is_prime(value: int) -> bool:
    divisors: int = 0
    # ... rest of the function ...
    return True # Placeholder

10. Equal function (== vs is)

Definition:
Python provides two main ways to compare objects: == (equality operator) and is (identity operator).

Note(s):

  • == (Equality): Compares the values of two objects. It returns True if the objects have the same content. For custom objects, this behavior can be overridden by defining the __eq__ method.
  • is (Identity): Compares the identity of two objects. It returns True if both variables point to the exact same object in memory (i.e., they have the same memory address).
  • You should generally use == for checking if two objects have the same value.
  • Use is primarily for checking if a variable points to the singleton None (e.g., x is None or x is not None).
  • For immutable types like strings and small integers, Python might cache and reuse objects, so is might sometimes return True even if you expect False (this is an implementation detail and shouldn't be relied upon for value comparison).

11. Argument Passing in Python ("Pass by Object Reference" / "Pass by Assignment")

  • Definition: When an argument is passed to a Python function, the function's parameter name becomes a new reference to the same object that was passed in. It's not strictly pass-by-value (copy of value) or pass-by-reference (copy of address of variable).
  • Points to Note:

  • Everything in Python is an object. Variables are names pointing to objects.

  • The function receives a reference to the original object.
  • Immutable Objects (e.g., integers, strings, tuples): If the function reassigns the parameter or performs an operation that creates a new object (like += on an integer), the parameter inside the function will refer to this new object. The original object outside the function remains unchanged.
  • Mutable Objects (e.g., lists, dictionaries): If the function modifies the object's contents in-place (e.g., list.append()), these changes will be visible outside the function because both the external variable and the internal parameter refer to the same, now modified, object.
  • id() can be used to check if two names refer to the same object.
  • Simple Example (Immutable):

def modify_immutable(num):
    print(f"Inside, before: num={num}, id={id(num)}")
    num += 1 # Creates a new integer object, 'num' now refers to it
    print(f"Inside, after: num={num}, id={id(num)}")

val = 10
print(f"Outside, before: val={val}, id={id(val)}")
modify_immutable(val)
print(f"Outside, after: val={val}, id={id(val)}") # val remains 10
- Simple Example (Mutable):

def modify_mutable(lst):
    print(f"Inside, before: lst={lst}, id={id(lst)}")
    lst.append(1) # Modifies the original list object in-place
    print(f"Inside, after: lst={lst}, id={id(lst)}")

my_list = []
print(f"Outside, before: my_list={my_list}, id={id(my_list)}")
modify_mutable(my_list)
print(f"Outside, after: my_list={my_list}, id={id(my_list)}") # my_list is now [1]

12. Collections in Python

  • Definition: Built-in data structures used to store groups of items.
  • Points to Note & Simple Examples:

  • List:

    • Ordered, changeable (mutable), allows duplicate members.
    • my_list = ["apple", "banana", "apple"]
    • Tuple:

    • Ordered, unchangeable (immutable), allows duplicate members.

    • my_tuple = ("apple", "banana", "apple")
    • Set:

    • Unordered (in older Python versions, may appear ordered in CPython 3.7+ due to implementation, but order is not guaranteed by language spec until 3.7+), items are unchangeable but the set itself is mutable (can add/remove items), unindexed, no duplicate members.

    • my_set = {"apple", "banana"}
    • Dictionary:

    • Ordered (in Python 3.7+, unordered in <3.6, insertion order preserved in CPython 3.6), changeable (mutable), no duplicate keys (values can be duplicates). Stores key-value pairs.

    • my_dict = {"fruit1": "apple", "fruit2": "banana"}
    • type() function can identify the type of a collection: print(type(my_list)) -> <class 'list'>.

13. Python Modules

  • Definition: A file containing Python definitions (functions, classes, variables) and statements. The file name is the module name with the .py extension.
  • Points to Note:

  • Used to organize code into logical units.

  • Imported using the import statement (e.g., import math).
  • Definitions from an imported module are accessed using dot notation (e.g., math.pi).
  • __name__: A special built-in variable.

    • If the file is run directly: __name__ is set to "__main__".
    • If the file is imported: __name__ is set to the module's name (the file name without .py).
    • if __name__ == "__main__": block: Code inside this block executes only when the file is run directly, not when imported. This is used for tests or script-specific logic.
    • Importing a module executes its top-level statements (e.g., variable assignments, function/class definitions, print() calls not inside functions or the if __name__ == "__main__" block) once per interpreter session.
    • Simple Example:
  • my_module.py:

    # my_module.py
    print(f"my_module's __name__ is: {__name__}")
    def greet():
        print("Hello from my_module!")
    
    if __name__ == "__main__":
        print("my_module is being run directly")
        greet()
    
    - ​main_script.py:

    # main_script.py
    import my_module
    print("Running main_script.py")
    my_module.greet()
    
    - Running python my_module.py will show its __name__ as __main__ and execute the if block. - Running python main_script.py will first import my_module (showing its __name__ as my_module), then print "Running main_script.py", then call my_module.greet().


14. Function Overloading (Python context)

  • Definition (General): The ability to define multiple functions with the same name but different parameters (either in number or type).
  • Points to Note for Python:

  • Python does not support traditional function overloading directly. If you define multiple functions with the same name, the last definition overwrites any previous ones.

  • Python achieves similar flexibility through:

    • Default argument values.
    • Variable-length arguments (*args, **kwargs).
    • Type checking within the function body (e.g., using isinstance()).
    • Simple Example (Illustrating overwriting):
def my_func(x):
    print(f"One argument: {x}")

def my_func(x, y): # This definition replaces the previous one
    print(f"Two arguments: {x}, {y}")

# my_func(10)  # This would now cause a TypeError
my_func(10, 20) # Calls the second definition

15. Command-Line Arguments (Python)

  • Definition: Values passed to a Python script when it is executed from the command line.
  • Points to Note:

  • Accessed via the sys.argv list, which is part of the sys module.

  • sys.argv[0] is always the name of the script itself.
  • Subsequent elements (sys.argv[1], sys.argv[2], etc.) are the arguments passed to the script as strings.
  • You need to import sys to use sys.argv.
  • Simple Example:

  • script_args.py:

    import sys
    if __name__ == "__main__":
        print(f"Script name: {sys.argv[0]}")
        if len(sys.argv) > 1:
            print(f"First argument: {sys.argv[1]}")
        else:
            print("No arguments provided.")
    
    - Running from command line: python script_args.py hello​ - Output:

    Script name: script_args.py
    First argument: hello
    

16. Object-Oriented Programming (OOP) - Introduction

  • Definition: A programming paradigm based on the concept of "objects", which bundle data (attributes) and methods (functions that operate on the data).
  • Points to Note:

  • Aims to describe values and operations on them while hiding internal implementation details (encapsulation).

  • Class: A blueprint or template for creating objects. Defines the attributes and methods.
  • Object: An instance of a class, with a specific state (values for its attributes).
  • Simple Example (Conceptual): A Car class could define attributes like color, speed and methods like start_engine(), accelerate(). An individual car object would be an instance, e.g., my_red_car = Car(color="red").

17. Python Classes

  • Definition: A blueprint for creating objects in Python. It defines a set of attributes (data members) and methods (member functions) that the created objects will have.
  • Points to Note:

  • Defined using the class keyword.

  • __init__(self, ...): Special method (constructor) called when an object is instantiated. self is the first argument, referring to the instance being created. Used to initialize instance attributes.
  • self: The first parameter of instance methods, explicitly referring to the instance itself (like this in Java, but explicit).
  • __str__(self): Special method that returns a string representation of an object, used by print() and str().
  • Attributes (variables belonging to an instance) are typically accessed using self.attribute_name.
  • Methods (functions belonging to an instance) are defined like regular functions within the class, with self as the first parameter.
  • Simple Example:
class Greeter:
    def __init__(self, name: str):  # Constructor
        self.name = name  # Instance attribute

    def greet(self) -> str:  # Instance method
        return f"Hello, {self.name}!"

# Creating an instance (object)
alice_greeter = Greeter("Alice")
print(alice_greeter.greet())  # Output: Hello, Alice!

18. Abstract Data Types (ADTs)

  • Definition: A theoretical concept that defines a data type by its behavior (the operations that can be performed on it and the semantics of these operations) without specifying its concrete implementation.
  • Points to Note:

  • Focuses on what operations are supported and what they do, not how they are implemented.

  • Hides the internal representation and implementation details.
  • Simple Example: A "Stack" ADT can be defined by operations push(item), pop(), peek(), is_empty(). The user of the Stack ADT doesn't need to know if it's implemented using an array or a linked list.

19. Abstract Classes (Python)

  • Definition: Classes that contain one or more abstract methods. Abstract methods are declared but have no implementation in the abstract class itself. Abstract classes cannot be instantiated directly.
  • Points to Note:

  • Python uses the abc module (ABC class and abstractmethod decorator).

  • A class inherits from ABC to be recognized as an abstract base class.
  • Methods decorated with @abstractmethod must be implemented by any concrete (non-abstract) subclass.
  • The pass statement is often used as the body for an abstract method in Python.
  • pass is a null statement in Python. It acts as a placeholder.
  • Used to define a common interface or contract that subclasses must adhere to.
  • Python does not have explicit "interfaces" like Java; abstract classes serve a similar purpose.
  • Simple Example:
from abc import ABC, abstractmethod

class List(ABC):  # Inherits from ABC
    """An abstract list, a linearly ordered collection of elements."""
    @abstractmethod  # Decorator for abstract method
    def append(self, elem) -> bool:
        """Appends an element to the end of the list"""
        pass # No implementation here

class MyConcreteList(List): # Concrete subclass
    def __init__(self):
        self._elements = []

    def append(self, elem) -> bool: # Must implement append
        self._elements.append(elem)
        print(f"Appended {elem}")
        return True

# my_abstract_list = List() # This would cause a TypeError
my_list = MyConcreteList()
my_list.append("item1")

20 . Multiple Classes per Module (Python)

  • Definition: A single Python file (module) can contain the definitions for more than one class.
  • Points to Note:

  • All classes defined within the module are part of that module's namespace.

  • They can be imported and used from other modules.
  • Simple Example (shapes.py):
# shapes.py
class Circle:
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14159 * self.radius * self.radius

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height

21. Name Mangling / Convention for "Private" Attributes (Python)

  • Definition: Conventions in Python to indicate that attributes or methods are intended for internal use, rather than being part of the class's public interface. Python does not have true private members like some other languages.
  • Points to Note:

  • Single Underscore Prefix (e.g., _node):

    • A convention indicating that a name is for internal use.
    • It's a hint to programmers not to rely on it as part of the public API.
    • It does not prevent access.
    • from module import * does not import names starting with an underscore.
    • Double Underscore Prefix (e.g., self.__value):

    • Triggers "name mangling." Python renames the attribute to _ClassName__attributeName.

    • Primarily used to avoid naming conflicts in subclasses (if a subclass defines an attribute with the same double-underscore name).
    • It makes it harder to access directly from outside but not impossible (if you know the mangled name).
    • Simple Example:
class MyData:
    def __init__(self, value):
        self._internal_value = value * 2  # Convention: internal
        self.__mangled_value = value * 3 # Will be _MyData__mangled_value

    def get_mangled(self):
        return self.__mangled_value # Access internally

md = MyData(10)
print(md._internal_value)  # Accessible, but conventionally internal: 20
# print(md.__mangled_value) # AttributeError
print(md._MyData__mangled_value) # Accessible via mangled name: 30
print(md.get_mangled()) # Accessible via public method: 30

The example class _Node: from the slides uses a single underscore for the class name itself, suggesting the entire class is intended for internal use within its module.