2

这是我的第一个问题的链接:从字典创建类实例?
所以我试图从包含类没有的键的字典中创建类实例。例如:

class MyClass(object):
    def __init__(self, value1, value2):
        self.attr1 = value1
        self.attr2 = value2

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}

在创建类实例之前,我必须redundant_key从 dict中删除它

dict.pop('redundant_key', None)
new_instance = MyClass(**dict)

问题是我有几个类和几个带有很多键的字典(我有几个 json 格式的响应,它们表示为字典,我想从这个 json 响应创建对象)。我已经从上一个问题中找到了一个临时解决方案 - 如何删除冗余键。我只能使用我需要的键从旧字典创建新字典:

new_dict = {key: old_dict[key] for key in allowed_keys}

所以这里是代码:

class MyClass(object):
    def __init__(self, value1, value2):
        self.attr1 = value1
        self.attr2 = value2

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}
new_instance = MyClass(**{key: dict[key] for key in allowed_keys})

我现在只需要得到allowed_keys. 所以问题 - 有没有办法在不创建类实例的情况下获取类实例属性?

4

4 回答 4

3

如果您坚持使用过于通用的字典来初始化您的对象,只需定义__init__接受但忽略额外的键。

class MyClass(object):
    def __init__(self, attr1, attr2, **kwargs):
        self.attr1 = attr1
        self.attr2 = attr2

d = {'attr1': 'value1', 'attr2': 'value2', 'extra_key': 'value3'}
new_instance = MyClass(**d)

如果您无法修改__init__(如果它从 SQLAlchemy 声明性基础继承,似乎就是这种情况),请添加一个替代构造函数以接受所有关键字参数,但选择您需要的那些。

class MyClass(Base):
    @classmethod
    def from_dict(cls, **kwargs):
        # Let any KeyErrors propagate back to the caller.
        # They're the one who forgot to make sure **kwargs
        # contained the right keys.
        value1 = kwargs['attr1']
        value2 = kwargs['attr2']
        return cls(value1, value2)

new_instance = MyClass.from_dict(**d)
于 2015-05-08T17:27:37.267 回答
1

免责声明:这回答了 OP 所询问的内容(获取实例的属性),而不是他们需要的内容。这似乎是构造函数的参数列表。

你不能做你想做的事。在 python 中,属性被动态添加到类的实例中。同一类的两个实例可以具有不同的属性。嗯......准确地说,有一些东西叫做实例属性和属性。

实例属性是与类的实例相关联的属性。类属性与其定义相关联,即如果你写了 ( MyClass.foo)

如果您查看示例,则会在__init__on期间添加属性,self因此它们是实例属性。

你可以做的是创建一个有效的实例并检查它(看下面的例子),提供一个静态列表allowed_keys(例如作为一个类属性),或者以某种方式要求allowed_keys作为构造函数参数。所有这些都是一种解决方法,因为您真正需要的是不可能的。他们有他们的优点和缺点。

示例

class MyClass(object):
    def __init__(self, value1, value2):
        self.attr1 = value1
        self.attr2 = value2

instance = MyClass(1,2)                        # create a valid object
instance_attributes = instance.__dict__.keys() # inspect it
print(instance_attributes)
于 2015-05-08T17:01:18.210 回答
1

以下是您尝试做的事情的方法:使用适当的参数实例化您的类。请注意,您不是在检查__init__创建的属性,而是检查它接受的参数。它对它们做什么并不重要——当您调用构造函数时,这不是您关心的问题。

myparams = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}
usable = { k:v for k, v in myparams if k in MyClass.__init__.__code__.co_varnames }
new_instance = MyClass(**usable)

为了清晰起见,我使用了过滤的字典理解,但您当然可以一步完成。

PS。请注意,如果您的字典之一恰好包含 key ,您将遇到问题self。:-) 如果您不能信任您的数据源,您可能希望将其过滤掉。

于 2015-05-08T17:18:34.063 回答
1

您应该提到过,您需要 SQLAlchemy-Mapper-Class 的列。这是一个更容易的任务:

dict = {'attr1': 'value1', 'attr2': 'value2', 'redundant_key': 'value3'}
columns = YourTable.__table__.columns.keys()
entry = YourTable(**{k: dict[k] for k in columns})
于 2015-05-08T17:43:04.823 回答