Jim*_*ane 29 python oop class object expandoobject
在python中,如何在没有预定义类的情况下创建新对象,然后动态添加属性?
例:
dynamic_object = Dynamic()
dynamic_object.dynamic_property_a = "abc"
dynamic_object.dynamic_property_b = "abcdefg"
Run Code Online (Sandbox Code Playgroud)
最好的方法是什么?
编辑因为许多人在评论中建议我可能不需要这个.
问题是我有一个序列化对象属性的函数.出于这个原因,我不想因为一些构造函数的限制而创建一个期望类的对象,而是创建一个类似的对象,让我们说像模拟,添加我需要的任何"自定义"属性,然后将其反馈给功能.
Ned*_*der 40
只需定义自己的类即可:
class Expando(object):
pass
ex = Expando()
ex.foo = 17
ex.bar = "Hello"
Run Code Online (Sandbox Code Playgroud)
Blc*_*ght 19
使用对象来保存值并不是最恐怖的编程风格.它在编程语言中很常见,没有好的关联容器,但在Python中,你可以使用字典:
my_dict = {} # empty dict instance
my_dict["foo"] = "bar"
my_dict["num"] = 42
Run Code Online (Sandbox Code Playgroud)
您还可以使用"字典文字"一次定义字典的内容:
my_dict = {"foo":"bar", "num":42}
Run Code Online (Sandbox Code Playgroud)
或者,如果您的密钥都是合法标识符(如果您计划将它们作为属性名称,它们将是,)您可以使用dict
带有关键字参数的构造函数作为键值对:
my_dict = dict(foo="bar", num=42) # note, no quotation marks needed around keys
Run Code Online (Sandbox Code Playgroud)
填写字典实际上是Python在你使用对象时在幕后做的事情,例如在Ned Batchelder的回答中.他的ex
对象的属性存储在字典中ex.__dict__
,最终应该等于dict
直接创建的等价物.
除非ex.foo
绝对需要属性语法(例如),否则您也可以完全跳过该对象并直接使用字典.
saa*_*aaj 10
如果你从@ Martijn的回答中采用元类化方法,@ Ned的答案可以被重写得更短(虽然它显然不太可读,但做同样的事情).
obj = type('Expando', (object,), {})()
obj.foo = 71
obj.bar = 'World'
Run Code Online (Sandbox Code Playgroud)
或者只是,使用dict
参数与上面相同:
obj = type('Expando', (object,), {'foo': 71, 'bar': 'World'})()
Run Code Online (Sandbox Code Playgroud)
对于Python 3,bases
不需要将对象传递给参数(请参阅type
文档).
但是对于简单的情况,实例化没有任何好处,所以可以这样做:
ns = type('Expando', (object,), {'foo': 71, 'bar': 'World'})
Run Code Online (Sandbox Code Playgroud)
同时,我个人更喜欢普通的类(即没有实例化),因为ad-hoc测试配置案例最简单,最易读:
class ns:
foo = 71
bar = 'World'
Run Code Online (Sandbox Code Playgroud)
在Python 3.3+中,正是 OP要求的,types.SimpleNamespace
.只是:
一个简单的
object
子类,提供对其命名空间的属性访问,以及有意义的repr.
object
与之不同,SimpleNamespace
您可以添加和删除属性.如果SimpleNamespace
使用关键字参数初始化对象,则会将这些参数直接添加到基础命名空间.
import types
obj = types.SimpleNamespace()
obj.a = 123
print(obj.a) # 123
print(repr(obj)) # namespace(a=123)
Run Code Online (Sandbox Code Playgroud)
但是,在Python 2和Python 3的stdlib中argparse.Namespace
,它们具有相同的目的:
用于存储属性的简单对象.
通过属性名称和值实现相等性,并提供简单的字符串表示形式.
import argparse
obj = argparse.Namespace()
obj.a = 123
print(obj.a) # 123
print(repr(obj)) # Namespace(a=123)
Run Code Online (Sandbox Code Playgroud)
请注意,两者都可以使用关键字参数初始化:
types.SimpleNamespace(a = 'foo',b = 123)
argparse.Namespace(a = 'foo',b = 123)
Run Code Online (Sandbox Code Playgroud)
使用collections.namedtuple()
类工厂为您的返回值创建自定义类:
from collections import namedtuple
return namedtuple('Expando', ('dynamic_property_a', 'dynamic_property_b'))('abc', 'abcdefg')
Run Code Online (Sandbox Code Playgroud)
返回的值既可以用作元组,也可以通过属性访问使用:
print retval[0] # prints 'abc'
print retval.dynamic_property_b # prints 'abcdefg'
Run Code Online (Sandbox Code Playgroud)