Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中,什么时候应该使用元类?_Python_Oop - Fatal编程技术网

在Python中,什么时候应该使用元类?

在Python中,什么时候应该使用元类?,python,oop,Python,Oop,我经历过: 但是,有谁能更具体地解释我应该在什么时候使用元类概念,以及什么时候它非常方便 假设我有一个如下所示的类: class Book(object): CATEGORIES = ['programming','literature','physics'] def _get_book_name(self,book): return book['title'] def _get_category(self, book): for cat

我经历过:

但是,有谁能更具体地解释我应该在什么时候使用元类概念,以及什么时候它非常方便

假设我有一个如下所示的类:

 class Book(object):
    CATEGORIES = ['programming','literature','physics']
    def _get_book_name(self,book):
        return book['title']
    def _get_category(self, book):
        for cat in self.CATEGORIES:
            if book['title'].find(cat) > -1:
                return cat  
        return "Other"


if __name__ == '__main__':
    b = Book()
    dummy_book = {'title':'Python Guide of Programming', 'status':'available'}
    print b._get_category(dummy_book)
这节课

在哪种情况下我应该使用元类?为什么它有用


提前感谢。

当您希望在创建类时对其进行变异时,可以使用元类。元类几乎不需要,它们很难调试,也很难理解——但有时它们可以使框架更易于使用。在我们的600Kloc代码库中,我们已经使用了7次元类:一次是ABCMeta,一次是Django的4x models.SubfieldBase,两次是使类在Django中可用作视图的元类。正如@Ignacio所写,如果你不知道你需要一个元类(并且考虑了所有其他选项),你就不需要一个元类。

如果你出于任何原因想做像
Class[x]
x在Class
等的事情,你必须使用元类:

class Meta(type):
    def __getitem__(cls, x):
        return x ** 2

    def __contains__(cls, x):
        return int(x ** (0.5)) == x ** 0.5

# Python 2.x
class Class(object):
    __metaclass__ = Meta

# Python 3.x
class Class(metaclass=Meta):
    pass

print Class[2]
print 4 in Class

从概念上讲,类的存在是为了定义一组对象(类的实例)的共同点。这就是全部。它允许您根据类定义的共享模式考虑类的实例。如果每个对象都不同,我们就不用麻烦使用类了,我们只需要使用字典

元类是一个普通类,它的存在也是出于同样的原因;定义其实例的公共内容。默认元类
type
提供了使类和实例按您习惯的方式工作的所有常规规则,例如:

  • 实例上的属性查找检查实例及其类,然后按MRO顺序检查所有超类
  • 调用
    MyClass(*args,**kwargs)
    调用
    i=MyClass.\uu new\uuuu(MyClass,*args,**kwargs)
    获取一个实例,然后调用
    i.\uu init\uu(*args,**kwargs)
    对其进行初始化
  • 通过将类块中的所有名称绑定到类的属性中,从类块中的定义创建类
如果您想让某些类的工作方式与普通类不同,那么可以定义一个元类,并使您的异常类成为该元类的实例,而不是
type
。您的元类几乎肯定是
类型的子类,因为您可能不想使不同类型的类完全不同;正如您可能希望某些书籍子集的行为有点不同(例如,是其他作品的汇编的书籍),并使用
Book
的子类,而不是完全不同的类

如果您不想定义一种使某些类的工作方式与普通类不同的方式,那么元类可能不是最合适的解决方案。注意,“类定义它们的实例如何工作”已经是一个非常灵活和抽象的范例;大多数情况下,您不需要更改类的工作方式

如果你搜索一下,你会看到很多元类的例子,这些元类实际上只是用来做一些关于类创建的事情;通常自动处理类属性,或者从某处自动查找新属性。我真的不认为元类的这些伟大用途。他们没有改变类的工作方式,他们只是在处理一些类。在我看来,创建类的工厂函数,或者在创建类之后立即调用的类方法,或者最好是类装饰器,将是实现这类事情的更好方法

但有时您会发现自己编写了复杂的代码,以使Python的默认类行为在概念上做一些简单的事情,这实际上有助于“更进一步”并在元类级别实现它

一个相当简单的例子是“单例模式”,其中您有一个类,其中只能有一个实例;调用该类将返回一个已创建的现有实例。就我个人而言,我反对单例,也不建议使用单例(我认为它们只是全局变量,巧妙地伪装成新创建的实例,以便更容易引起微妙的bug)。但是人们使用它们,并且有大量的方法使用
\uuuu new\uuuu
\uuu init\uuuu
来创建单例类。这样做可能会有点恼人,主要是因为Python希望调用
\uuuunew\uuuuuu
,然后根据结果调用
\uuuuuu init\uuuuu
,所以您必须找到一种方法,避免每次有人请求访问单例时都重新运行初始化代码。但是,如果我们在调用类时直接告诉Python我们想要发生什么,而不是试图设置Python想要做的事情,以便它们最终恰好做我们想要做的事情,那不是更容易吗

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance
在10行以下,它只需添加
\uuuuuuuu元类=Singleton
,即可将普通类转换为单例,也就是说,只需声明它们是单例。在这个层次上实现这类东西要比在类层次上直接破解更容易

但是对于您特定的
书籍
类,看起来您不需要做任何元类可以帮助您完成的事情。你真的不需要接触元类,除非你发现类如何工作的正常规则阻止你以简单的方式做一些应该简单的事情(这与“伙计,我希望我不必为所有这些类输入那么多,我想知道我是否可以自动生成公共位?”)不同。事实上,尽管我每天都在工作中使用Python,但我从来没有真正使用过元类;我所有的元类都是像上面的
Singleton
这样的玩具例子,或者只是愚蠢的探索