在类初始化程序中访问Python类`__dict__`?

时间:2013-10-27 09:23:25

标签: python class inheritance reflection initialization

如何在自己的“类初始化程序”(类定义)代码中访问类__dict__?如果不这样做,我怎样才能将类的定义属性作为字符串访问(这样可以生成名称,并以编程方式设置它们的值)

class A:  # from a library by a stubborn maintainer
  def __init__ (self):
    self.hello = "Hello"
    # + some huge misguided crap that I do not control
  def f1 (self):
    self.f2 ()
  def f2 (self):
    print self.hello

class B:
  f1 = A.__dict__ ['f1'] # works
  # how to loop over 2..10 and set B.f$i <- A.f$i ?
  # this doesn't work:
  #B.__dict__ ['f2'] = A.__dict__ ['f2']  # B not yet defined
  def __init__ (self):
    #self.hello = A ().hello  # the actual code has to be copied manually
    # misguided crap removed

a = B ()
a.f2()

最好不要复制/粘贴self.hello初始化只是为了绕过被误导的东西,但我不认为这可以很容易地帮助解决重构工具。

2 个答案:

答案 0 :(得分:2)

抱歉,在定义课程时,你无法真正做到这一点。换句话说,您无法在自己的定义中访问类__dict__,因为执行定义的结果将成为字典的内容(这就是为什么类名尚未绑定到任何内容)。可能最简单的解决方法是给你的班级__metaclass__

元类是类的类,因此它们的实例是类(因此名称)。为简单起见,我将B中的一个定义放在其中,因为它的用法和范围仅限于该类(但是,这不能在Python 3中完成)。

__metaclass__.__new__()中的代码仅在创建 it 的实例时执行,即在类B的定义期间执行,而不是在类B的实例时执行是创建的,因此复制所有方法的开销仅在发生时才会发生 - 通常是一次。请注意,因为类方法也是描述符对象,所以必须调用每个方法的__get__方法,以便获得将它们绑定到另一个类对象的正确值。有关详细信息,请参阅文档中的Raymond Hettinger标题为Descriptor HowTo Guide的部分。

class A(object):
    def __init__(self):
        self.hello = "Hello"
        # + some huge misguided crap that I do not control
    def f1(self):
        self.f2()
    def f2(self):
        print self.hello

class B(object):
    class __metaclass__(type):
        A_METHODS = ['f{}'.format(i) for i in xrange(1, 11)] # 'f1'...'f10'

        def __new__(mcls, classname, bases, classdict):
            classobj = type.__new__(mcls, classname, bases, classdict)
            classobj.hello = A().hello
            for fn in mcls.A_METHODS:
                if fn in A.__dict__:
                    setattr(classobj, fn, A.__dict__[fn].__get__(classobj, A))
            return classobj

    def __init__(self):
        pass

a = B()
a.f2()  # --> Hello

答案 1 :(得分:1)

完全可能有更好的方法(例如分支A类并删除误导的代码,或让每个B实例保持或共享A实例,或在{{1}的定义后修改B.__dict__完成)。

那就是说,你可以替换:

B

使用:

B.__dict__ ['f2'] = A.__dict__ ['f2']  # B not yet defined

这不保证可以正常工作,因为不允许修改locals()['f2'] = A.__dict__ ['f2'] ,但它似乎至少在CPython 2.7.5中起作用:

locals()

输出class Foo: a = locals() locals()['b'] = 0 print Foo.a is Foo.__dict__, Foo.b 。有趣的是,如果True 0继承自False 0,则会输出Foo,这表示我所处的水很难。

当然这是对特定于实现的行为的可怕滥用,不推荐,可能会出错某些地方,等等: - )