SoFunction
Updated on 2025-03-04

Introduction to Python Page 9/10


Chapter 9 Class
Python is a truly object-oriented language that implements classes by adding only a few new syntaxes. Its class mechanism is a mixture of C++ and Modula-3 class mechanisms. Python classes do not strictly restrict users' modifications to definitions, they rely on users to consciously not modify definitions. However, Python maintains full power for the most important functions of the class. The class inheritance mechanism allows inheritance of multiple base classes. The exported class can overload any method of the base class, and the method can call the base class's method with the same name. Objects can contain as much private data as possible.

In C++ terms, all class members (including data members) are common and all member functions are virtual. There are no special build functions or destructors. As in Modula-3, there is no shortcut way to refer to object members from an object's methods: the method function must take the object as the first parameter, and is automatically provided when called. Like in Smalltalk, the class itself is an object. In fact, the meaning of the object here is relatively wide: in Python, all data types are objects. Like in C++ or Modula-3, built-in types cannot be extended by users as base classes. Moreover, like C++ but not Modula-3, most built-in functions (such as arithmetic operators, subscripts, etc.) with special syntax can be redefined as class members.

9.1 About Terms
Python has a wide concept of object, and objects do not necessarily have to be instances of classes, because like C++ and Modula-3, unlike Smalltalk, Python's data types are not all classes, such as basic built-in types, integers, lists, etc., and even weirder types such as files are not classes. However, all Python data types have more or less object-like syntax.

Objects have separate identities, and the same object can have multiple names to associate with them. This is called an alias in other languages. The benefits of this are not obvious at first glance, and there is no difference between non-mutable types (numbers, strings, tuples), etc. However, the alias syntax has an impact on programs that contain mutable objects such as lists, dictionaries, and programs involving external objects such as files, and windows of the program. This can be beneficial to program programming, because alias are somewhat similar to pointers: for example, passing an object becomes easy, because it is just passing a pointer; if a function modifies the object passed as a parameter, the modification result can be passed back to the call. This way, there is no need to use the two parameter transfer mechanism like Pascal.

9.2 Python scope and namespace
Before introducing classes, we must talk about the scope rules of Python. Class definition makes good use of namespace, and you need to understand how Python handles scope and namespace in order to fully understand the use of classes. In addition, scope rules are also knowledge that a high-level Python programmer must master.

Give some definitions first.

A namespace is a mapping from a name to an object. Most namespaces are currently implemented using Python dictionary types, but this is generally not noticeable and may change in the future. Below are some examples of namespace: built-in names in Python (such as abs() and other functions, as well as built-in exception names); global names in modules; local variable names in function calls. In a sense, all properties of an object also form a namespace. The most important thing about namespaces is to know that the names of different namespaces have no connection; for example, two different modules may define a function called "maximize" without causing confusion, because the user of the module must add the module name before the function name as a modification.

In addition, in Python, any name after a period can be called a property. For example, in an expression, real is an attribute of an object z. Strictly speaking, a reference to a name in a module is a property reference: in an expression, modname is a module object and funcname is a property of it. In this case there is a direct mapping between the module properties and the global names defined by the module: they use the same namespace!

The attribute can be read-only or writable. When the attribute is writable, the attribute can be assigned value. Module properties are writable: you can write "modname.the_answer = 42". Writable attributes can also be flashed with del statements, such as "del modname.the_answer".

Name spaces have different survival cycles when created at different moments. A namespace containing Python built-in names is created when the Python interpreter starts and will not be deleted. The global namespace of a module is created when the module definition is read in, and the module namespace usually exists until the interpreter exits. Statements executed by the top-level call of the interpreter, whether read from a script file or input interactively, belong to a module called __main__, so they also exist in their own global namespace. (The built-in name actually exists in a module, which is called __builtin__).

The local namespace of a function is created when the function is called, and is deleted when the function returns or produces an exception that cannot be processed inside the function. (In fact, it is said that I forgot that this namespace is more in line with what actually happens.) Of course, recursive calls have their own local namespace in each recursion.

A scope is a text area in a Python program, where a namespace can be accessed directly. "Direct access" here refers to using names without modification to directly find objects in the name space.

Although scope is defined statically, scope is dynamic when used. At any run time, there are always three scopes in use (that is, there are exactly three namespaces that are directly accessible): the innermost scope is first searched, containing the local name; the middle level scope is second searched, containing the global name of the current module; the outermost scope is last searched, containing the built-in name.

Generally, the local scope refers to the local name of the current function, where the local is in the sense of the source program text. Outside the function, the local scope uses the same namespace as the global scope: the module's namespace. The class definition adds another namespace to the local scope.

