首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在下面的场景中使用python元类?

如何在下面的场景中使用python元类?
EN

Stack Overflow用户
提问于 2018-01-16 19:03:54
回答 2查看 776关注 0票数 1

我想要创建一个具有级联特性的配置类。我这么说是什么意思?假设我们有这样一个配置类

代码语言:javascript
复制
class BaseConfig(metaclass=ConfigMeta, ...):
   def getattr():
       return 'default values provided by the metaclass'

class Config(BaseConfig):
   class Embedding(BaseConfig, size=200):
       class WordEmbedding(Embedding):
           size = 300

当我在代码中使用它时,我将按如下方式访问配置,

代码语言:javascript
复制
def function(Config, blah, blah):
    word_embedding_size = Config.Embedding.Word.size
    char_embedding_size = Config.Embedding.Char.size

最后一行访问Embedding类“Char”中不存在的属性。它应该调用getattr(),在本例中应该返回200。我对元类不太熟悉,无法做出正确的判断,但我需要定义元类的__new__()

这种方法有意义吗?还是有更好的方法去做呢?

编辑:

代码语言:javascript
复制
class Config(BaseConfig):
   class Embedding(BaseConfig, size=200):
       class WordEmbedding(Embedding):
           size = 300
   class Log(BaseConfig, level=logging.DEBUG):
       class PREPROCESS(Log):
           level = logging.INFO

#When I use 
log = logging.getLogger(level=Config.Log.Model.level) #level should be INFO
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-17 18:36:20

这有点让人迷惑。我不确定这是否是用默认参数声明配置的最佳方式--这看起来很冗长。但是是的,考虑到Python中元类和神奇方法的灵活性,这样的东西有可能使您需要的所有灵活性都过时。

出于这个原因,我想说的是,像您正在做的那样,使用嵌套类作为名称空间可能是它们唯一有用的东西。(嵌套类)。经常会看到很多人误解Python,试图使用嵌套类。

因此-针对您的问题,您需要在最后一个类中存在一个__getattr__方法,该方法可以获取atributes的默认值。然后,这些属性被声明为嵌套类的关键字--这些类也可以具有相同的元类。否则,嵌套类的层次结构就可以使用Python中的点表示法来获取嵌套属性。

此外,对于嵌套集中的每个类,如果未定义下一层嵌套类,则可以传递用作默认值的关键字参数。在给定的示例中,尝试使用非exisitng Config.Embedding.Char.size访问Char应该返回默认的“大小”。并不是“嵌入”中的__getattr__可以返回一个假的"Char“对象,而是必须生成一个size属性的对象。因此,我们的__getattr__还没有产生一个具有推进程序__getattr__的对象;

但是,我将建议对您的requirements进行更改--而不是将默认值作为关键字参数传递给您,使其具有一个保留的名称,比如可以在其中放置默认属性的_default。这样,您可以提供深度嵌套的默认子包,而不仅仅是标量值,而且实现可能更简单。

实际上-简单多了。按照您的建议,通过对类使用关键字,实际上需要在数据结构中设置元类的默认参数(但是在__new____init__中都是可能的)。但是,只要始终使用嵌套类(保留名称),metac类上的自定义__getattr__就可以工作。这将检索配置类本身上的不存在的类属性,如果请求的属性不存在,则只需尝试检索我提到的_default类。

因此,您可以使用以下内容:

代码语言:javascript
复制
class ConfigMeta(type):
    def __getattr__(cls, attr):
        return cls._default

class Base(metaclass=ConfigMeta):
    pass

class Config(Base):
    class Embed(Base):
        class _default(Base):
            size = 200
        class Word(Base):
            size = 300

assert Config.Embed.Char.size == 200
assert Config.Embed.Word.size == 300

顺便说一句--就在去年,我还在做一个具有默认值的配置,但使用字典语法的项目--这就是为什么我不确定嵌套类是否是一个很好的设计的原因。但是,由于所有的功能都可以由具有3 LoC的元类提供,所以我想这比任何方式都要好。

而且,这也是为什么我认为能够嵌套整个默认的子树可能对你想要的有用--我一直在那里。

票数 1
EN

Stack Overflow用户

发布于 2018-01-16 19:18:14

您可以使用元类来设置属性:

代码语言:javascript
复制
class ConfigMeta(type):
    def __new__(mt, clsn, bases, attrs):
        try:
            _ = attrs['size']
        except KeyError:
            attrs['size'] = 300
        return super().__new__(mt, clsn, bases, attrs)

现在,如果类没有size属性,那么它将被设置为300 (根据您的需要更改此属性)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48288163

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档