python type()函数专题——动态创建类
我们知道,type()
函数是python的内置函数,可以用来查看变量的类型,它是小编最常用的一个函数。小编之所以如此中意他并不仅仅是因为它只有四个字母,在使用上比isinstance()
输入更快,还因为使用type()
可以直接看到变量的类型,而使用isinstance()
需要先知道大概是什么类型,才能判断是不是这个类型,从直观程度上type()
更加直观。它也成为小编手册示例代码的优选函数之一。但是type()
函数的作用不止于此,今天这篇文章我们就来重温一下type(
)函数的功能吧。
简介
type()
函数有两种语法,分别是:
type(object)
#或者
type(name, bases, dict, **kwds)
前一种用法接受一个对象(变量),返回 object 的类型。 返回值是一个 type 对象,通常与 object.__class__
所返回的对象相同。
说人话,就是返回这个对象的类型,举个例子:
class Animal():
name = ""
def __init__(self,name):
self.name = name
def get_name(self):
return self.name
def breathe():
print("我可以呼吸")
a = Animal('大象')
print(type(a)) # 返回类Animal的实例对象 (aka 'object') 或者 <class '__main__.Animal'>)
print(dir(a))
他的返回值是:
<class '__main__.Animal'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'get_name', 'name']
我们可以看出,这是一个Animal对象。它有一个name属性和两个方法(get_name()和breathe())
所有的动物都会呼吸!!
动态创建类
让我们再来看看第二种语法:
type(name, bases, dict, **kwds)
这个时候type()
函数可以传入三个参数,第一个参数name是我们要创建的类的类名,第二个参数bases为这个类继承于谁(也就是谁是他的父类),如果为空的话则继承于object类,第三个参数dict是一个字典,包含类的属性和方法定义。
注意,bases参数必须是一个元组,所以要使用元组的形式把参数传进去!
创建一个子类,增加新的属性
前面我们提到dict参数可以给新的子类添加新的属性和方法定义,来看看这个例子:
class Animal():
name = ""
def __init__(self,name):
self.name = name
def get_name(self):
return self.name
def breathe():
print("我可以呼吸")
a = Animal('大象')
print(type(a)) # 返回类Animal的实例对象 (aka 'object') 或者 <class '__main__.Animal'>)
print(dir(a))
People = type("People",(Animal,) , {'sex':'M'}) # 我们定义了一个新类叫People,他继承于animal类,多了一个新的属性sex
human = People('男人')
print(type(human)) # 返回类People的实例对象 <class '__main__.People'>)
print(dir(human))
class Animal():
name = ""
def __init__(self,name):
self.name = name
def get_name(self):
return self.name
def breathe():
print("我可以呼吸")
a = Animal('大象')
print(type(a)) # 返回类Animal的实例对象 (aka 'object') 或者 <class '__main__.Animal'>)
print(dir(a))
People = type("People",(Animal,) , {'sex':'M'}) # 我们定义了一个新类叫People,他继承于animal类,多了一个新的属性sex
human = People('男人')
print(type(human)) # 返回类People的实例对象 <class '__main__.People'>)
print(dir(human))
运行结果如下:
<class '__main__.Animal'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'get_name', 'name']
<class '__main__.People'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'get_name', 'name', 'sex']
可以看到我们成功地创建了一个Animal类的子类People,这个子类相比父类多了一个sex方法。
创建一个子类,增加新的方法
dict参数是一个字典,字典内不能写函数,但我们可以先定义一个函数,然后将函数名作为字典的值传进去:
class Animal():
name = ""
def __init__(self,name):
self.name = name
def get_name(self):
return self.name
def breathe():
print("我可以呼吸")
a = Animal('大象')
print(type(a)) # 返回类Animal的实例对象 (aka 'object') 或者 <class '__main__.Animal'>)
print(dir(a))
People = type("People",(Animal,) , {'sex':'M'}) # 我们定义了一个新类叫People,他继承于animal类,多了一个新的属性sex
human = People('男人')
print(type(human)) # 返回类People的实例对象 <class '__main__.People'>)
print(dir(human))
def fly(self):
print("我可以飞")
Bird = type('Bird', (Animal,), {'fly': fly})
bird =Bird('乌鸦')
print(type(bird)) # 返回类People的实例对象 <class '__main__.People'>)
print(dir(bird))
bird.fly()
运行结果如下:
<class '__main__.Animal'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'get_name', 'name']
<class '__main__.People'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'get_name', 'name', 'sex']
<class '__main__.Bird'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'breathe', 'fly', 'get_name', 'name']
我可以飞
可以看到,我们成功的将fly方法添加到了Animal类的子类Bird类中了!
同时这个fly()方法也工作正常。
python中类创建的本质
我们使用class创建类,当你使用class关键字时,Python解释器自动创建这个对象。而底层其实使用的是type函数(type函数也可以查看实例所属类型)来创建类的。所以我们可以直接使用type()函数来手动实现动态创建类。
当type()只有一个参数时,其作用就是返回变量或对象的类型当type()有三个参数时,其作用就是创建类对象:
- 第一个参数:name表示类名称,字符串类型
- 第二个参数:bases表示继承对象(父类),元组类型,单元素使用逗号
- 第三个参数:attr表示属性,这里可以填写类属性、类方式、静态方法,采用字典格式,key为属性名,value为属性值
总结
通过type添加的属性是类属性,并不是实例属性
通过type可以给类添加普通方法,静态方法,类方法,效果跟class一样
type创建类的效果,包括继承等的使用性质和class创建的类一样。本质class创建类的本质就是用type创建。所以可以说python中所有类都是type创建的。
对元类的理解与注意事项
元类就是类的类,python中函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。Python中所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。type就是Python的内建元类,当然了,也可以创建自己的元类。
python查看对象所属类型既可以用type函数,也可以用对象自带的__class__属性。
以下代码验证:任何对象最终的所属类都是type。 type是所有类的创造者。
str = "W3cschool"
print(type(str))
print(type(type(str)))
运行结果如下:
<class 'str'>
<class 'type'>