将字典键设置为类实例的属性

时间:2014-12-06 15:51:05

标签: python class dictionary key

我有一个存储类foo对象的字典。类foo具有属性Name。对于每个实例,我希望Name属性是字典中实例的关键。该类的所有实例都将在字典中定义。

class foo:
    def __init__(self):
        self.Name = None  #self.Name should equal "self"

foo_dict = {
'foo1' = foo()
}

#(foo.Name should equal 'foo1')

如何将Name属性设置为字典中实例的键?

评论是否需要规范。

3 个答案:

答案 0 :(得分:1)

反过来说:

class Foo:
    def __init__(self, name=None):
        self.name = name

foo1 = Foo('foo1')
foo_dict = {
    foo1.name: foo1
}

答案 1 :(得分:1)

似乎您需要对实例的引用才能执行您想要的操作。如果您使用理解构建字典,则可以创建实例引用并使用它们。

class Foo(object):
    def __init__(self, n = None):
        self.name = n

d = {f.name:f for f in (Foo(n) for n in 'abcd')}

>>> d
{'a': <__main__.Foo object at 0x03DF9710>, 'c': <__main__.Foo object at 0x03E01250>, 'b': <__main__.Foo object at 0x03DF9A50>, 'd': <__main__.Foo object at 0x03E01290>}
>>> 
>>> d = {f.name:f for f in (Foo(n) for n in [1])}
>>> d
{1: <__main__.Foo object at 0x03E01B50>}
>>> foo_dict = {}
>>> foo_dict.update(d)
>>> foo_dict
{1: <__main__.Foo object at 0x03E01B50>}
>>> 

前几天我偶然发现了this SO answer。使用该类装饰器/描述符,您可以创建一个生成Foo个对象的类工厂,并跟踪当前对象和下一个对象的计数器。

class InnerClassDescriptor(object):
    '''allows access to the outer class and its attributes

    decorator/descriptor
    an instance of a nested inner class can access the outer class and its attributes
    '''
    def __init__(self, cls):
        self.cls = cls
    def __get__(self, instance, outerclass):
        class Wrapper(self.cls):
              outer = instance
        Wrapper.__name__ = self.cls.__name__
        return Wrapper

class FooFactory(object):
    next_foo = 0
    this_foo = None
    @InnerClassDescriptor
    class Foo(object):
        def __init__(self):
            # print 'Foo,__init__, next_foo = ', self.outer.next_foo
            self.name = 'Foo' + str(self.outer.next_foo)
            self.outer.next_foo += 1
            self.outer.this_foo = self 

用法:

ff = FooFactory()
d = {ff.this_foo.name:ff.Foo()}
for k, v in d.items():
    print k, v.name

>>> 
Foo0 Foo0
>>>

这依赖于在键之前计算的字典项值 - 这似乎是Python 2.7的情况

答案 2 :(得分:1)

我无法强调这是多么糟糕......请,请将此仅用于教育目的。它非常脆弱,不可靠... BAD 如果您更改了代码中的任何内容,它将停止工作。这东西好脏。它可能是不便携式的... OMG ......我认为当我点击发布你的答案时,有几只小猫被杀了

import inspect
import re

class Foo(object):
        def __init__(self):
            r = re.compile(
                r"\W+['\"](?P<name>\w+)['\"]\W+%s\W+"
                % self.__class__.__name__
            )
            caller_frame = inspect.currentframe().f_back
            code_context = inspect.getframeinfo(caller_frame).code_context
            match = r.match(''.join(code_context))
            if match:
                self.name = match.groupdict()['name']
                print "Assigned name: %s" % self.name
            else:
                raise Exception("This wasn't called as it was supposed to")

if __name__ == "__main__":
    foo_dict = {
        'foo1': Foo(),
        'foo2': Foo(),
    }

但它确实是你要求的:

borrajax@borrajax:/tmp$ python ./test.py 
Assigned name: foo1
Assigned name: foo2

现在,我要做的是:

选项1:

在初始化中传递名称。

可能是最简单,最易维护的代码,使代码处于更清晰的状态(如果其他人读取您的代码,则很重要)

class Foo(object):
        def __init__(self, name):
            self.name = name
            print "Assigned name: %s" % self.name

if __name__ == "__main__":
    foo_dict = {
        'foo1': Foo('foo1'),
        'foo2': Foo('foo2'),
    }

选项2:

创建您自己的dict课程并覆盖__setitem__方法(另请参阅Subclassing Python dictionary to override __setitem__How to "perfectly" override a dict?):

class Foo(object):
    pass

class MyDict(dict):
    def __setitem__(self, key, val):
        if not isinstance(val, Foo):
            raise TypeError("My dict only accepts %s" % Foo)
        val.name = key
        print "Assigned name: %s" % val.name
        return super(MyDict, self).__setitem__(key, val)

if __name__ == "__main__":
    foo_dict = MyDict()
    foo_dict['foo1'] = Foo()
    foo_dict['foo2'] = Foo()
    foo_dict['foo3'] = 1

打印:

borrajax@borrajax:/tmp$ python ./test.py 
Assigned name: foo1
Assigned name: foo2
Traceback (most recent call last):
  File "./stack64.py", line 17, in <module>
    foo_dict['foo3'] = 1
  File "./stack64.py", line 8, in __setitem__
    raise TypeError("My dict only accepts %s" % Foo)
TypeError: My dict only accepts <class '__main__.Foo'>

这样做的缺点是魔法在分配给字典时将属性(.name)添加到Foo的实例,这可能会导致名称冲突(如果您的{ {1}}类已经有Foo,此方法会更改其值)。一般来说,我不会忘记在执行过程中神奇地向实例添加属性的方法。

选项3:

使用@ Daniel&#39; answer来解决此问题。对于阅读代码的其他人来说,清洁和易懂。