元编程听起来可能是新的,但是如果用户曾经使用过 Decorators 或元类,他们已经在他们的项目中使用了元编程。因此,我们可以说元编程是用于操纵程序的程序。
在本教程中,我们将讨论元类及其用途,以及它们的替代方法。由于这是 Python 的高级话题,建议用户在开始本教程之前,先修改一下 Python 中的装饰者和 Python 中的 OOPS 概念的基本概念。
元类
在 Python 中,每个模块或函数都与某种类型相关联。例如,如果用户有一个整数值的变量,那么它就与一个“int”类型相关联。用户可以通过使用 type()方法知道任何东西的类型。
示例:
number = 13
print("Type of number is:", type(num))
list = [3, 7, 8]
print("Type of list is:", type(list))
name = "Mark Jackson"
print("Type of name is:", type(name))
输出:
Type of number is: <class 'int'>
Type of list is: <class 'list'>
Type of name is: <class 'str'>
解释-
Python 中的每种类型都是由类定义的。因此,在上面的例子中,它们是“int”、“list”或“str”类类型的对象,不像 C 语言或 Java 语言中 int、char 和 float 是主要的数据类型。用户可以通过创建该类型的类来创建新类型。例如,我们可以按城市类创建一个新的对象类型。
示例:
class City:
pass
City_object = City()
# now, we will print the type of object of City class
print("Type of City_object is:", type(City_object))
输出:
Type of City_object is: <class '__main__.City'>
Python 中的类也是一个对象,因此,像其他对象一样,它是元类的实例。元类是一种特殊的类类型,负责创建类和类对象。因此,例如,如果用户想要找到“City”类的类型,他们会发现它是“type”
示例:
class City:
pass
# now, we will print the type of the City class
print("Type of City class is:", type(City))
输出:
Type of City class is: <class 'type'>
由于类也是一个对象,我们可以修改它们。例如,用户可以像处理其他对象一样,在类中添加或减去字段或函数。
示例:
# First, we will define the class without any using any class methods or variables.
class City:
pass
# now, we will define the method variables
City.a = 65
# we will now, define the class methods
City.foo = lambda self: print('Pune')
# then, we will create the object
userobject = City()
print(userobject.a)
userobject.foo()
输出:
65
Pune
我们可以将整个元类总结为:
元类用于创建类,这些类可以创建对象。
元类负责创建类,因此用户可以通过插入代码或额外的操作来修改类的创建方式,从而编写自己定制的元类。通常,用户不需要定制的元类,但是在特殊情况下,它是必要的。
有一些问题可以通过使用元类或非元类来解决,但是也有一些情况下只使用元类来解决它们。
如何创建定制的元类
为了创建定制的元类,用户定制的元类必须继承类型元类,并且通常重写,例如:
- new (): new ()函数是 int()函数之前的类。这用于创建对象并返回它。用户可以覆盖此功能来控制对象的创建方式。
- int(): 函数用于初始化创建的对象,该对象作为参数传递。
用户可以直接使用 type()方法创建类。可以通过以下方式调用 type()方法:
- 如前面的例子所示,用户可以用一个参数调用它,它将返回类型。
- 用户可以用三个参数调用它。它将创建类。其中传递了以下参数:
- 班级名称
- 传递具有由类继承的基类的元组
- 类字典:这将作为类的本地命名空间,用函数和变量填充。
示例:
def City_method(self):
print("This is City class method!")
# we will create the base class
class Base:
def userfunction(self):
print("This is a inherited method!")
# we will create the city class dynamically by using
# type() function.
City = type('City', (Base, ), dict(a = "Mark Jackson", user_method = City_method))
# now, we will print the type of City
print("The Type of City class: ", type(City))
# we will create the instance of City class
City_object = City()
print(" The Type of City_object: ", type(City_object))
# we will now call the inherited method
City_object.userfunction()
# we will call the City class method
City_object.user_method()
# at last we will print the variable
print(City_object.a)
输出:
The Type of City class: <class 'type'>
The Type of City_object: <class '__main__.City'>
This is a inherited method!
This is City class method!
Mark Jackson
现在,让我们看看如何在不直接使用 type()函数的情况下创建元类。例如,我们将创建名为 MultiBases 的元类,它将检查正在创建的类是否继承自多个基类。如果是这样,它将引发错误。
示例:
# Inside the metaclass
class MultiBases(type):
# we will override the __new__() function
def __new__(city, city_name, bases, citydict):
# if the number of base classes are greator than 1
# it will raise an error
if len(bases)>1:
raise TypeError("There are inherited multiple base classes!!!")
# else it will execute the __new__() function of super class, that is
# it will call the __init__() function of type class
return super().__new__(city, city_name, bases, citydict)
# the metaclass can be specified by using 'metaclass' keyword argument
# now we will use the MultiBase class for creating classes
# this will be propagated to all subclasses of Base
class Base(metaclass = MultiBases):
pass
# this will raise no error
class P(Base):
pass
# this will raise no error
class Q(Base):
pass
# this will raise no error
class R(Base):
pass
# This will raise an error!
class S(P, Q, R):
pass
输出:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-409c90c285d5> in <module>
29 pass
30 # This will raise an error!
---> 31 class S(P, Q, R):
32 pass
<ipython-input-2-409c90c285d5> in __new__(city, city_name, bases, citydict)
6 # it will raise an error
7 if len(bases)>1:
----> 8 raise TypeError("There are inherited multiple base classes!!!")
9
10 # else it will execute the __new__() function of super class, that is
TypeError: There are inherited multiple base classes!!!
如何用元类解决这个问题
有一些问题,用户可以通过使用元类和装饰器来解决。但是有些问题只能用元类来解决。比如,用户想要调试类函数,他们想要的是,每当执行类函数时,它都会在执行它们的主体之前打印出它们的完全限定名。
示例:
from functools import wraps
def debugg(funct):
'''decorator for debugging passed function'''
@wraps(funct)
def wrapperr(*args, **kwargs):
print("The full name of this Function:", funct.__qualname__)
return funct(*args, **kwargs)
return wrapperr
def debug_methods(clas):
'''class decorator make use of debug decorator
for debuging the class functions '''
# now we will check in the class dictionary for any callable(function)
# if there is any, replace it with debugged version
for key, value in vars(clas).items():
if callable(value):
setattr(clas, key, debugg(value))
return clas
# sample class
@debugmethods
class Calculator:
def add(self, p, q):
return p+q
def mul(self, p, q):
return p*q
def div(self, p, q):
return p/q
user_cal = Calculator()
print(user_cal.add(5, 8))
print(user_cal.mul(6, 7))
print(user_cal.div(21, 7))
输出:
The full name of this method: Calculator.add
13
The full name of this method: Calculator.mul
42
The full name of this method: Calculator.div
3.0
解释-
上面的解决方案运行良好,但是有一个问题,那就是用户想要将装饰器方法应用到继承了“Calculator”类的所有子类。因此在这种情况下,用户必须将 decorator 方法分别应用于每个子类,就像我们在上面的例子中对 Calculator 类所做的那样。
现在,实际的问题是这个类可能有很多子类,将 decorator 方法单独应用于每个子类是一个具有挑战性和耗时的过程。因此,为了解决这个问题,用户必须确保每个子类都有这个调试属性,他们应该寻找基于元类的解决方案。
示例:
我们将正常地创建类,然后立即使用调试方法装饰器来结束:
from functools import wraps
def debugg(funct):
'''decorator for debugging passed function'''
@wraps(funct)
def wrapperr(*args, **kwargs):
print("The full name of this Function:", funct.__qualname__)
return funct(*args, **kwargs)
return wrapperr
def debug_methods(clas):
'''class decorator will make use of the debug decorator
to the debug class '''
for key, value in vars(clas).items():
if callable(value):
setattr(clas, key, debugg(value))
return clas
class debug_Meta(type):
'''meta class which feed created class object
to debug_method for getting debug functionality
enabled objects'''
def __new__(clas, clasname, bases, clasdict):
object = super().__new__(clas, clasname, bases, clasdict)
object = debug_methods(object)
return object
# the base class with metaclass 'debug_Meta'
# now all the subclass of this will have the applied debugging function
class Base(metaclass = debug_Meta):pass
# now, we will inherite the Base
class Calculator(Base):
def add(self, p, q):
return p+q
#and then, we will inherite the Calculator
class Calculator_adv(Calculator):
def mult(self, p, q):
return p*q
# Now Calculator_adv object will show
# the behaviour og debugging
user_cal = Calculator_adv()
print(user_cal.add(3, 7))
user_cal = Calculator_adv()
print(user_cal.mult(3, 7))
输出:
The full name of this Function: Calculator.add
10
The full name of this Function: Calculator_adv.mult
21
用户何时应该使用元类
用户不经常使用元类,因为元类主要用于复杂的情况。但是很少有用户可以使用元类的情况:
- 如上例所示,元类用于向下生成继承层次结构。这也将影响所有的子类。如果用户有这样的情况,那么他们可以使用元类。
- 如果用户想自动改变类,他们可以在创建元类时使用它。
- 如果用户是 API 开发人员,他们可以为此使用元类。
结论
在本教程中,我们讨论了元类,如何定制元类,以及用户如何使用它们来解决问题和复杂的编程及其替代方案。