我有一个存储类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
属性设置为字典中实例的键?
评论是否需要规范。
答案 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
现在,我要做的是:
在初始化中传递名称。
可能是最简单,最易维护的代码,使代码处于更清晰的状态(如果其他人读取您的代码,则很重要)
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'),
}
创建您自己的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
,此方法会更改其值)。一般来说,我不会忘记在执行过程中神奇地向实例添加属性的方法。