不明白为什么点符号不适用于合成对象

时间:2019-10-01 20:42:37

标签: python class hierarchy composition

这就是我正在尝试的

# This is how I understood composition to work
class A():
    def __init__(self):
        self.attr1 = ''
        self.attr2 = 0
        self.attr3 = ''

    def some_update(self, newval):
        self.attr3 = newval

class B():
    def __init__(self):
        self.attr4 = ''
        self.sub1 = A()
    self.sub2 = A()
        self.sub2.attr1 = subspecialval

    def different_update(self, newval1, newval2)
        self.sub1.attr2 = newval1
        self.sub2.attr2 = newval2

def __main__():
    my_obj = B()
    B.sub1.attr = 'some string'               # This doesn't work
    setattr(B, 'sub1.attr1', 'some string')   # This works
    print(B.sub1.attr1)                       # This doesn't work
    print(getattr(B, 'sub1.attr1'))           # This works

if __name__ == '__main__':
    main()

问题是,为什么点表示法不扩展到组合类(B),但是getattr / setattr能够正确协商类继承关系?我以为每个点都将延伸到层次结构中的下一个对象级别,但是它似乎无法正常工作

2 个答案:

答案 0 :(得分:1)

  

getattr / setattr能够正确协商类层次结构吗?

不是。

setattr(B, 'sub1.attr1', 'some string')设置文字属性'sub1.attr1'。什么都没有遍历或协商。

请记住,您是在类(B)而不是实例(my_obj)上设置属性。 my_obj.sub1.attr就可以了。

class A:
    def __init__(self):
        self.attr2 = ''

class B:
    def __init__(self):
        self.a = A()


B.a.attr1 = ''

AttributeError: type object 'B' has no attribute 'a'

另一方面,

b = B()
b.a.attr1 = 'attr1'
print(b.a.attr1)

工作。


setattr(B, 'a.attr1', 'new')在做什么?

它在'a.attr1 自身上设置文字属性B。一切都不必动摇或协商。

setattr(B, 'a.attr1', 'new')
print(B.__dict__)

输出

{'__module__': '__main__', '__init__': <function B.__init__ at 0x00000188F1EB9F28>, 
 '__dict__': <attribute '__dict__' of 'B' objects>, 
 '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None, 
 'a.attr1': 'new'}

答案 1 :(得分:0)

您对类和python有基本的误解。

B.sub1.attr = 'some string'不起作用

B是类型<class 'B'>。类型sub1中没有属性B

但是

我相信您期望使用类型<class 'A'>,可以通过在类级别定义该属性来实现:

>>> class A:
...     pass
...
>>> class B:
...     sub1 = A()
...
>>> B.sub1
<__main__.A object at 0x7fa2e1d1c490>

奇怪的是,同样的sub1也可用作实例属性。如果您和我一样,那是python中的错误,请打开讨论。

>>> b = B()
>>> b.sub1
<__main__.A object at 0x7fa2e1d1c490>

setattr(B, 'sub1.attr1', 'some string')有效

如果第一个参数是类的实例,则

setattr将始终有效。它强制属性可用。它在类对象中创建属性。

B.sub1.attr1不起作用。 getattr(B, 'sub1.attr1')确实

这是最奇怪的,我也不知道。归结为对setattr(B, 'sub1.attr1', 'some string')的调用。如前所述,强制使用属性。

我认为正在发生的事情是您无法通过python语法访问该属性,因为该属性名称实际上包含一个点sub1.attr1。但是您可以将原始字符串作为属性名称传递给getattr,这就是它起作用的原因。

但是

在这种情况下,您可能想做的就是将属性设置为类'A'的实例。

>>> class A:
...     def __init__(self):
...             self.attr1 = 'attr A'
...
>>> class B:
...     pass
...
>>> setattr(B, 'sub1', A())
>>> B.sub1.attr1
'attr A'

但是到那时属性sub1.attr1不存在!

>>> getattr(B, 'sub1.attr1')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'B' has no attribute 'sub1.attr1'

结论

您正在使用内置函数getattrsetattr做一些非常奇怪的事情。如果您正在学习,那很好,但是请注意,它需要了解语言中正在发生的事情才能成功使用此类功能。

有了足够的魔力,属性名称实际上可以有.个。