Classes as objects (类作为对象)
Before understanding metaclasses, you need to master classes in Python. (在理解元类之前,您需要掌握Python的类。) And Python has a very peculiar idea of what classes are, borrowed from the Smalltalk language. (Python从Smalltalk语言中借用了一个非常独特的类概念。)
In most languages, classes are just pieces of code that describe how to produce an object. (在大多数语言中,类只是描述如何产生对象的代码段。) That's kinda true in Python too: (在Python中也是如此:)
>>> class ObjectCreator(object):
... pass
...
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
But classes are more than that in Python. (但是类比Python中更多。) Classes are objects too. (类也是对象。)
Yes, objects. (是的,对象。)
As soon as you use the keyword class
, Python executes it and creates an OBJECT. (一旦使用关键字class
,Python就会执行它并创建一个对象。) The instruction (指令)
>>> class ObjectCreator(object):
... pass
...
creates in memory an object with the name "ObjectCreator". (在内存中创建一个名称为“ ObjectCreator”的对象。)
This object (the class) is itself capable of creating objects (the instances), and this is why it's a class . (这个对象(类)本身具有创建对象(实例)的能力,这就是为什么它是一个类 。)
But still, it's an object, and therefore: (但是,它仍然是一个对象,因此:)
- you can assign it to a variable (您可以将其分配给变量)
- you can copy it (你可以复制它)
- you can add attributes to it (您可以为其添加属性)
- you can pass it as a function parameter (您可以将其作为函数参数传递)
eg: (例如:)
>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
... print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>
Creating classes dynamically (动态创建类)
Since classes are objects, you can create them on the fly, like any object. (由于类是对象,因此您可以像创建任何对象一样即时创建它们。)
First, you can create a class in a function using class
: (首先,您可以使用class在函数中创建一个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) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
But it's not so dynamic, since you still have to write the whole class yourself. (但这并不是那么动态,因为您仍然必须自己编写整个类。)
Since classes are objects, they must be generated by something. (由于类是对象,因此它们必须由某种东西生成。)
When you use the class
keyword, Python creates this object automatically. (使用class
关键字时,Python会自动创建此对象。) But as with most things in Python, it gives you a way to do it manually. (但是,与Python中的大多数事情一样,它为您提供了一种手动进行操作的方法。)
Remember the function type
? (还记得函数type
吗?) The good old function that lets you know what type an object is: (好的旧函数可以让您知道对象的类型:)
>>> print(type(1))
<type 'int'>
>>> print(type("1"))
<type 'str'>
>>> print(type(ObjectCreator))
<type 'type'>
>>> print(type(ObjectCreator()))
<class '__main__.ObjectCreator'>
Well, type
has a completely different ability, it can also create classes on the fly. (好吧, type
具有完全不同的能力,它也可以动态创建类。) type
can take the description of a class as parameters, and return a class. (type
可以将类的描述作为参数,并返回一个类。)
(I know, it's silly that the same function can have two completely different uses according to the parameters you pass to it. It's an issue due to backwards compatibility in Python) ((我知道,根据传递给它的参数,同一个函数可以有两种完全不同的用法是很愚蠢的。由于Python向后兼容,这是一个问题))
type
works this way: (type
这种方式工作:)
type(name of the class,
tuple of the parent class (for inheritance, can be empty),
dictionary containing attributes names and values)
eg: (例如:)
>>> class MyShinyClass(object):
... pass
can be created manually this way: (可以通过以下方式手动创建:)
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
You'll notice that we use "MyShinyClass" as the name of the class and as the variable to hold the class reference. (您会注意到,我们使用“ MyShinyClass”作为类的名称和变量来保存类引用。) They can be different, but there is no reason to complicate things. (它们可以不同,但??是没有理由使事情复杂化。)
type
accepts a dictionary to define the attributes of the class. (type
接受字典来定义类的属性。) So: (所以:)
>>> class Foo(object):
... bar = True
Can be translated to: (可以翻译为:)
>>> Foo = type('Foo', (), {'bar':True})
And used as a normal class: (并用作普通类:)
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True
And of course, you can inherit from it, so: (当然,您可以从中继承,因此:)
>>> class FooChild(Foo):
... pass
would be: (将会:)
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
Eventually you'll want to add methods to your class. (最终,您需要向类中添加方法。) Just define a function with the proper signature and assign it as an attribute. (只需定义具有适当签名的函数并将其分配为属性即可。)
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True
And you can add even more methods after you dynamically create the class, just like adding methods to a normally created class object. (在动态创建类之后,您可以添加更多方法,就像将方法添加到正常创建的类对象中一样。)
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
You see where we are going: in Python, classes are objects, and you can create a class on the fly, dynamically. (您会看到我们要去的方向:在Python中,类是对象,您可以动态地动态创建类。)
This is what Python does when you use the keyword class
, and it does so by using a metaclass. (这是Python在使用关键字class
时所做的,并且通过使用元类来实现。)
What are metaclasses (finally) (什么是元类(最终))
Metaclasses are the 'stuff' that creates classes. (元类是创建类的“东西”。)
You define classes in order to create objects, right? (您定义类是为了创建对象,对吗?)
But we learned that Python classes are objects. (但是我们了解到Python类是对象。)
Well, metaclasses are what create these objects. (好吧,元类是创建这些对象的原因。) They are the classes' classes, you can picture them this way: (它们是班级的班级,您可以通过以下方式描绘它们:)
MyClass = MetaClass()
my_object = MyClass()
You've seen that type
lets you do something like this: (您已经看到该type
可以执行以下操作:)
MyClass = type('MyClass', (), {})
It's because the function type
is in fact a metaclass. (这是因为函数type
实际上是一个元类。) type
is the metaclass Python uses to create all classes behind the scenes. (type
是Python用于在幕后创建所有类的元类。)
Now you wonder why the heck is it written in lowercase, and not Type
? (现在,您想知道为什么用小写而不是Type
来写吗?)
Well, I guess it's a matter of consistency with str
, the class that creates strings objects, and int
the class that creates integer objects. (好吧,我想这与str
,创建字符串对象的类和int
创建整数对象的类的一致性有关。) type
is just the class that creates class objects. (type
只是创建类对象的类。)
You see that by checking the __class__
attribute. (通过检查__class__
属性可以看到这一点。)
Everything, and I mean everything, is an object in Python. (一切,我的意思是,一切都是Python中的对象。) That includes ints, strings, functions and classes. (其中包括整数,字符串,函数和类。) All of them are objects. (它们都是对象。) And all of them have been created from a class: (所有这些都是从一个类创建的:)
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
Now, what is the __class__
of any __class__
? (现在,任何__class__
的__class__
是什么?)
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
So, a metaclass is just the stuff that creates class objects. (因此,元类