Python:有选择地重载属性?

时间:2015-07-09 18:03:08

标签: python python-3.x

所以这就是我想要完成的事情

class Class(object):
    _map = {0: 'ClassDefault', 1:'3', 2:'xyz'}

    def handle_map(self):
        print('.'.join((self._map[0], self._map[1], self._map[2])))


class SubClass(Class):
    _map = {3: '012'}


class SubSubClass(SubClass):
    _map = {0: 'SubClassDefault', 4: 'mno'}

    def handle_map(self):
        print('.'.join((self._map[0], self.map[4])).upper())
        super().handle_map()

c, sc, ssc = Class(), SubClass(), SubSubClass()

c.handle_map()
# ClassDefault.3.xyz
sc.handle_map()
# ClassDefault.3.xyz (_map[3] is used by some other method entirely, etc.)
ssc.handle_map()
# SUBSUBCLASSDEFAULT.MNO
# 3.xyz  --OR-- SubSubClassDefault.3.xyz

基本上我想做的是有一个简单的方法来定义父级及其子类中的值。我希望默认情况下,在定义它的层次结构中处理数据,因为子类不应该,但我也希望子类可以选择完全覆盖该处理或至少修改它在它上升之前。

我并没有把_map完全挂在字典上。它可以是一组对象,甚至只是元组等......我可以为一个用例提供的最明显的例子是为 init ()生成签名。这么多(但不是全部)参数都很常见,我想避免一遍又一遍地使用相同的锅炉板。同时,父类的合理默认值对于子类是不明智的。他们应该能够覆盖这些默认值。

同样,子类可能具有解释给定值所需的不同方式,因此如果只需要稍微修改,则不应该完全重新定义它如何处理它们。

我已经有了一些关于如何实现或者应该如何实施的半成品的想法,但是没有任何事情一直在一起。我在实现一个元类方面做了很长的工作,但很难让父类方法忽略子类定义/处理的值。当我输入它时,我考虑使用collections.chainmap来替换我在元类中编写的一堆代码,但是我认为这还没有解决我遇到的任何问题。

所以我的问题是,最合理的现有模式是什么?或者,这是不是一个可行的要求?

2 个答案:

答案 0 :(得分:1)

好吧,我想我有一个解决方案:

class Class:
    _map = {0: "a", 1: "b"}

    def getmap(self):
        # Create an empty map
        mymap = {}
        # Iterate through the parent classes in order of inheritance
        for Base in self.__class__.__bases__[::-1]:
            # Check if the class has a "getmap" attribute
            if issubclass(Base, Class):
                # Initialize the parent class
                b = Base()
                # If so, add its data to mymap
                mymap.update(b.getmap())
        # Finally add the classes map data to mymap, as it is at the top of the inheritance
        mymap.update(self._map)
        return mymap

class SubClass(Class):
    _map = {2: "c"}

class SubSubClass(SubClass):
    _map = {0: "z", 3: "d"}

c = Class()
sc = SubClass()
ssc = SubSubClass()

print(c.getmap())  # -> {0: 'a', 1: 'b'}
print(sc.getmap())  # -> {0: 'a', 1: 'b', 2: 'c'}
print(ssc.getmap())  # -> {0: 'z', 1: 'b', 2: 'c', 3: 'd'}

据我所知,这可以满足您的一切需求。如果您有疑问,请告诉我。

答案 1 :(得分:1)

关键问题是:父类中_map更改后会发生什么?

  • 子类应该看到更改 - > 使用@ noahbkim的回答

  • 子类应该看到更改 - > 使用类装饰器或元类来巩固创建的类。

元类解决方案如下所示:

class ClassMeta(type):
    def __new__(metacls, cls, bases, classdict):
        new_class = super(ClassMeta, metacls).__new__(metacls, cls, bases, classdict)
        _map = {}
        prev_classes = []
        obj = new_class
        for base in obj.__mro__:
            if isinstance(base, ClassMeta):
                prev_classes.append(base)
        for prev_class in reversed(prev_classes):
            prev_class_map = getattr(prev_class, '_map', {})
            _map.update(prev_class_map)
        new_class._map = _map
        return new_class

class Class(object, metaclass=ClassMeta):
    ...