元类配置类。但我们可以配置元类吗?

时间:2011-04-03 18:13:07

标签: python configuration metaclass finite-automata

我发现元类的存在和使用可以通过在类创建过程中提供优雅的句柄来避免大量的代码编写。我在我的应用程序中使用它,其中实例化了几个交互服务器。详细说明:

每个设备都实例化一个特定于其操作的服务器类,该操作类是(一个......的子类)的子类,这个BaseServer类是ulitmately。现在,某些设备服务器需要ThreadedTCPserver,有些需要SimpleTCPServer(模块:socketserver)。它们不能全部派生自同一个类,因为使用ThreadingMixin会覆盖SimpleTCPServer的行为。

为了处理这种动态类配置,我创建了一个MetaServerType,它选择BaseServer的基类为(SimpleTCPServer,)(ThreadedTCPServer,) - >产生我想要的动态配置服务器类的结果! (呜呜)

现在,我的问题出现了: 我想使用存储参数的配置文件,默认情况下MetaServerType使用这些参数。例如:config.default_loglevel或config.default_handler等。根据元类规范,可以覆盖(从命令行或其他方式)单个服务器。

配置对象的一个实例通过程序流传递是一种好的设计实践吗?一种方法是在元类的类体中初始化配置对象 - 但我的程序流从别处开始,这意味着多次调用元类,从而产生各种配置实例。似乎在导入时调用元类(?)

因此非常欢迎详细的答案:

  1. 如何使用配置信息提供元类?
  2. 单个配置实例传递给程序流,进行编辑,更新以及最终可能最终编写的好方法是什么?
  3. 元类的输入参数是否可以某种方式扩展到Metaclass.__new__(meta, name, bases, attrs)之外?
    1. 奖金问题:这是否使我们向有限状态机(服务器)靠近一步,以便状态(不是实例)可以“暂停”或“恢复”?

1 个答案:

答案 0 :(得分:3)

  

1 - 如何使用配置信息提供元类?

有几种方法可以做到这一点 - 因为你的元类存在于自己的模块中 (是的,模块在import时执行一次,无论在同一个应用程序中导入了多少次,一个配置它们的好方法是拥有一个可调用的对象(同一模块上的类或函数),它将设置将用于配置的“全局变量”。

尽管由于C名称“global”的起源而声名远,但Python中的全局变量实际上是“模块”变量:这意味着该模块中的所有函数(包括方法)都可以访问这些变量。其他模块中的函数或代码必须为模块名称添加前缀。

这样的功能如下:

def configure_servers(p1, p2,...):
    global opt1, opt2, ...
    opt1 = p1
    opt2 = p2
    (...)

可以在创建服务器实例之前从应用程序入口点调用。 (当然,您可以传递配置文件路径而不是p1p2,...)

  

2 - 传递SINGLE配置实例的好方法是什么   通过程序流程来实现   编辑,更新,也许最终   写?

元类模块上的全局(模块)变量名称可以被所有这些名称读取,并且可以与复杂的配置对象相关联。也许存在像上面那样的“配置”功能可以使这个问题过时。

但是如果你真的需要一个“单例”对象,也就是一个只有一个实例的对象,你可以用简单的方法做到这一点:在元类字典上有一个类,并传递该类而不是它的一个实例。如果你有一本词典而不是一堂课,那就更好,更清洁。

如果你需要创建一个“真正的”单例对象,你应该有一个类并覆盖它中的__new__方法,以便它总是返回第一个创建的实例 - 例如:

class Singleton(object):
   _instance = None
   def __new__(cls, *args, **kw):
       if cls._instance is not None:
           return cls._instance
       self = object.__new__(cls, *args, **kw)
       cls._instance = self
       return self
  

3 - 元类的输入参数可以以某种方式扩展到超出范围   Metaclass.new(meta,name,bases,attrs)?

不利用语言语法。 我的意思是,总是可以将元类称为普通的Python调用,但是这会阻止您使用语言语法来描述您的类:您需要将类体定义为字典以传递为{{ 1}}用于通话。

例如,要创建派生的异常类,可以执行以下操作:

attrs

而不是:

MyException = type("MyException", (Exception, ), {})

将附加信息传递给元类的常用方法是在类主体上使用具有固定名称的属性。然后,元类检查class MyException(Exception): pass 中的这些属性并使用它们。它可以选择保留在结果类中,或者在此时从attrs dict中删除它们。

如果传递元类所需的信息仅在运行时已知,则这些属性可以指向其他(模块级)变量,或包含在创建类时评估的Python表达式。

attrs

在上面的示例中,您的元类可以使用mod_server_type = "TCP" class YAServer(ParentServer): __metaclass__ = ServerMetaBase _sever_type = mod_server_type with open("config_file") as config: _server_params = pickle.load(config) del config def __init__(self,...): ... _server_type属性来进一步控制类的创建。