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

标签 python configuration metaclass finite-automata

我发现元类的存在和使用可以为类创建过程提供优雅的处理,从而使您免于编写大量代码。我在我的应用程序中使用它,其中实例化了多个交互服务器。详细说明:

每个设备都实例化一个特定于其操作的服务器类,它是(...的子类)最终是这个 BaseServer 类的子类。现在,一些设备服务器需要一个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 - How can one supply metaclasses with configuration info?

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

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

这样的函数:

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

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

2 - What is a good way to have a SINGLE config instance be passed through the program-flow, to be edited, updated and perhaps eventually written?

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

但是如果您真的需要一个“单例”对象,即只有一个实例的对象,您可以采用简单的方法:在元类字典中有一个类,然后传递该类,而不是它的一个实例。如果你有字典而不是类,那就更好、更干净了。

如果您需要创建一个“真正的”单例对象,您应该创建一个类并覆盖其中的 __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 - Can the input arguments to metaclass be somehow extended beyond the Metaclass.new(meta, name, bases, attrs) ?

没有利用语言语法。 我的意思是,总是可以像普通的 Python 调用一样调用元类,但这会阻止您使用语言语法来描述您的类:您需要将类主体定义为字典以作为 调用的属性

例如,要创建派生异常类,可以这样做:

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

代替:

class MyException(Exception):
    pass

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

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

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_server_params 属性来进一步控制类的创建。

关于python - 元类配置类。但是我们可以配置元类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5531483/

相关文章:

Android 使用程序化 WifiConfiguration 连接到 wifi

grails - 元编程XMLSlurper结果

python - 如何使用 Pymongo 在 MongoDB 中选择单个字段?

python - 当我提前知道它的长度时,我可以加快可迭代类的速度吗?

python - 少量删除 SQLAlchemy MySQL

tomcat - 触发tomcat contentType检测

python - 我可以在 Dask/Distributed 中使用从 .py 文件导入的函数吗?

java - LDAP 与 activiti 集成

ruby - 类方法中的define_method

python - 方法解析顺序和元类