It is important to note that the scope is determined according to the text position in the source program: the global scope of the function defined in the module is the namespace of the module, no matter where the function is called or under what name. On the other hand, the search for names is performed dynamically during the program operation. However, the definition of Python language is also evolving and may develop into static name resolution in the future. When "compiling", so don't rely on dynamic name resolution! (In fact, the local name is already statically determined).

One of the special features of Python is that assignments always enter the innermost scope. The same is true for deletion: "del x" deletes the name binding of x from the name space corresponding to the local scope (note that in Python, multiple names can correspond to an object, so deleting a name only deletes the connection between the name and its object and does not necessarily delete the object. In fact, all operations that introduce new names use local scope: In particular, import statements and function definitions bind module names or function names into the local scope. (The global statement can be used to indicate that some variables belong to the global name space).

9.3 First-time knowledge of the category
Classes introduce some new syntax, three new object types, and some new semantics.

9.3.1 Class definition syntax
The simplest form of class definition is as follows:

class class name:
<Sentence-1>
    .
    .
    .
<Sentence-N>


Just like function definitions (def statements), class definitions must be executed before they can take effect. (You can even place the class definition in a branch of an if statement or in a function). When used in actual use, the statements in the class definition are usually function definitions, and other statements are also allowed and sometimes useful - we will mention this later. Function definitions within a class usually have a special form of independent variable tables, dedicated to method calling conventions - this will be discussed in detail later.

After entering the class definition, a new namespace is generated, which is used as a local scope - so all assignments to local variables enter this new namespace. In particular, function definitions bind the function name to the new function in this name space.

When the function definition ends normally (exits from the end), a class object is generated. This is basically an object that wraps the namespace generated by the class definition; we will learn more about class objects in the next section. The original local scope (the one that works before entering the class definition) is restored, where the class object is bound to the name specified in the class object definition header.

9.3.2 Class Objects
Class objects support two operations: attribute reference and instantiation. The format of attribute reference is the same as other attribute reference formats in Python, that is. Valid attribute names include all names in the class name space when generating the class object. So, if you define the class like this:

class MyClass:
    "A simple example class"
    i = 12345
    def f(x):
        return 'hello world'


Then sum is both valid attribute references, returning an integer and a function object respectively. You can also assign values ​​to class attributes, so you can change the value of the attribute to the assignment.

__doc__ is also a valid property. It is read-only and returns the document string of the class: "A simple example class".

Class instantiation uses function notation. Just treat this class object as a function without independent variables and return a class instance. For example (assuming the above class):

    x = MyClass()

A new instance of the class can be generated and the instance object is assigned to the local variable x.

9.3.3 Instance Object
How do we use instance objects? Class instances only know how to refer to attributes. There are two valid attributes.

The first type of attribute is called data attributes. Data attributes are equivalent to "instance variables" in Smalltalk and "data members" in C++. Data members do not need to be declared, nor do they need to exist in the class definition. Like local variables, it will be generated as soon as it is assigned. For example, if x is an instance of the MyClass class above, the following example will display the value 16 without leaving any trace:

 = 1
while  < 10:
     =  * 2
print 
del 


The second class attribute reference that a class instance can understand is a method. A method is a function that "belongs" to an object. (In Python, methods are not only used for class instances: other object types can also have methods, for example, list objects also have append, insert , remove, sort, etc. However, unless otherwise specified here, we use methods to specifically refer to methods of class instance objects).

The valid method name of a class object depends on its class. By definition, all types of a class define the corresponding methods of its instance for function object properties. So in our example y, it is a valid method reference, because MyClass is a function; it is not a method reference, because it is not. But it is not the same thing - it is a method object rather than a function object.

9.3.4 Method Object
Methods are generally called directly, for example:

    ()

In our example, this will return the string ‘hello world’. However, you can also not call the method directly: it is a method object, which can be saved and called. For example:

xf = 
while 1:
    print xf()


"hello world" will be displayed constantly.

What exactly happened when calling a method? You may have noticed that the() call has no arguments, and the function f has an argument when it is called. What's going on with that independent variable? If Python calls a function that requires arguments, it will definitely cause exception errors - even if that argument does not need to be used...

In fact, you can guess the answer: the difference between a method and a function is that the object is automatically passed to the method as the first independent variable of the method. In our example, calling() is equivalent to calling (x). Generally speaking, calling a method with n independent variables is equivalent to inserting the object to the method into front of the first independent variable and calling the corresponding function.

If you don't understand how methods work, it may be helpful to take a look at the implementation of methods. When referring to an instance property that is not a data property, its class is searched. If the property name is a valid function object, a method object is generated, wrapping the instance object (pointer) and the function object: this is the method object. When the method object is called with an argument table, it is then unwrapped, and the instance object and the original argument table are combined to form a new argument table, and the function is called with this new argument table.

9.4 Some Instructions
Data attributes overwrite method attributes when the names are the same; in order to avoid accidental name conflicts, this will cause difficult-to-find errors in large programs, it is best to distinguish method names from data names according to some naming convention. For example, all method names start with capital letters, all data attribute names start with a unique string (or just an underscore), or method names use verbs and data names use nouns.

Data attributes can be referenced by methods or by ordinary users ("customers"). In other words, classes cannot be used to construct abstract data types. In fact, there is no way in Python to force data hiding—this is based on conventions. (On the other hand, the implementation of Python is written in C, which can completely hide implementation details and control object access if necessary; Python extension modules written in C also have the same characteristics).

Customers should be careful with data attributes themselves - customers may destroy the consistency of class data maintained by class methods by arbitrarily changing the data attributes of class objects. Note that customers can add new data attributes to the instance object at will without affecting the effectiveness of the method - here, effective naming conventions can save a lot of trouble.

There is no abbreviation method to access the data attributes (or other methods) of this object from within a method. I think this actually increases the readability of the program: local variables and instance variables are not confused in the method definition.

Customarily, the first independent variable of the method is called self. This is just an idiom: the name self has no special meaning in Python. However, because users use this convention, violating this convention may make it difficult for other Python programmers to read your program, and you can imagine that some types of browsing programs will rely on this convention).

