0

如何__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 初始化以绕过被误导的东西,但我认为如果没有重构工具,这将无法轻松解决。

4

2 回答 2

2

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

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

中的代码__metaclass__.__new__()仅在创建的实例时执行,即在 classB的定义期间,而不是在B创建 class 的实例时执行,因此复制所有方法的开销只会在这种情况下发生——通常是一次。请注意,由于类方法也是描述符对象,因此有必要调用__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
于 2013-10-27T13:02:18.127 回答
1

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

也就是说,您可以替换:

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

和:

locals()['f2'] = A.__dict__ ['f2']

这不能保证有效,因为您不允许修改locals(),但它似乎至少在 CPython 2.7.5 中有效:

class Foo:
    a = locals()
    locals()['b'] = 0

print Foo.a is Foo.__dict__, Foo.b

输出True 0。有趣的是,它输出False 0ifFoo继承自object,这表明我所处的困境。

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

于 2013-10-27T09:32:30.027 回答