allbet gmaing代理:Python 中的元类到底是什么?这篇恐怕是最清晰的了

admin 3个月前 (06-30) 科技 30 0

类作为工具

在理解元类之前,您需要掌握 Python 的类。Python 从 SMalltalk 语言中借用了一个异常特殊的类观点

在大多数语言中,类只是形貌若何发生工具的代码段。在 Python 中也是云云:

>>> class ObjectCreator(object):
...       pass
...

>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>

然则Python的类愈甚。在Python中,Python的类也是工具。

对的,也是工具。

一旦使用关键class,Python 就会执行它并建立一个工具。示例代码:

>>> class ObjectCreator(object):
...       pass
...

如上代码在内存中建立一个名称为 “ObjectCreator” 的工具。

这个工具(类)自己具有建立工具(实例)的能力,这就是为什么它也是一个类

然则,它仍然是一个工具,由于:

  • 您可以将其分配给变量
  • 你可以复制它
  • 您可以为其添加属性
  • 您可以将其作为函数参数通报

例如:

>>> print(ObjectCreator) # 你可以打印一个类,由于它是一个工具
<class '__main__.ObjectCreator'>
>>> def echo(o):
...       print(o)
...
>>> echo(ObjectCreator) # 可以将类作为参数通报
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # 可以向类添加属性
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatoRMirror = ObjectCreator # 可以为变量指定类
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>

动态建立类

由于类是工具,因此您可以像建立任何工具一样即时建立它们。

首先,您可以使用class以下方式在函数中建立一个类:

>>> def choose_class(name):
...     if name == 'foo':
...         class Foo(object):
...             pass
...         return Foo # 返回类,而不是一个实例
...     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可以将类的形貌作为参数,并返回一个类。

(我知道,凭据通报给它的参数,同一个函数可以有两种完全差别的用法是很愚蠢的。由于 Python 中的向后兼容性,这是一个问题

type 用法:

type(name, bases, attrs)

参数:

  • name:Class名称
  • bases:父类的元组(对于继续,可以为空)
  • attrs:包罗属性名称和值的字典

例如:

>>> 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})

并用作通俗类:

>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True

固然,您可以从中继续,因此:

>>>   class FooChild(Foo):
...         pass

将是:

>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True

最终,您需要向类中添加方式。只需界说具有适当署名的函数并将其分配为属性即可。

>>> 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

在动态建立类之后,您可以添加更多方式,就像将方式添加到正常建立的类工具中一样。

>>> def echo_bar_more(self):
...       print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True

最终您会看到我们要表达的内容:在 Python 中,类是工具,您可以动态动态地建立一个类。

这是 Python 在使用关键字class时所做的,而且是通过使用元类来完成的。

什么是元类(最终)

元类是建立类的 “器械”。

您界说类是为了建立工具,对吗?

然则我们领会到 Python 类是工具。

好吧,元类就是建立这些工具的缘故原由。它们是类的类,您可以通过以下方式描绘它们:

MyClass = MetaClass()
my_object = MyClass()

您已经看到,type您可以执行以下操作:

MyClass = type('MyClass', (), {})

这是由于该函数type实际上是一个元类。typePython 用于在幕后建立所有类的元类

现在,您想知道为什么用小写而不是小写Type

好吧,我想这与str建立字符串工具int的类和建立整数工具的类的一致性有关。type只是建立类工具的类。

您可以通过检查__class__属性来看到。

一切,我的意思是一切,都是 Python 中的工具。其中包罗整数,字符串,函数和类。它们都是工具。所有这些都是从一个类建立的:

>>> 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'>

现在,什么是__class__任何__class__

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

因此,元类只是建立类工具的器械。

若是愿意,可以将其称为 “类工厂”。

type 是 Python 使用的内置元类,然则您固然可以建立自己的元类。

__metaclass__属性

在 Python 2 中,您可以__metaclass__在编写类时添加属性(有关 Python 3 语法,请参见下一部门):

class Foo(object):
    __metaclass__ = something...
    [...]

若是这样做,Python 将使用元类建立类Foo

小心点,这很棘手。

class Foo(object)先编写,但Foo尚未在内存中建立类工具。

Python 将__metaclass__在类界说中寻找。若是找到它,它将使用它来建立工具类Foo。若是没有,它将 type用于建立类。

读几回。

当您这样做时:

class Foo(Bar):
    pass

Python 执行以下操作:

中有__metaclass__属性Foo吗?

若是是的话,在内存中建立一个类工具(我说的是类工具,陪在我身边在这里),名称Foo使用是什么__metaclass__

若是 Python 找不到__metaclass__,它将__metaclass__在 MODULE 级别上查找,并实验执行相同的操作(但仅适用于不继续任何内容的类,基本上是老式的类)。

然后,若是基本找不到任何工具__metaclass__,它将使用Bar的(第一个父工具)自己的元类(可能是默认值type)建立类工具。

请注意,该__metaclass__属性将不会被继续,父(Bar.__class__)的元类将被继续。若是Bar使用通过(而不是)__metaclass__建立的属性,则子类将不会继续该行为。Bar``type()``type.__new__()

现在最大的问题是,您可以输入__metaclass__什么?

谜底是:可以建立类的器械。

什么可以建立一个类?type,或任何继续或使用它的内容。

Python 3 中的元类

设置元类的语法在 Python 3 中已更改:

class Foo(object, metaclass=something):
    ...

__metaclass__不再使用该属性,而在基类列表中使用关键字参数。

然则,元类的行为基本保持稳定。

在 python 3 中添加到元类的一件事是,您还可以将属性作为关键字参数通报给元类,如下所示:

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...

为什么要使用元类?

现在是个大问题。为什么要使用一些艰涩的易错功效?

好吧,通常您不会:

元类是更深层的魔术,99%的用户永远不必忧郁。若是您想知道是否需要它们,则不需要(实际上需要它们的人肯定会知道他们需要它们,而且不需要注释缘故原由)。

Python 大师 Tim Peters

元类的主要用例是建立 API。一个典型的例子是 Django ORM。它允许您界说如下内容:

class Person(models.Model):
    name = models.CharField(max_length=30)
    age = models.IntegerField()

然则,若是您这样做:

person = Person(name='bob', age='35')
print(person.age)

它不会返回IntegerField工具。它将返回int,甚至可以直接从数据库中获取它。

这是可能的,由于models.Modeldefine __metaclass__并使用了一些魔术,这些魔术将使Person您使用简朴语句界说的工具酿成与数据库字段的庞大挂钩。

Django 通过公然一个简朴的 API 并使用元类,从该 API 重新建立代码来完成幕后的实际工作,使看起来庞大的事情变得简朴。

最后一点

首先,您知道类是可以建立实例的工具。

实际上,类自己就是元类的实例。

>>> class Foo(object): pass
>>> id(Foo)

一切都是 Python 中的工具,它们都是类的实例或元类的实例。

除了type

type实际上是它自己的元类。

其次,元类很庞大。您可能不希望将它们用于异常简朴的类更改。您可以使用两种差别的手艺来更改类:

  • 猴子修补
  • 类装饰

99%的时间,您需要更改类,最好使用这些。

然则 98%的时间基本不需要更改类。

本文首发于BigYoung小站

,

欧博官网手机

欢迎进入欧博官网手机(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

AllBetGaming声明:该文看法仅代表作者自己,与本平台无关。转载请注明:allbet gmaing代理:Python 中的元类到底是什么?这篇恐怕是最清晰的了

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:668
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1130
  • 评论总数:254
  • 浏览总数:8295