Python 在模块级或类内定义列表

Python 在模块级或类内定义列表,python,python-3.x,oop,Python,Python 3.x,Oop,我有一个类方法,通过将字典与列表进行比较,验证字典是否包含我期望它包含的所有键 目前,我在类的模块级别定义了集合,如下所示: expected_keys = { 'key1', 'key2', 'key3', 'key4', } class Spam(object): def __init__(self, config_dict): try: self.validate_configs(configs)

我有一个类方法,通过将字典与列表进行比较,验证字典是否包含我期望它包含的所有键

目前,我在类的模块级别定义了集合,如下所示:

expected_keys = {
    'key1',
    'key2',
    'key3',
    'key4',
}

class Spam(object):
    def __init__(self, config_dict):
        try:
            self.validate_configs(configs)
        except TypeError, ValueError:
            raise

        ...

    def validate_configs(self, config_dict):
        if not isinstance (config_dict, dict):
            raise TypeError('Config structure is not a dictionary.')

        if not expected_keys == config_dict.keys():
            raise ValueError('Config dict does not have all necessary keys.')

这是最好的(性能和实践方面的)方法吗?我计划一次实例化数百个这样的对象,我不确定当前方法是否会导致性能下降。真正的
预期的\u键集也包含约30个条目。只要我做得正确,我就可以克服它在源文件中的丑陋(“应该有一种——最好只有一种——明显的方法来做”)。

扩展@PM2Ring的评论,你应该做几件事:

1.)将
期望的\u键
更改为
(当前它是
元组
。一个集用
{}
表示)。根据@PM2Ring的注释,如果类对象已修复,则可以将其作为
类属性来保持整洁:

class Spam(object):
    expected_keys = {
        'key1',
        'key2',
        'key3',
        'key4',
    }

    def __init__(self, config_dict):
        # continue defining the rest of your class...
2.)将上次验证更改为:

if not expected_keys.issubset(config_dict.keys()):
    raise ValueError('Config dict does not have all necessary keys.')
这将检查
config_dict
是否包含所有
预期的密钥
,但仍将验证
config_dict
是否有其他与预期不同的密钥

如果根据您的注释,
config\u dict
必须具有与
预期的\u键
完全相同的键(不多也不少),则您应验证为:

if not expected_keys == config_dict.keys():
    raise ValueError('Config dict does not have all necessary keys.')

您的
all
测试将检查
期望的\u键是否是
config\u dict
键的子集。使用set操作可以更快地完成这项操作,因此
期望的_键应该是set,而不是list。(
config_dict.keys()
自动成为类似集合的对象)。它应该是一个子集,还是这两个集合应该相等?这两个集合应该相等。我想也许我应该检查
config_dict.keys()
期望的键之间是否相等?我知道
config\u dict.keys()
会返回一个
dict\u keys
对象,不过顺便说一句,如果在
中除了
raise
之外,你不需要在
初始化中尝试
。这将自动发生。@PM2Ring fair point-尽管在实际实现中,它发生在类中其他位置的不同函数中。这是我的quick-n'-肮脏但仍然有效的例子。我绝对会在未来的项目中牢记这一点。@problem_代码,前提是您的
预期_键在整个类中保持不变(即实例之间没有区别),将其放在类中最有意义,因为它真正属于对象而不是主体。就性能而言,我认为这不会有什么不同。但是,如果您确实将其设置为实例属性(
self.expected\u keys
),则如果您实例化了不合理的数量,则可能会影响性能。@problem\u代码类属性由所有实例共享,不会复制到实例中。因此,它使用的内存量与使其成为一个全局的内存量相同。是的,通常的做法是在
\uuuu init\uuu
之前定义类属性。您只需使用裸名称
expected\u keys
进行定义,但在方法中,您可以使用
Spam从中读取。expected\u keys
self。expected\u keys
@problem\u code FWIW,您可能希望向该值错误消息添加更多信息。例如,您可以执行
keys=config_dict.keys()
,查看
keys
是否等于
self.expected_-keys,如果失败,则计算
missing=self.expected_-keys;unknown=keys-self.expected_keys`并打印结果。@pm2很有趣,我不相信
self.expected_keys
会是一个有效的引用,但确实是。我会想象它仅限于垃圾邮件。仅应为\u keys
self.expected\u keys
上的名称解析首先检查实例属性,如果找不到实例属性,则查找类属性。