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__方法中创建一个空对象并初始化,最后返回这个对象。