“Class” is a template, and the template packages many “functions” for use. This post introduces the members of Python classes, member modifiers, and the special members of classes.

Class members

The members of a class can roughly be divided into three categories: fields, methods and properties

Note: among all members, only the content of ordinary fields is stored in objects, that is, however many objects are created from this class, there will be that many ordinary fields in memory. The other members are all stored in the class, that is, no matter how many objects there are, only one copy is created in memory.

Fields

Fields include ordinary fields and static fields; ordinary fields belong to objects and static fields belong to the class.

class World:

    string='earth'  #static field
    def _init_(self,name):
        self.name='name'  #ordinary field

obj=World('China')
#directly access the ordinary field
print(obj.name)

#directly access the static field
world.string

From the code above we can see that ordinary fields are accessed through objects and static fields through the class. That is, static fields belong to the class while ordinary fields belong to objects, and the class does not store the ordinary fields of objects.

When creating objects from a class, if every object has the same field, use a static field

Methods

Methods include: ordinary methods, static methods and class methods. All three kinds of methods belong to the class in memory; the difference is in how they are called.

  • Ordinary methods: called by objects; at least one self parameter; when an ordinary method is executed, the object calling the method is automatically assigned to self;

  • Class methods: called by the class; at least one cls parameter; when a class method is executed, the class calling the method is automatically copied to cls;

  • Static methods: called by the class; no default parameter;

class Foo:
    def _init_(self,name):
        self.name-name

    #define an ordinary method with at least one self parameter
    def ord_func(self):
        print('ordinary method')

    #define a class method with at least one cls parameter
    @classmethod
    def class_func(cls):
        print('class method')

    #define a static method with no default parameter
    @staticmethod
    def static_func():
        print('static method')

#call the ordinary method
f=Foo()
f.ord_func()

#call the class method
Foo.class_func()

#call the static method
Foo.static_func()

These methods have in common that they all belong to the class (not to objects), so only one copy is kept in memory. What differs is how the methods are called, and the parameters passed when calling them.

Properties

Basic use of properties

class Foo:
    def func(self):
        pass

    @property  #define a property
    def prop(self):
        pass

foo_obj=Foo()
foo_obj.func()
foo_obj.prop  #call the property

A few points to note about defining and calling properties:

  • When defining, the @property decorator is added on top of an ordinary method;
  • When defining, a property has only one self parameter;
  • When calling, no parentheses are needed;
  • Method: foo_obj.func();
  • Property: foo_obj.prop

A property is derived from a method; if there were no properties in Python, methods could fully replace them.

The existence of properties can create the illusion of accessing a field.

The function of a Python property is: a series of logical computations are carried out inside the property, and the result of the computation is finally returned.

Two ways of defining properties:

  • Decorator, that is, applying a decorator to a method
  • Static field, that is, defining in the class a static field whose value is a property object

Decorator approach: apply the @property decorator to an ordinary method of the class

For old-style classes, there is one kind of @property decorator

class Goods:
    @property
    def price(self):
        return "four yuan"

obj=Goods()
result=obj.price  #automatically executes the price method decorated with @property and obtains its return value

For new-style classes, there are three kinds of @property decorators

class Goods(object):
    @property
    def price(self):
        print('@property')

    @price.setter
    def price(self,value):
        print('@price.setter')

    @price.deleter
    def price(self):
        print('@price.deleter')

obj=Goods()

obj.price  #automatically executes the price method decorated with @property and obtains its return value

obj.price=890  #automatically executes the price method decorated with @property and assigns 890 to the method's parameter

del obj.price  #automatically executes the price method decorated with @property

From the above we can see: a property in an old-style class has only one access mode, corresponding to the method decorated with @property; a property in a new-style class has three access modes, corresponding respectively to the three methods decorated with @property, @method_name.setter and @method_name.deleter

Since a new-style class has three access modes, according to the access characteristics of these properties, the three methods are defined for the same property as: get, set and delete.

Static field approach: create a static field whose value is a property object

When creating a property using the static field approach, old-style and new-style classes are no different

class Foo:
    def get_bar(self):
        return 'five yuan'

    BAR=property(get_bar)

obj=Foo()
result=obj.BAR  #automatically calls get_bar and obtains the method's return value
print(result)

The property constructor has four parameters

  • The first parameter is a method name; calling object.property automatically triggers the execution of the method
  • The second parameter is a method name; calling object.property=XXX automatically triggers the execution of the method
  • The third parameter is a method name; calling del object.property automatically triggers the execution of the method
  • The fourth parameter is a string; calling object.property.__doc__ returns it — this parameter is the description of the property
class Foo:
    def get_bar(self):
        return 'five yuan'

    # requires two parameters
    def set_bar(self, value):
        return 'set value' + value

    def del_bar(self):
        return 'five yuan'

    BAR = property(get_bar, set_bar, del_bar, 'description...')
   
obj = Foo()
obj.BAR  #automatically calls the method defined in the first parameter: get_bar

#automatically calls the method defined in the second parameter: set_bar, passing "alex" as the parameter
obj.BAR = "alex"

