【问题标题】:Python magic meta class creationPython魔术元类创建
【发布时间】:2018-10-25 18:36:04
【问题描述】:

基本上,我想用staticmethods 创建一个“模板”类型对象,然后创建一个继承自它的新对象,但使用functools.partial 使用父级的方法,其中使用了子级的参数。子参数与父方法的参数同名。由此产生的范式将是这样的:

class Naked:

    @staticmethod        
    def echo1(foo):
        return f"echo1: {foo}"

    @staticmethod        
    def echo2(bar, bla):
        return f"echo2: {bar}, {bla}"

class Clothed(Naked):
    def __init__(self, *args, **kwargs):
        for arg in args:
            setattr(self, arg, arg)

        for k,v in kwargs.items():
            setattr(self, k, v)

a = Clothed(foo = "Hello", bar = "World")
a.echo1 == "echo1: Hello"
a.echo2("wsup?") == "echo2: World, wsup?"

这是一个不起作用的尝试:

from inspect import signature
from functools import partial
class Meta(type):
    def __init__(cls, name, bases, attrs):
         funcs = (k for k,v in attrs.items() if callable(v) and k not in dir(type)) #this doesn't work...
         for func in funcs:
            args = signature(func).keys() #function argument names
            newargs = {arg:getattr(self, arg, None) for arg in args} #create dictionary with val from instance, how is this possible, no self here?
            attrs[func] = partial(func,newargs)
        return type.__init__(cls, name, bases, attrs)  

class Naked(metaclass=Meta):

    @staticmethod        
    def echo1(foo):
        return f"echo1: {foo}"

    @staticmethod        
    def echo2(bar, bla):
        return f"echo2: {bar}, {bla}"

class Clothed(Naked):
    def __init__(self, *args, **kwargs):
        for arg in args:
            setattr(self, arg, arg)

        for k,v in kwargs.items():
            setattr(self, k, v)

【问题讨论】:

  • 对元编程不太熟悉。但是,如果 __init__attrs 参数是字典,那么您的 if callable(attr) 似乎正在检查 attr 键是否可调用。键是一个字符串,所以它是不可调用的,对吧?也许if callable(attrs[attr]) 有效?
  • 谢谢!我对其进行了修改,以便现在可以使用它
  • 所以这就是问题的原因?这是一个疯狂的猜测,但如果它有效,我可以将其发布为答案而不是评论。
  • 不幸的是它只修复了那部分......不,它不能解决整个问题:/
  • 我很确定这对元类来说是不可能的:你不知道你在定义类时(在实例创建时)所做的映射(这是元类做它的时候)。

标签: python python-3.x object inheritance metaprogramming


【解决方案1】:

我不知道如何使用元类来做到这一点,但这里有一个使用 mixin 类的可能解决方案。你也许可以使用这样的东西。

from inspect import signature
from functools import partialmethod, partial

class Naked:

    @staticmethod        
    def echo1(foo):
        return f"echo1: {foo}"

    @staticmethod        
    def echo2(bla, bar):
        return f"echo2: {bar}, {bla}"

class PartialMixin:
    def __init__(self, **kwargs):
        methods = [m for m in dir(self) if callable(getattr(self, m)) and m not in dir(type)]
        for method_name in methods:
            method = getattr(self, method_name)
            method_kwargs = signature(method).parameters.keys()
            partial_kwargs = {k:kwargs[k] for k in kwargs if k in method_kwargs}
            new_method = partial(method, **partial_kwargs)
            # if the methods are not static, maybe functools.partialmethod should be used.
            setattr(self, method_name, new_method)

class Clothed(PartialMixin, Naked):
    pass

a = Clothed(foo = "Hello", bar = "World")
a.echo1() == "echo1: Hello"
a.echo2("wsup?") == "echo2: World, wsup?"

【讨论】:

  • 嗨,我会将其标记为答案,尽管我正在寻找元类解决方案,这可能是不可能的......
  • 当然。如果有人提交了更有用的答案,您可以随时将该答案标记为已接受。如果你想找到一个使用元类的解决方案,我推荐 Luciano Ramalho 的书Fluent Python,其中包含关于类元编程和类装饰器的章节(也可以在这里使用)。
  • 谢谢,这是最好的书之一 :)。我再看看
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-07
  • 2017-11-13
  • 1970-01-01
  • 2018-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多