gpt4 book ai didi

python - 确保两个 Python 类具有相同名称的属性

转载 作者:太空狗 更新时间:2023-10-30 02:26:22 24 4
gpt4 key购买 nike

我希望在 Python 中构建类接口(interface),但发现 Python 缺少接口(interface)结构。

我需要的是,如果程序员试图在一个类中添加新属性而不在另一个类中添加具有相同名称的属性,则会引发异常(在编译时或运行时)

一个例子:

class MongoCompany:
company_name = MongoField()

class ESCompany:
company_name = ESField()

如果程序员试图在不更改 ESCompany 的情况下向 MongoCompany 添加字段,则会引发异常。

class MongoCompany:
company_name = MongoField()
company_phone = MongoField()

class ESCompany:
company_name = ESField()

MongoCompany.init()

编辑:

背景这是为了防止程序员修改使用 Mongoengine 的 Document 类声明的 MongoDB 模式,而不对使用 elasticsearch-dsl 的 DocType 类在另一个文件中声明的 Elasticsearch 模式添加相应的修改。

最佳答案

耶!元类的实际应用并不是为了使用元类而设计的!我们可以编写一个元类,如果类定义中出现意外属性,它会抛出异常。我们需要做的就是确保您的程序员实际使用它。

class RequiredFieldsMeta(type):
_interface = {'company_name', 'num_employees'}

def __new__(cls, clsname, bases, attrs):
for field in RequiredFieldsMeta._interface:
if field not in attrs:
raise AttributeError(
'Class %s missing required property %s'
% (clsname, field))
for name in attrs:
if not isdunder(name) and name not in RequiredFieldsMeta._interface:
raise AttributeError(
'Class %s has extra property %s'
% (clsname, name))
return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)

# Works fine:
class MongoCompany(metaclass=RequiredFieldsMeta):
company_name = 'Mongo Inc.'
num_employees = 100

# Throws AttributeError:
class ESyCompany(metaclass=RequiredFieldsMeta):
extra_prop = 'foobar'

Here's快速演示

请注意我们甚至没有让它实例化:我们的检查在类本身被定义时运行。

编辑:在我的编辑中,我引用了一个函数 is_dunder。这可以像 name.startswith('__') 或正则表达式或任何你想要的一样简单,只要它摆脱了 python(而不是程序员)放在类上的属性。


编辑 2:为了好玩,这里有两个更“优雅”(虽然不那么具体)的检查实现:

def __new__(cls, clsname, bases, attrs):
attr_names = {a for a in attrs if not is_dunder(a)}

if attr_names.difference(RequiredFieldsMeta._interface):
raise AttributeError('Class %s has extra properties' % clsname)
if RequiredFieldsMeta._interface.difference(attr_names):
raise AttributeError('Class %s missing required properties' % clsname)

return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)

或者简单地说:

def __new__(cls, clsname, bases, attrs):
attr_names = {a for a in attrs if not is_dunder(a)}
if attr_names != RequiredFieldsMeta._interface:
raise AttributeError(
'Class %s does not match the required interface' % clsname)
return super(RequiredFieldsMeta, cls).__new__(cls, clsname, bases, attrs)

关于python - 确保两个 Python 类具有相同名称的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45316931/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com