【问题标题】:Set dictionary key to attribute of class instance将字典键设置为类实例的属性
【发布时间】:2014-12-06 15:51:05
【问题描述】:

我有一个字典,它存储类 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 属性设置为字典中实例的键?

如果需要规范,请发表评论。

【问题讨论】:

  • 如何访问Name 属性?
  • 初始化中
  • 可以在实例化变量之前访问它吗?你有没有尝试解决这个问题?
  • 好吧,我不这么认为。至于尝试,我知道我需要使用self.Name = foo_dict[???]。但是由于实例化是在创建字典键/字典条目之后发生的,我不能以某种方式将键分配给self.Name吗?
  • 如果你这样做,.Name 会是什么:f = foo(); foo_dict = {'foo1': f, 'foo2': f,}

标签: python class dictionary key


【解决方案1】:

反过来做:

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

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

【讨论】:

  • 我说,“类的所有实例都将在字典中定义”。这意味着实例将在字典中实例化并被分配一个字典键。 foo_dict = {'foo1': Foo()}
【解决方案2】:

我怎么强调都不过分……拜托,拜托,仅将其用于教育目的。它易碎、不可靠... 糟糕如果您更改代码中的任何内容,它就会停止工作。这东西好脏。它可能是不可携带的……天哪……我想当我点击 Post Your Answer

时有几只小猫被杀了
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 的实例中,这可能会导致名称冲突(如果您的 Foo 类已经有一个.name,这个方法会改变它的值)。一般来说,我会远离那些在执行过程中神奇地为实例添加属性的方法。

选项 3:

使用@Danielanswer 回答这个问题。其他人阅读您的代码时清晰易懂。

【讨论】:

    【解决方案3】:

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

    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 的情况

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-12
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 2012-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多