关于oop:Python中的对象树

Object trees in Python

为了访问对象,我希望在字典或类似对象上自动完成。以下是我目前拥有的:

1
2
3
4
5
class Foo:
   def DoFoo(self):
      pass

list = {"x": Foo(),"y": Foo()}

现在我想做的是:

1
list.x.DoFoo()

如何用以后可以用IPython自动完成访问的对象填充列表?

我需要像我在这里看到的那样的"一流工厂"吗?


自定义类的实例可以作为您在其上设置的属性的容器。这可以简单地开始:

1
2
3
4
5
6
7
8
class MyContainer:
   pass

a = MyContainer()
a.x = Foo()
a.y = Foo()

a.x.DoFoo()

您可以使传递作为构造函数一部分的属性的能力变得更加复杂(使用与dict构造函数相同的语义):

1
2
3
4
5
6
7
def MyContainer:
    def __init__(self, vals={}, **kwvals):
        self.__dict__.update(vals, **kwvals)

a = MyContainer({"x":Foo()}, y=Foo())   # there are multiple ways to pass the args

a.x.DoFoo()

如果在创建此类容器之后不需要添加或删除值,则可以使用标准库的collections.namedtuple类工厂。向它传递一个类名和一系列属性名,它将返回一个新类。

1
2
3
4
5
6
7
from collections import namedtuple

A = namedtuple("A", ["x","y"])
a = A(Foo(), y=Foo())       # can use positional or keyword arguments

a.x.DoFoo()      # this still works!
a.x ="something else"      # but this will raise an error

您需要覆盖__getattr__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Foo(object):

    attr_a = 'default_attr_a_value'
    attr_b = 'default_attr_b_value'

    def __init__(self, *args, **kwargs):
        if len(args) >= 2:
            self.attr_a = args[0]
            self.attr_b = args[1]
        if len(args) == 1:
            self.attr_a = args[0]

        # holds the"emulated" attributes
        self._properties = kwargs

    def __getattr__(self, name):
        if name in self._properties:
            return self._properties[name]
        else:
            raise AttributeError

    def __hasattr__(self, name):
        return name in self._properties

bar = Foo('modified_value_of_attr_a', **{'aaa':1,'bbb':2})

print bar.attr_a
print bar.attr_b
print bar.aaa

try:
    print bar.sss
except AttributeError:
    print 'Attribute error raised!'

list_attrs = ['attr_a', 'aaa', 'sss']
for a in list_attrs:
    if hasattr(bar, a):
        print 'bar, instance of Foo, has an attribute named"%s"' % a
    else:
        print 'bar, instance of Foo, doesn\'t have an attribute named"%s"' % a

多读