del Foo.BAR  #automatically calls the method defined in the third parameter: del_bar
obj.BAR.__doc__  #automatically obtains the value set in the fourth parameter: description...

Since creating a property with the static field approach provides three access modes, in the same way, according to the access characteristics of the properties, the three methods are defined for the same property as: get, set and delete

Modifiers of class members

All the members of a class have been described in detail above; for each member of a class there are two forms:

  • Public members, accessible anywhere
  • Private members, accessible only inside the class

Private members and public members are defined differently: when naming a private member, the first two characters are underscores. (Except for special members, for example: __init__, __call__, __dict__ and so on)

class C:
    def __init__(self):
        self.first='public field'
        self._second='private field'

The access restrictions for private members and public members differ:

Static fields

  • Public static fields: accessible by the class; accessible inside the class; accessible in derived classes
  • Private static fields: accessible only inside the class
class C:
    name='public static field'

    def func(self):
        print(C.name)

class B(C):
    def show(self):
        print(C.name)

C.name  #class access

obj=C()
obj.func()  #access inside the class

obj_son=D()
obj_son.show()  #access in a derived class
class C:
    __name='private static field'

    def func(self):
        print(C.__name)

class B(C):
    def show(self):
        print(C.__name)

C.__name  #class access, results in an error

obj=C()
obj.func()  #access inside the class

obj_son=D()
obj_son.show()  #access in a derived class, results in an error

Ordinary fields

  • Public ordinary fields: accessible by objects; accessible inside the class; accessible in derived classes
  • Private ordinary fields: accessible only inside the class

(They can be accessed through object.__class name__private field name, but forcing access to private members is not recommended)

The access to methods and properties is similar to the above, that is: private members can only be accessed inside the class

Special members of classes

In Python there are some members with special meanings, as follows:

  1. __doc__: represents the description information of the class
class Foo:
"""descrptioin...."""
    def func(self):
        pass

print(Foo.__doc__)  #outputs """descrption..."""
  1. __module__ and __class__

    __module__ indicates the module in which the currently operated object is located;

    __class__ indicates what the class of the currently operated object is

  2. __init__: the constructor, which is automatically triggered and executed when the object is created

  3. __del__: the destructor, which is automatically triggered and executed when the object is released from memory

    This method generally does not need to be defined; usually the destructor is automatically triggered by the interpreter during garbage collection.

  4. __call__: adding parentheses after an object triggers execution

    The execution of the constructor is triggered by the created object, that is: object=class_name(); whereas the execution of __call__ is triggered by adding parentheses after the object, that is: object() or class()()

class Foo:
    def __init__(self):
        pass

    def __call__(self,*args,**kwargs):
        print('__call__')

obj=Foo()  #executes __init__
obj()  #executes __call__
  1. __dict__: the members in a class or object

    The ordinary fields of a class belong to objects; the static fields and methods in a class belong to the class

  2. __str__: if a class defines a __str__ method, printing the object outputs the return value of that method by default

class A:
    def __str__(self):
        return 'simplestory'

obj=A()
print(obj)  #output: simplestory
  1. __getitem__, __setitem__, __delitem__

    Used for index operations, denoting getting, setting and deleting data respectively

class A(object):
    def __getitem__(self,key):
        print('__getitem__',key)

    def __setitem__(self,key,value):
        print('__setitem__',key,value)

    def __delitem__(self,key):
        print('__delitem__',key)

obj=A()

result=obj['k1']  #automatically executes __getitem__
obj['k2']='simplestory'  #automatically executes __setitem__
del obj['k1']  #automatically executes __delitem__
  1. __getslice__, __setslice__, __delslice__

    These three methods are used for slice operations, for example on lists

  2. __iter__

    The reason lists, dictionaries and tuples can be iterated with a for loop is that the type internally defines __iter__ a for loop actually iterates over the result of iter

obj=iter([1,2,3,4,5,6,7])

for i in obj:
    print(i)
  1. __new__ and __metcalss__
class Foo(object):
    def __init__(self):
        pass

obj=Foo()  #obj is an object instantiated through the Foo class

Everything in Python is an object According to this theory we can conclude: the obj object is created by executing the constructor of the Foo class, so the Foo class object should also be created by executing the constructor of some class. (The parent class of a class can be checked with the type() function)

#continuing from the code snippet above
print(type(obj))
#output: <class '__main__.Foo'>, meaning the obj object is created by the Foo class

print(type(Foo))
#output: <type 'type'>, meaning the Foo class object is created by the type class

Class creation can in fact be done in two ways:

  • The ordinary way
class Foo(object):
    def func(self):
        print('Hello World!')
  • The special way (the constructor of the type class)
def func(self):
    print('Hello World')

Foo=type('Foo',(object,),{'func':func})
#first parameter of type: class name
#second parameter of type: base classes of the current class
#third parameter of type: the members of the class

A class is produced by instantiating the type class

As for the type class, there is a __metaclass__, used to indicate by what the class is instantiated and created. So we can set a derived class of the type class for __metaclass__, and then all classes created within the scope of __metaclass__ will use the class or function specified by __metaclass__ as the derived class of the type class.