Classes are also objects
In most programming languages, a class is a set of code snippets that describe how to generate an object, which is also true in python.
class ObjectCreator: pass my_object = ObjectCreator() print(my_object) """ //Output results: <__main__.ObjectCreator object at 0x037DACD0> """
But python's classes are more than that. Classes are also objects.
class ObjectCreator: pass
The above code segment will create an object in memory called ObjectCreator. This object (class object creator) has the ability to create objects (instance objects), but it is still essentially an object, so you can do the following for it:
- Copy a variable to it
- Copy it
- Add attributes to it
- Pass it as a function parameter
Sample code:
class ObjectCreator: pass # Assign it to a variable a = ObjectCreator print(a) # <class '__main__.ObjectCreator'> # Transfer as a function parameter def echo(o): print(o) echo(ObjectCreator) # <class '__main__.ObjectCreator'>
Creating classes dynamically
Because classes are also objects, they can be created dynamically at runtime using class keywords.
def choose_class(name): if name == 'foo': class Foo(object): pass return Foo # Returns classes, not instances of classes else: class Bar(object): pass return Bar MyClass = choose_class("foo") print(MyClass) # Print class object # Output results <class '__main__.choose_class.<locals>.Foo'> print(MyClass()) # Print instance objects # Output results <__main__.choose_class.<locals>.Foo object at 0x0368CFD0>
Create classes using type
We know what the type of this object is through type(), and it has a completely different function, creating classes dynamically.
type can accept a description of a class as a parameter, and then return a class.
Grammar:
Type (class name, tuple of parent class name (null for inheritance), dictionary containing attributes)
MyClass = type("MyClass",(),{}) print(MyClass) # Output results: <class '__main__.MyClass'>
Using type to create classes with attributes
type accepts a dictionary to define attributes for the class, as follows:
Foo = type("Foo",(),{'bar':True})
Equivalent to
class Foo: bar = True
Create inherited subclasses using type
Next to the above code, we have created a Foo class, and now we will create a subclass of it.
FooChild = type("FooChild",(Foo,),{}) print(FooChild.bar) # # The bar attribute is inherited from Foo # Output results: True
Be careful:
- The second parameter of type is the name of the parent class in the tuple, not the string.
- The added attributes are class attributes, not instance attributes.
Create classes with methods using type
Eventually you will want to add methods to your classes. Just define a function with the appropriate signature and assign it as an attribute.
Adding Instance Method
def test_f(self): print("Instance method added") Foo = type("Foo",(),{"test_f":test_f}) f = Foo() f.test_f() # Output results: //Instance method added
Adding static methods
@staticmethod def test_static(): print("Additional static methods") Foo = type("Foo",(),{"test_static":test_static}) Foo.test_static() Foo.test_static() # Output results: //Additional static methods
Adding class methods
@classmethod def test_class(cls): print("Additional class methods") Foo = type("Foo",(),{"test_class":test_class}) Foo.test_class() # Output results: //Additional class methods
What is metaclass
Metaclasses are the "things" used to create classes. Metaclasses are used to create class objects, and metaclasses are classes of classes.
It can be understood as follows:
MyClass = MetaClass() # Creating class objects using metaclasses MyObject = MyClass() # Creating instance objects using class objects
The type function is actually a metaclass. Type is the metaclass of all classes created in Python. It can be viewed through the _class_ attribute. The function of _class_ is to view the class of the object, which can be nested.
class A: pass print(A.__class__) a = A() print(a.__class__) print(a.__class__.__class__) # Output results: <class 'type'> <class '__main__.A'> <class 'type'>
As you can see, the final object class is the type metaclass.
Everything in Python, notice, I mean everything -- objects. This includes integers, strings, functions, and classes. They are all objects, and they are all created from a class, which is type.
Integer:
age = 18 print(age.__class__) print(age.__class__.__class__) # Output results: <class 'int'> <class 'type'>
Character string:
name = "Zhang San" print(name .__class__) print(name .__class__.__class__) # Output results: <class 'str'> <class 'type'>
Function:
def f(): pass print(f.__class__) print(f.__class__.__class__) # Output results: <class 'function'> <class 'type'>
Custom metaclass
Let's first look at the metaclass attribute, which is used to specify a metaclass. python will look for the metaclass attribute in the defined class, and if it is not found, it will look for the metaclass attribute in its parent class and so on. If it is found, python will use it to create class objects, and if it is not found, it will use the built-in type to create the class.
In metaclass, you can put type or anything that uses type or subclassed type.
The main purpose of custom classes is:
- Interception class creation
-
Modifying classes
Implementing a custom metaclass with functions
Function: To capitalize class attribute names that are not _____________.
def upper_attr(future_class_name: str,future_class_parents: tuple,future_class_attr: dict): newAttr = {} for key,value in future_class_attr.items(): if not key.startswith("__"): newAttr[key.upper()] = value return type(future_class_name,future_class_parents,newAttr) class Foo(metaclass=upper_attr): name = "Zhang San" age = 18 hasattr(Foo,"name") # Determine whether there is such a property False hasattr(Foo,"NAME") # True hasattr(Foo,"age") # False hasattr(Foo,"AGE") # True
Implementing a custom metaclass by inheriting type
Function: Ibid.
class MyMetaClass(type): def __new__(cls, class_name: str, class_parents: tuple, class_attr: dict): newAttr = {} for key, value in class_attr.items(): if not key.startswith("__"): newAttr[key.upper()] = value # Method 1: Create class objects by'type' # return type(class_name, class_parents, newAttr) # Method 2: Reuse type. _new_ method # That's basic OOP programming, no magic. # return type.__new__(cls, class_name, class_parents, newAttr) # Method 3: Using super method return super(MyMetaClass, cls).__new__(cls, class_name, class_parents, newAttr) class Foo(metaclass=MyMetaClass): name = "Zhang San" age = 18 hasattr(Foo,"name") # Determine whether there is such a property False hasattr(Foo,"NAME") # True hasattr(Foo,"age") # False hasattr(Foo,"AGE") # True
The effect is the same as above.