Python-元类

python中一切皆对象,所有的对象都是实例化或者调用类得到。那么我们创建的类也是一个对象,创建类的类就称为元类

class Person(object):

    def __init__(self,name):
        self.name = name

p = Person("jack")
print(p) # <__main__.Person object at 0x0000000000692198>

动态的创建类

"""
定义创建类的函数create_class
如果给create_class传的参数为user,则创建User"""
def create_class(name):
    if name == "user":
        class User(object):
            def __str__(self):
                return "user"
        return User
    elif name == "person":
        class Person(object):
            def __str__(self):
                return "person"
        return Person


myclass = create_class("user")  # User = create_class("user")
obj = myclass()                 # obj = User()
print(obj)                      # user

但这仍然不够灵活,因为你还是要编写整个类的代码,由于类也是对象,所以它们必须是通过什么东西来生成的才对。当你使用class关键字时,Python解释器自动创建这个对象。但就和Python中的大多数事情一样,Python仍然提供给你手动处理的方法。还记得内建函数type吗? 这个古老但强大的函数能够让你知道一个对象的类型是什么,就像这样:

print(type(1)) # <class 'int'>
print(type([2,3,5])) # <class 'list'>

然而type不仅能够查看对象的类型,也能够帮助我们动态的创建类。如下:

# 定义类属性
country = "China"

# 定义魔法方法
def __init__(self,name,age):
    self.name = name
    self.age = age

# 定义实例方法
def speak(self):
    print("%s is speaking" % self.name)

# 定义类方法
@classmethod
def cls_method(cls):
    print("this is %s classmethod" % cls)

# 定义静态方法
@staticmethod
def sta_method():
    print("this is staticmethod")

dic = {"country":country,"__init__":__init__,"speak":speak,"cls_method":cls_method,"sta_method":sta_method}

# 第一个参数为创建类的名称
# 第二个参数为继承父类的元组
# 第三个参数为类的属性,以字典的形式传入,这里在外面定义好了直接传入字典dic
Person = type("Person",(object,),dic)  # 动态创建一个Person类然后赋值给变量Person
print(Person) # <class '__main__.Person'>
print(Person.country) # 访问类属性
p = Person("jack",22) # 实例化
print(p.__dict__) # {'name': 'jack', 'age': 22}
print(p.name) # 访问实例属性
p.speak() # 调用实例方法
p.cls_method() # 调用类方法
p.sta_method() # 调用静态方法

函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。现在你想知道那为什么type会全部采用小写形式而不是Type呢?好吧,我猜这是为了和str保持一致性,str是用来创建字符串对象的类,而int是用来创建整数对象的类。type就是创建类对象的类。

自定义元类控制类的创建

基于Python中一切皆对象,我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(简称类的类),默认的元类为type。我们也可以通过继承type来自定义元类,然后通过metaclass关键字参数为一个类来指定元类

class Mymetaclass(type):

    def __init__(self,cls_name,cls_bases,cls_dict):
        print(self) # <class '__main__.Student'>  Student类的对象
        print(cls_name) #  Student     类名
        print(cls_bases) # (<class 'object'>,)  父类元组
        print(cls_dict) # {'__module__': '__main__', '__qualname__': 'Student', '__doc__': '\n    学生类的注释文档\n    ', '__init__': <function Student.__init__ at 0x000000000284FD08>}
        if not cls_name.istitle():
            raise TypeError("类的首字母必须大写") # 如果类的首字母没有大写则抛出异常

        if not self.__dict__["__doc__"]:
            raise SyntaxError("请补充注释文档") # 类中必须写注释文档,无注释文档则抛出异常

        type(cls_name,cls_bases,cls_dict)


class Student(object,metaclass=Mymetaclass):
    """
    学生类的注释文档
    """
    def __init__(self,name,age):
        self.name = name
        self.age = age

s = Student("jack",22)

自定义元类控制类的调用

class Mymetaclass(type):

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

        # 调用new方法创建一个空对象
        obj = object.__new__(self)

        # 调用init方法初始化对象,这样obj.__dict__中就有值了
        self.__init__(obj,*args, **kwargs)

        # 返回实例化的对象
        return obj

class Student(object,metaclass=Mymetaclass):
    """
    学生类的注释文档
    """
    def __init__(self,name,age):
        self.Name = name
        self.Age = age

s = Student("jack",22)
print(s.__dict__) # {'Name': 'jack', 'Age': 22}

当我们调用一个对象的时候,实际上是执行该对象的__call__方法。然后在__call__方法中创建一个空对象并初始化,最后返回这个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值