Any function object that is a class attribute defines a method for an instance of that class. The definition of a function does not necessarily have to be inside the class definition: just assign a function object to a local variable within the class. For example:

# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)
 
class C:
    f = f1
    def g(self):
        return 'hello world'
    h = g


Now f, g and h are properties of class C and point to function objects, so they are methods of instances of C - where h is exactly equivalent to g. Note that we should avoid this usage in order not to mislead readers.

Methods can use self arguments representing the object to which they belong to reference other methods of this class, such as:

class Bag:
    def empty(self):
         = []
    def add(self, x):
        (x)
    def addtwice(self, x):
        (x)
        (x)


The instantiation operation ("call" a class object) generates an empty object. Many classes require the generation of classes with known initial knowledge states. To this end, the class can define a special method called __init__(), such as:

    def __init__(self):
        ()


After a class defines the __init__() method, the __init__() method will be automatically called for the newly generated class instance when the class is instantiated. So in the Bag example, a new initialized instance can be generated using the following program:

    x = Bag()

Of course, the __init__() method can have independent variables, which can achieve greater flexibility. In this case, the argument specified during class instantiation is passed to the __init__() method. For example:

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...          = realpart
...          = imagpart
... 
>>> x = Complex(3.0,-4.5)
>>> , 
(3.0, -4.5)


Methods can refer to global names like normal functions. The global scope of a method is a module containing the class definition. (Note that the class itself is not used as a global scope!) Although we rarely need to use global data in methods, global scope still has many legal uses: for example, functions and modules that import global scopes can be used by methods, and functions and methods defined in the same module can also be used by methods. Classes containing this method are generally also defined in this global scope. In the next section, we will see why a method needs to reference its own class!

9.5 Inheritance
Of course, if a language does not support inheritance, there is no "class". The definition method of exporting classes is as follows:

class export class name (base class name):
<Sentence-1>
    .
    .
    .
<Sentence-N>


Where the "base class name" must be defined in the scope containing the export class definition. In addition to giving the base class name, you can also give an expression, which is useful when the base class is defined in other modules, such as:

class export class name (module name. base class name):

The method of exporting class definitions is the same as the method of running base class. The generated class object is, the base class is memorized. This is used to solve attribute reference: if the required attribute is not found in the class, search in the base class. If the base class has a base class, this rule is recursively applied to higher classes.

There are no special rules for exporting classes when instantiating. "Export class name()" produces a new instance of the class. Method reference is solved in this way: search for the corresponding class attributes, search for the base class step by step if necessary, and if a function object is found, it is a valid method reference.

Exporting a class can override the base class's methods. Because the method does not have any special permissions when calling other methods of the same object, if a method in the base class calls another method of the same base class, the method in the export class may call the method that has been rewritten by the export class. (For C++ programmers: all methods in Python are "virtual functions").

The method overridden in the export class may be to expand the base class's method with the same name instead of completely replacing the original method. It is very simple to export the class to call the base class with the same name: "Basic class name. Method name (self, independent variable table)". This approach is also occasionally useful for class users. (Note that this is only used when the base class is defined or imported in the same global scope).

8.5.1 Multiple Inheritance
Python also supports limited multiple inheritance. The class definition formats with multiple base classes are as follows:

class export class name (base class 1, base class 2, base class 3):
<Sentence-1>
    .
    .
    .
<Sentence-N>


Regarding multiple inheritance, you only need to explain how to resolve class attribute references. Class attribute references are depth-first and are carried out from left to right. Therefore, if no attribute is found in the export class definition, first look in base class 1, and then (recursively) look in base class 1. If none of them are found, look in base class 2, and continue like this.

(For some people, width-first-find in base class 2 and 3 and then in base class 1's base class - it looks more natural. However, this requires you to know clearly whether the attribute is defined in base class 1 itself or in its base class when determining the properties of base class 1 conflict with base class 2. The depth-first rule does not distinguish whether a property of base class 1 is directly defined or inherited).

Obviously, using multiple inheritance without constraints will create a nightmare for program maintenance, because Python only depends on habitual conventions to avoid name conflicts. A well-known problem with multiple inheritance is when the exported class has two base classes that happen to be exported from the same base class. Although it is easy to think of the consequences of this situation (the instance variable or data attribute is used by a common base class in the instance), it is unclear what the use of this approach is.

9.6 Private variables
Python has partial support for private class members. Any identifier of the form like __spam (with at least two leading underscores, at most one end underscore) is currently replaced with _classname__spam, where classname is the result of removing the leading underscore from the class name of the class. This disturbance regardless of the syntax location of the identifier, so it can be used to define instances, variables, methods, and global variables that are private, and even save instances of other classes that are private to this class. Truncation may occur if the messed-up name exceeds 255 characters. Don't mess around outside the class or when the class name has only underscore.

The purpose of name messing is to give a class a simple way to define "private" instance variables and methods. You don't need to worry that other classes will define variables with the same name, nor do you have to worry that code outside the class messes up the instance's variables. Note that the chaos rules are mainly to avoid accidental errors. If you must do it, you can still access or modify private variables. This is even useful, such as debugging programs requires private variables, which is also one of the reasons why this vulnerability is not blocked. (Small error: Exporting the class and the base class can use the private variables of the base class by taking the same name).

Note that the code passed to exec, eval() or evalfile() does not consider the class name of the class that calls them to be the current class, which is similar to the case of global statements, where global functions are limited to code compiled together bytes. The same limitations apply to getattr() , setattr() and delattr(), as well as when accessing __dict__ directly.

The class in the following example implements its own __getattr__ and __setattr__ methods, saving all attributes in a private variable, which is feasible in both old and new versions of Python:

class VirtualAttributes:
    __vdict = None
    __vdict_name = locals().keys()[0]

    def __init__(self):
        self.__dict__[self.__vdict_name] = {}

    def __getattr__(self, name):
        return self.__vdict[name]

    def __setattr__(self, name, value):
        self.__vdict[name] = value


9.7 Supplement
Sometimes we want to have a type similar to Pascal's "record" or C's "struct" that can combine several famous data items together. An empty class can meet this need well, such as:

class Employee:
    pass
 
john = Employee() # Generate an empty employee record
 
#Fill the records in various fields
 = 'John Doe'
 = 'computer lab'
 = 1000


A Python program that requires some abstract data type as input can often accept a class as input, which simply mimics the method of the data type to be entered. For example, if you have a function that formats data in a file object, you can define a class with methods read() and readline(). This class can be input from a file instead of inputting it from a string buffer, using this class as an argument.

The instance method object also has properties: m.im_self is the instance to which the method belongs, and m.im_func is the function object corresponding to the method.

9.7.1 The exception can be a class
User-defined exceptions can be classes in addition to string objects. This defines an extensible hierarchical class exception structure.

There are two new valid formats for the raise statement:

raise class, instance
 
Raise instance


In the first form, an instance of "class" must be an instance of "class" or an instance of an exported class of "class". The second form is

raise instance.__class__, instance

abbreviation of . Except statements can list classes in addition to string objects. If the class listed in the execpt clause is an exception class or base class that occurs, it matches (in reverse, it is not correct - if the exception occurs in except, if the class is exported, it does not match when it belongs to the base class). For example, the following program will show B, C, and D:

class B:
    pass
class C(B):
    pass
class D(C):
    pass
 
for c in [B, C, D]:
    try:
        raise c()
    except D:
        print "D"
    except C:
        print "C"
    except B:
        print "B"


Note that if the order of the except clause is reversed ("except B" is placed first), the program will display B, B, B, B - because the first matching except clause is raised.

When the exception that is not processed is a class, the class name is displayed in the error message, followed by a colon and a space, and finally the result of the instance converting it into a string using the built-in function str().
Previous page12345678910Next pageRead the full text