如何在不实例化的情况下复制类属性

时间:2017-06-27 05:34:49

标签: python oop

我正在尝试将类属性从一个类复制到另一个类

d = {1:'one', 2:'two'}
class X(object):
    a = 1
    b = 2

我需要定义类Y,以便满足以下条件: assert Y.a =='one' and Y.b=='two'

实现这一目标的一种方法如下:

attrDict = {attr:d[getattr(X,attr)] for attr in dir(X) if isinstance(getattr(X,attr), int)}
# attrDict is {'a':'one', 'b':'two'}

class Y(X):
    def __init__(self):
        self.copyOver()

    @classmethod
    def copyOver(klass):
        [setattr(klass, k,v) for k,v in attrDict.iteritems()]

y = Y()  # Y.a = 1 unless this runs
assert Y.a == 'one' and Y.b == 'two'

但是,在实际应用中实例化可能很昂贵:没有可能实现这个目标吗?

换句话说, 我用什么内置来更新类属性而不需要实例化它的对象

class Y(X):
    #TODO: setattr all key value pairs in attrDict on the class Y, not on instances of it.
    #TODO: Do it without requiring to instantiate an object of class Y

2 个答案:

答案 0 :(得分:1)

与您所拥有的相似但没有在其间创建字典:

In [120]: d = {1:'one', 2:'two'}
     ...: class X(object):
     ...:     a = 1
     ...:     b = 2
     ...:

In [121]: class Y(X):
     ...:     @classmethod
     ...:     def change_me(cls):
     ...:         for k, v in X.__dict__.items():
     ...:             if v in d:
     ...:                 setattr(cls, k, d[v])
     ...:

In [122]: Y.a
Out[122]: 1

In [123]: Y.change_me()

In [124]: Y.a
Out[124]: 'one'

In [125]: X.a
Out[125]: 1

这是一个使用元类的版本,它解决了您必须明确运行 classmethod 的问题(假设是python3):

In [145]: d = {1:'one', 2:'two'}
     ...: class X(object):
     ...:     a = 1
     ...:     b = 2
     ...:
     ...:

In [146]: class ChangeOnCreation(type):
     ...:     def __init__(cls, name, bases, attr_dict):
     ...:         super().__init__(name, bases, attr_dict)
     ...:         for subs in bases:
     ...:             for k, v in subs.__dict__.items():
     ...:                 if v in d:
     ...:                     setattr(cls, k, d[v])
     ...:

In [147]: class Y(X, metaclass=ChangeOnCreation):
     ...:     pass
     ...:

In [148]: Y.a
Out[148]: 'one'

In [149]: X.a
Out[149]: 1

答案 1 :(得分:0)

什么阻止您直接在类型(类)上分配值? e.g:

class X(object):
    a = 1
    b = 2

d = {1: 'one', 2: 'two'}

class Y(X): pass

for k in dir(Y):
    val = getattr(Y, k)
    try:
        if val in d:
            setattr(Y, k, d[val])
    except TypeError:
        pass  # ignore the types that cannot be in our `d`

assert Y.a == "one" and Y.b == "two"