Last Updated on
类
在理解元类之前,您需要掌握Python的类。Python从Smalltalk语言中借用了一个非常独特的类概念。
在大多数语言中,类只是描述如何产生对象的代码段。在Python中也是如此:
class ObjectCreator(object):
pass
my_object = ObjectCreator()
print(my_object)
# 输出结果:
<__main__.ObjectCreator object at 0x10994a748>
但是在Python中,万物皆为对象,所以,类也是一个对象。
是的,对象。
一旦使用关键字class
,Python就会执行它并创建一个对象。指令
class ObjectCreator(object):
pass
在内存中创建一个名称为“ ObjectCreator”的对象。
这个对象(类)本身具有创建对象(实例)的能力,这就是为什么它是一个类。
但是,它仍然是一个对象,因此:
- 您可以将其分配给变量
- 你可以复制它
- 您可以为其添加属性
- 您可以将其作为函数参数传递
例如:
class ObjectCreator(object):
pass
# 你能打印一个类,因为它是一个对象
print(ObjectCreator)
# 输出:
<class '__main__.ObjectCreator'>
# def echo(o):
print(o)
# 你能将其作为函数参数
echo(ObjectCreator)
# 输出:
<class '__main__.ObjectCreator'>
# 你能为其添加属性
print(hasattr(ObjectCreator, 'new_attribute'))
ObjectCreator.new_attribute = 'foo'
print(hasattr(ObjectCreator, 'new_attribute'))
print(ObjectCreator.new_attribute)
# 输出:
False
True
foo
# 你能将其赋值给一个变量
ObjectCreatorMirror = ObjectCreator
print(ObjectCreatorMirror.new_attribute)
print(ObjectCreatorMirror())
# 输出
foo
<__main__.ObjectCreator object at 0x10fcd3828>
动态创建类
由于类是对象,因此您可以像创建任何对象一样即时创建它们。
首先,您可以使用class
以下方法在函数中创建一个类:
def choose_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo # return the class, not an instance
else:
class Bar(object):
pass
return Bar
MyClass = choose_class('foo')
# 函数返回一个类,而不是一个实例
print(MyClass)
<class '__main__.Foo'>
# 你可以通过此类,创建一个实例
print(MyClass())
<__main__.Foo object at 0x89c6d4c>
但这并不是那么动态,因为您仍然必须自己编写整个类。
由于类是对象,因此它们必须由某种东西生成。
使用class
关键字时,Python会自动创建此对象。但是,与Python中的大多数事情一样,它为您提供了一种手动进行操作的方法。
还记得功能type
吗?此函数可以让您知道对象的类型:
print(type(1))
<type 'int'>
print(type("1"))
<type 'str'>
print(type(ObjectCreator))
<type 'type'>
print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
嗯,type
具有完全不同的功能,它也可以动态创建类。type
可以将类的描述作为参数,并返回一个类。
type
这样工作:
type(name of the class,
tuple of the parent class (for inheritance, can be empty),
dictionary containing attributes names and values)
例如:
class MyShinyClass(object):
pass
可以通过以下方式手动创建:
# 返回一个类
MyShinyClass = type('MyShinyClass', (), {})
print(MyShinyClass)
<class '__main__.MyShinyClass'>
# 使用此类,创建实例
print(MyShinyClass())
<__main__.MyShinyClass object at 0x8997cec>
您会注意到,我们使用“ MyShinyClass”作为类的名称和变量来保存类引用。它们可以不同,但是没有理由使事情复杂化。
type
接受字典来定义类的属性。所以:
class Foo(object):
bar = True
可以翻译为:
Foo = type('Foo', (), {'bar':True})
并用作普通类一样使用,当然,同样的还可以继承类。
最终,您需要向类中添加方法。只需定义具有适当签名的函数并将其分配为属性即可。
def echo_bar(self):
print(self.bar)
# FooClid类,继承自Foo类,并添加方法。
FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
print(hasattr(Foo, 'echo_bar'))
# 输出:False
print(hasattr(FooChild, 'echo_bar'))
# 输出:True
my_foo = FooChild()
my_foo.echo_bar()
# 输出:True
在动态创建类之后,您可以添加更多方法,就像将方法添加到正常创建的类对象中一样。
def echo_bar_more(self):
print('yet another method')
FooChild.echo_bar_more = echo_bar_more
print(hasattr(FooChild, 'echo_bar_more'))
# 输出:True
您会看到我们要去的方向:在Python中,类是对象,您可以动态地动态创建类。
这是Python在使用关键字class
时所做的,并且通过使用元类来完成。
什么是元类(最终)
元类是创建类的“东西”。
您定义类是为了创建对象,对吗?
但是我们了解到Python类是对象。
好吧,元类是创建这些对象的东西。它们是class的class,您可以通过以下方式描绘它们:
MyClass = MetaClass()
my_object = MyClass()
您已经看到,type
您可以执行以下操作:
MyClass = type('MyClass', (), {})
这是因为该函数type
实际上是一个元类。type
是Python用于在幕后创建所有类的元类。
至于为什么用小写而不是小写Type
?好吧,我想这与str
创建字符串对象int
的类和创建整数对象的类的一致性有关。type
只是创建类对象的类。
您可以通过检查__class__
属性来看到。
一切,我的意思是,一切都是Python中的对象。其中包括整数,字符串,函数和类。它们都是对象。所有这些都是从一个类创建的:
age = 35
print(age.__class__)
<type 'int'>
name = 'bob'
print(name.__class__)
<type 'str'>
def foo(): pass
print(foo.__class__)
<type 'function'>
class Bar(object): pass
print(Bar.__class__)
<class 'type'>
自定义元类
上面我们了解了元类是什么后,知道Python中所有的类class都是通过元类type创建的,那么我们就可以通过继承type的方式,自定义自己的元类,然后通过自己的元类来创建类,就可以完成一下类的预定义属性,预定义方法等的操作。
自定义元类,需要继承type,通过__new__魔法方法,定义使用此元类创建对象(类对象)时运行的
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
# do something 。。。
return super().__new__(cls, name, bases, attrs)
其中name.base,attrs就是使用type创建类对象时需要的参数:
- name: 名称
- base:继承的父类
- attrs:属性和方法
使用自定义元类,可以实现很多功能,具体在使用中灵活应用,查看一些优秀的开源代码,会发现其中有众多应用,可以学习其使用方式,灵活的在工作中使用。