我想创建一个一次性的“struct”对象来保存各种状态标志。我的第一个方法就是这个(javascript风格)
>>> status = object()
>>> status.foo = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'
绝对不是我的预期,因为这有效:
>>> class Anon: pass
...
>>> b=Anon()
>>> b.foo = 4
我想这是因为object()没有__dict__
。我不想使用字典,假设我不想创建Anon对象,还有其他解决方案吗?
答案 0 :(得分:23)
制作“可以指定/获取属性的通用对象”的最简洁方法可能是:
b = lambda:0
正如大多数其他答案所指出的那样,还有很多其他的方法,但是为了简明起见很难击败这一个(lambda:0
与object()
完全相同的字符数...... ;-)
答案 1 :(得分:15)
来自Python Official Documentation:
9.7。赔率和结束
有时获取数据很有用 类似于Pascal“记录”或类型 C“struct”,捆绑在一起 命名数据项。一个空课 定义会做得很好:
class Employee:
pass
john = Employee() # Create an empty employee record
# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
这似乎很自然而简单:Pythonic。 Remember the Zen!“简单比复杂更好”(编号3)和“如果实施容易解释,那可能是个好主意”(编号11)
此外,struct
只是公共成员的class
(即struct{};
和class{public:};
完全相同(例如,C ++) )。您是否应该考虑这一点并避免在Python程序中使用人工构造? Python应该是可读的,可维护的,易于理解的。
答案 2 :(得分:9)
我曾经有过同样的问题。我在邮件列表中问过它,Alex Martelli指出object
是Python中所有继承的基础;如果object()
使用自己的字典创建了一个类实例,那么Python中的每个对象都必须有自己的字典,这会浪费内存。例如,True
和False
是对象;显然他们对自己的词典没有任何需要!
如果有某种内置的Python功能,我会很高兴我可以说:
x = struct()
x.foo = 1
x.bar = 2
但是写struct()
:
class struct(object):
pass
或者你可以稍微复杂一点:
class struct(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
更复杂的一个允许你这样做:
x = struct(foo=1, bar=2)
print(x.foo) # prints 1
print(x.bar) # prints 2
x.baz = 3
print(x.baz) # prints 3
但写struct()
是如此微不足道,我想这不值得添加到语言中。也许我们应该推动将标准功能添加到collections
模块或其他内容。
答案 3 :(得分:4)
我个人认为最干净的解决方案是你已经猜到的:
class Scratch(object):
pass
s = Scratch()
s.whatever = 'you want'
我知道你说你不想要__dict__
,但这让我感到困惑,因为我看不出有理由关心这一点。您不必引用__dict__
,这是内部Python实现细节。无论如何,Python中允许动态添加属性的任何实例都将具有__dict__
,因为这就是Python执行动态属性的方式。即使实例是以非常聪明的方式创建的,它也会有__dict__
。
如果你还没有这样做,我建议你阅读PEP 20和PEP 8(没有声望,所以对我来说只有一个链接。)并不是说PEP与你的问题直接相关,但我认为它有用开始以 Pythonic 方式使用Python。
答案 4 :(得分:3)
试试这个
>>> status=type('status',(object,),{})()
>>> status.foo=3
>>> status.foo
3
如果您不想
,则无需为该课程命名>>> status=type('',(object,),{})()
>>> status.__class__.__name__
''
答案 5 :(得分:2)
这里的谜团是 对象 和 类实例 之间的区别。
在Python中,一切都是对象。类是对象,整数是对象,类型是对象,类实例是对象。当你说object()
时,你得到一个简单的基础对象。没什么。完全没用。比您在Python中可以引用的任何其他级别更低级别。
您可能认为调用object()
会为您提供一个类实例。这是可以理解的,因为您可能认为object
是一个类。不是。即使您可能这么认为,因为它是用于新式类定义的基础“类”,如:
class MyClass(object):
pass
object
实际上是 类型 (类似于str
和int
类型)。当您调用object()
时,您没有构建类实例,而是实例化一种特殊类型的对象。但是在object
的情况下,它完全是 blah 的特殊之处。
只有类实例具有使用点表示法处理事物的特殊能力。这不是所有对象的一般属性。想象一下,如果是这样的话!你可以做一些疯狂的事情,比如在字符串中添加属性:
s = "cat"
s.language = "english"
显然你不能这样做。
答案 6 :(得分:2)
当然总有namedtuple
。它既便宜又快速,但不可变 - 您必须事先知道您的属性名称和值,并且以后不能更改它们的值。但至少它有struct / object属性getters。它适用于Python 2和3
>>> from collections import namedtuple
>>> Status = namedtuple('Status', 'a b')
>>> s = Status(a=1, b=2)
>>> s.a + s.b
3
答案 7 :(得分:1)
如果您想要Javascript对象的语义,可以考虑使用namespaces library。您只需先pip install namespaces
。
>>> import namespaces as ns
>>> b = ns.Namespace()
>>> b.foo = 4
>>> b
Namespace(foo=4)
完整免责声明:我是namespaces
库的作者。