major=None school="哈尔滨工业大学"#类变量,被所有学生实例共有的属性或者特征 def __init__(self,name,age,major): #构造名字与年龄的init方法 self.name=name self.age=age self.major = major def Name_Age(self): #构造姓名与年龄的函数,分别传入self对应的年龄与姓名参数 print("我叫" + self.name+ "," + "今年" + str(self.age) + "岁," + "主修专业" + self.major + "。") #遇到(,。文字等)都加“ ” def School(self): #再构造一个函数来说明学生的学校信息,可提前设定好,或者重新构造一个 print("来自",Stu.school) def Total(self): #最后构造一个函数来互相调用上面的两个函数Name_Age和School Stu.Name_Age(self) Stu.School(self) ####################################################### #先整体传入参数 stu=Stu("马小云",20,"空气动力学") #传入姓名与年龄 ############################################# #(原始的调用方法)实例化对象进行调用 print("***********************各自函数调用的方法********************************") stu.Name_Age() #调用指定函数 stu.School() #再调用其他函数 ############################################# #(函数之间互相调用之后的方法)使用类中函数调用其他函数 print("***********************类中方法互相调用函数********************************") stu.Total() #导出结果 #######################################################

执行结果:

  • 你可以自由的、动态的修改/增加/删除 类的或者实例中的方法或者属性

  • 批量的对某些方法使用decorator,而不需要每次都在方法的上面加入@decorator_func

  • 当引入第三方库的时候,如果该库某些类需要patch的时候可以用metaclass

  • 可以用于序列化(参见yaml这个库的实现,我没怎么仔细看)

  • 提供接口注册,接口格式检查等

  • 自动委托(auto delegate)

  • more...

  • (二)metaclass的相关知识

  • what is metaclass?
  • 1.1 在wiki上面,metaclass是这样定义的:In object-oriented programming,

    a metaclass is a class whose instances are classes.

    Just as an ordinary class defines the behavior of certain objects,

    a metaclass defines the behavior of certain classes and their instances.

    也就是说metaclass的实例化结果是类,而class实例化的结果是instance。我是这么理解的:

    metaclass是类似创建类的模板,所有的类都是通过他来create的(调用 new ),这使得你可以自由的控制

    创建类的那个过程,实现你所需要的功能。

    (三)metaclass基础

  • 一般情况下, 如果你要用类来实现metaclass的话,该类需要继承于type,而且通常会重写type的 new 方法来控制创建过程。
  • 当然你也可以用函数的方式(下文会讲)

  • 在metaclass里面定义的方法会成为类的方法,可以直接通过类名来调用
  • (四)如何使用metaclass

    4.1 用类的形式

    4.1.1 类继承于type, 例如: class Meta(type):pass

    4.1.2 将需要使用metaclass来构建class的类的 metaclass 属性(不需要显示声明,直接有的了)赋值为Meta(继承于type的类)

    4.2 用函数的形式

    4.2.1 构建一个函数,例如叫metaclass_new, 需要3个参数:name, bases, attrs,

    name: 类的名字

    bases: 基类,通常是tuple类型

    attrs: dict类型,就是类的属性或者函数

    4.2.2 将需要使用metaclass来构建class的类的 metaclass 属性(不需要显示声明,直接有的了)赋值为函数metaclas_new

    (五) metaclass 原理

    5.1 basic

    metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了type的 new 方法为这个类分配内存空间,创建

    好了之后再调用type的 init 方法初始化(做一些赋值等)。所以metaclass的所有magic其实就在于这个 new 方法里面了。

    说说这个方法: new (cls, name, bases, attrs)

    cls: 将要创建的类,类似与self,但是self指向的是instance,而这里cls指向的是class

    name: 类的名字,也就是我们通常用类名. name 获取的。

    bases: 基类

    attrs: 属性的dict。dict的内容可以是变量(类属性),也可以是函数(类方法)。

    所以在创建类的过程,我们可以在这个函数里面修改name,bases,attrs的值来自由的达到我们的功能。这里常用的配合方法是

    getattr和setattr(just an advice)

    二、类与类之间调用函数

    下面实现python中在一个类中调用另一个类的函数方法

    #实现类与类中的函数调用
    class Person: #构造第一个类
        def __init__(self,name): #先定义init方法,指定参数
            self.name = name
        def go_to(self,position,type): #构造的函数
            :param position:地名参数
            :param type:去的方法
            :return:
            print('去:' + position)
            #此处调用另一个类:Car类的方法
            type.run()
    class Car: #构造第二个类
        def run(self):
            print('走你~')
    call = Person('小王')
    #为了让小王调用Car类中的run()方法,需实例化出一辆车
    toll = Car()
    #通过将Car类的对象toll传给call这个对象,从而达到调用toll方法run()的目的
    call.go_to('上海',toll)
    

    或者下面来一个号理解的例子

    #实现调用类与类之间的函数方法
    import numpy as np
    class Calculate(object): #构造第一个类
        def add(self, a, b): #构造加法函数
            a1 = np.add(a,  b)
            return a1
        def multiply(self,a, b):#构造乘法函数
            a2= np.multiply(a, b)
            return a2
        def reduce(self,a,b):#构造减法函数
            a3 = np.subtract(a, b)
            return a3
        def division(self,a, b):#构造除法函数
            a4 = np.divide(a, b)
            return a4
    class Total_grade(object):#构造第二个类
        def __init__(self): #构建一个init方法
            self.Calculate = Calculate() #该方法调用第一个类的方法
        def get_id(self,id): #身份证号或者什么号都行
            return id
        def get_name(self, grade):#名称参数
            return grade
        def get_totalgrade(self, c, d):#调用第二类方法 下面调用第一类方法
            return self.Calculate.add(c, d)#加法或者其他
    s = Total_grade()
    print(s.get_id('1234567890'))
    print(s.get_name('张飞'))
    print(s.get_totalgrade(2019,2020))
    

    执行结果:

    class MyOuter:#构造外部类 age=19 #定义一个参数,这里暂时用不上,只是想说明类开始也可传入恒定参数 def __init__(self,name):#构造一个init函数 self.name=name class MyInner: #构造内部法类 def __init__(self,inner_name): #类似的构造一个init函数 self.inner_name=inner_name ########################################################################### out=MyOuter('王小二在门外(外部类)') #实例化调用外部的类 ##################################### #直接实例化内部类调用 inner=out.MyInner('王小二在房间里inner(内部类)') #在从外部进入内部的类的函数 print(inner.inner_name) #将实例中的参数传入:王小二在房间里inner(内部类)=inner_name ########################################################################## #直接实例化外部类调用 out2=MyOuter #外部类参数 print(out2.age) #调用外部类方法

    2、嵌套类之间的互相调用

    内部类调用外部类的类属性和类方法

    #实现内部类调用外部类的类属性和类方法:这里是类属性和类方法
    class MyOuter:
        age=19
        def __init__(self,name):
            self.name=name
            :#描述:classmethod 修饰符对应的函数不需要实例化,
            :不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,
            :可以来调用类的属性,类的方法,实例化对象等。
        @classmethod
        def outer_class_method(cls):
            print('我是外部类的类方法')
        class MyInner:
            def __init__(self,inner_name):
                self.inner_name=inner_name
            def inner_method(self):
                print('我是内部类的对象方法')
                MyOuter.outer_class_method()
    out=MyOuter('在门外')
    inner=out.MyInner('在屋里inner')
    inner.inner_method() #执行调用内部函数
    

    3、内部类调用外部对象的对象属性和方法

    class MyOuter:
        age=24
        def __init__(self,name):
            self.name=name
        @classmethod
        def outer_class_method(cls):
            print('我是外部类的类方法')
        def outer_obj_method(self):
            print('我是外部类对象的绑定方法')
        class MyInner:
            def __init__(self,inner_name,obj):
                self.inner_name=inner_name
                self.obj=obj
            def inner_method(self):
                print('我是内部类的对象方法')
                MyOuter.outer_class_method()
                self.obj.outer_obj_method()
    out=MyOuter('外部类')
    inner=out.MyInner('从外部类进入内部类inner',out)
    inner.inner_method() #调用方法