阅读(3868) (1)

python type()函数专题——动态创建类

2023-04-20 16:19:05 更新

我们知道,​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 '__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'>