牢记一条宗旨,python中一切都是对象,everything is object. 记住这个原则,是非常有助于理解python这门语言。
基础的数据类型(整形,字符串等)、函数 都是对象。在其他的面向对象的编程语言中,类一般是用来描述如何生成对象、对象的属性和行为、释放对象的代码片段。但在python中,类不仅仅是描述对象的代码片段,类 也是 对象。
接下来,我将结合具体的代码运行实例来解析 类 也是 对象。
1class MyClass(object):
2 pass
3
4if __name__ == "__main__":
5 print(id(MyClass)) # 1662525764440
6 myObj = MyClass()
7 print(myObj.__class__) # <class '__main__.MyClass'>
8 print(myObj) # <__main__.MyClass object at 0x00000183182ACC88>
9 id1 = id(myObj)
10 print(id1) # 1662557801608
11 print(hex(id1)) # 0x183182acc88
类有实际的内存地址,id()内置函数的作用就是用来获取对象的内存地址的,说明 类 确实 也是对象。
我们知道myObj是一个对象,它是类Myclass的一个实例,myObj会被分配实际的内存地址,用来存储该对象的相关数据。第10行的打印信息,我们可以看到该对象确实是分配了内存地址。同样,第5行,通过id()函数打印Myclass时,也是有实际的内存地址。那么,我们可以说Myclass也是一个"对象",而这个"对象"有点儿特殊,类("对象")可以创建对象。
好,我们理解了 类 也是 对象。那么,对象是可以动态创建的,那么 类 可不可以动态创建(定义)呢?答案当然时肯定的。
1# 动态定义类
2# 方法一:
3# 通过函数来动态定义类
4def DynamicClass(class_name):
5 if class_name == 'Fruit':
6 class Fruit(object):
7 pass
8 return Fruit # 返回一个Fruit类,并不是一个对象
9 else:
10 class Plant(object):
11 pass
12 return Plant
这种动态定义的方式 还是有类的描述代码,而且看起来有点儿多次一举。那么,还有没有其他方法呢?
我们前面提到 类 也是一个对象,那么,类 的 类 是什么呢?
1print(type(Myclass)) # <class 'type'>
2print(type(myObj)) # <class '__main__.MyClass'>
从打印信息可以看到,Myclass类("对象")的类 是type类。myObj对象的类 是Myclass。
这里涉及到两个"type": type()函数 和 type类。
type()函数 有着两种作用:
- 判断一个对象的类 type(object);如上面的例子所示;
- 定义(创建)一个类 type(name, bases, attrs); name: 新定义的类的类名; bases: 父类元组,可以为空; attrs: 包含属性的字典;
这里,我们就引出了第二种动态定义类的方法
1# 动态定义类
2# 方法二
3Fruit = type('Fruit', (), {}) # 得到一个类对象
4print(Fruit) # <class '__main__.Fruit'>
5print(Fruit.__dict__) # {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Fruit' objects>, '__weakref__': <attribute '__weakref__' of 'Fruit' objects>, '__doc__': None}
6print(Fruit()) # <__main__.Fruit object at 0x000002DECD20DF08>
从上述打印信息中可以看到,方法二动态定义的类 和 使用class关键词 定义的类 完全一样。
1# 动态定义类,定义属性
2Fruit2 = type('Fruit2',(),{'name':'fruit'})
3print(Fruit2.__dict__)
4# {
5# 'name': 'fruit',
6# '__module__': '__main__',
7# '__dict__': <attribute '__dict__' of 'Fruit2' objects>,
8# '__weakref__': <attribute '__weakref__' of 'Fruit2' objects>,
9# '__doc__': None
10# }
1# 动态定义类,继承
2Apple = type('Apple', (Fruit2,), {})
3print(Apple.__dict__) # {'__module__': '__main__', '__doc__': None}
4print(Apple.name) # 继承了Fruit2的属性
5print(Apple.__bases__) # (<class '__main__.Fruit2'>,)
1# 动态定义好一个类后,如果想增加一个方法,咋弄呢?
2def get_name(self):
3 print(self.name)
4Apple.get_name = get_name
5print(hasattr(Apple, 'get_name')) # True
6print(Apple.__dict__) # {'__module__': '__main__', '__doc__': None, 'get_name': <function get_name at 0x00000217851B0A68>}
7apple1 = Apple()
8apple1.get_name() # fruit
上述的例子中,我们可以描述得到这样的关系 type <--- Fruit2 <--- apple1,进一步抽象,metaclass <--- class <--- object
经过上述的铺垫,我们终于引出 metaclass啦!
什么是metaclass怎样创建metaclassmetaclass的作用
什么是metaclass
简单讲,metaclass(元类)就是 类的类。普通类定义了类对象的属性和方法;元类 定义了 普通类的属性和方法,普通类是元类的一个实例。
1# metaclass --- class --- object
2MyClass = MetaClass()
3obj = Myclass()
怎样创建metaclass
怎样创建metaclass,换句话说就是自定义元类。
只要 子类化 type即可定义metaclass。
metaclass的作用
- metaclass可以影响类的创建,可以修改类创建的默认行为,返回一个被"改造"过的类。
1# 自定义元类
2class MyMetaClass(type):
3 def __new__(cls, clsname, bases, attrs):
4 print("do something to change default behavior of class creation")
5 do_something = {
6 attr_key if attr_key.startswith("_") else attr_key.upper():attr_v
7 for attr_key, attr_v in attrs.items()
8 }
9 return super().__new__(cls, clsname, bases, do_something)
10
11class Myclass(metaclass=MyMetaClass):
12 name = 'Myclass'
13
14print(Myclass.__dict__) # {'__module__': '__main__', 'NAME': 'Myclass', '__dict__': <attribute '__dict__' of 'Myclass' objects>, '__weakref__': <attribute '__weakref__' of 'Myclass' objects>, '__doc__': None}
15print(hasattr(Myclass, 'name')) # False
16print(Myclass.__class__) # <class '__main__.MyMetaClass'>
17print(Myclass.__class__.__class__) # <class 'type'>
这个例子,没有是什么实际的作用,仅仅是用来说明元类能修改类创建时的默认行为。MyMeteClass将类中非"__"开头的属性名改为大写。通过打印我们可以看到,Myclass类中没有name属性,而被修改成NAME。
总之,metaclass就是为了创建类,通过python版本的演进,逐渐丰富了metaclass对创建类进行控制的范围由python2中的 __metaclass__属性 来指定something 修改 创建类的默认行为,到python3中通过 metaclass参数 来指定something 修改 创建类的默认行为而这个something可以是函数,也可以是元类(type或其子类),宗旨就是要能创建类一般来说这个something返回的是当前定义的类的类型。
以上就是我对metaclass的理解,朋友们要是有更好的理解,欢迎讨论