Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
确保两个Python类具有相同名称的属性_Python_Class_Oop_Interface - Fatal编程技术网

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

确保两个Python类具有相同名称的属性,python,class,oop,interface,Python,Class,Oop,Interface,我希望用Python构建一个类接口,但发现Python缺少接口构造 我需要的是,如果程序员试图在一个类中添加新属性,而没有在另一个类中添加同名属性,则会引发一个异常(在编译时或运行时) 例如: 如果程序员试图在不更改ESCompany的情况下向MongoCompany添加字段,则会引发异常 class MongoCompany: company_name = MongoField() company_phone = MongoField() class ESCompany:

我希望用Python构建一个类接口,但发现Python缺少接口构造

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

例如:

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

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

class ESCompany:
    company_name = ESField()

MongoCompany.init()
编辑:

背景
这是为了防止程序员修改MongoDB使用Mongoengine的
文档
类声明的模式,而不添加对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'
快速演示

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

编辑:在我的编辑中,我引用了一个函数
is\u 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)

乍一看,您是否熟悉的概念?您可以创建一个“接口”类,该类继承自所需的各种方法上的
throw NotImplementedError
s。@MateenUlhaq它不会阻止程序员添加比“接口”类更多的属性,您可以在程序开始时进行快速运行时检查,以比较类。@MateenUlhaq您是指检查两个类的代码?没有pythonic类结构可以使用?啊,谢谢,我想这正是我需要的,但是代码没有按预期工作?MongoCompany抛出了一个错误。但是我明白了,在Python2和Python3之间,使用元类的语法发生了变化。你使用的是哪个版本?我相信是3.6.1,我正在运行你的快速演示。这是一个打字错误,还有其他的。。。。。我应该这样做。我刚才使用了
w.startswith(“'uuu')
作为我的“is dunder”谓词。如果需要更严格的检查,也可以使用正则表达式或check
endswith
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)