【问题标题】:How to make abstract protected fields in Python class?如何在 Python 类中创建抽象受保护字段?
【发布时间】:2018-08-30 06:32:41
【问题描述】:

我需要编写几十个类,它们仅通过变量彼此不同,这对于类的稳定工作至关重要。没有这样的变量,类就无法工作,变量的改变可能会破坏它们。我已经编写了一个用于创建相应 metaclss 的代码:

from abc import ABCMeta, abstractmethod, abstractproperty
import re

def get_field_protector(*names):
    def check_attributes(cls):
        for t in names:
            if not hasattr(cls, t):
                raise Exception('Abstract field "{0}" have to be defined'.format(t))
    def decorate_new_method(inp_method, class_name):
        def inner(cls, *args, **kwargs):
            if cls.__new__.decorated==class_name:
                check_attributes(cls)
            return inp_method(cls, *args, **kwargs)
        return inner
    class result_protector(ABCMeta):
        def __setattr__(self, name, value):
            if name in names:
                raise Exception("Read only class attribute!")
            super(self.__class__, self).__setattr__(name, value)
        def __delattr__(self, name):
            if name in names:
                raise Exception("Read only class attribute!")
            super(self.__class__, self).__delattr__(name)
        def __init__(self, name, bases, attributes):
            super(self.__class__, self).__init__(name, bases, attributes)
            if not hasattr(self.__new__, 'decorated'):
                self.__new__=decorate_new_method(self.__new__, name)
                self.__new__.decorated=name
    return result_protector 

在我开始使用以下类之前它工作正常:

class test(object, metaclass=get_field_protector("essential_field")):
    essential_field="some_value"
    def __init__(self, val):
        self.val=val

当我尝试创建此类时,我收到:

>>> test(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/media/bykov/9016-4EF8/main_architecture.py", line 13, in inner
    return inp_method(cls, *args, **kwargs)
TypeError: object() takes no parameters

【问题讨论】:

  • 永远不要将type(self)(或self.__class__,这是一回事)传递给super!您的问题被标记为python-3.x,因此请改用super()。见Shortcut for super(type(self), self)
  • 你真的需要那个防御吗? Python 是一种动态语言,它更多地依赖于约定适当的文档,而不是语言强制的限制,试图与 Python 的本质作斗争大多是浪费时间。
  • @brunodesthuilliers 这不应该是重复的。它不能解决问题。
  • 我不明白你为什么要覆盖/装饰类的 __new__ 方法。您知道每次创建test 类的instance 时都会调用__new__,对吧?为什么每次创建新实例时都需要调用check_attributes?您不能在创建类后调用一次吗?
  • @Aran-Fey 也许你是对的。如果重新定义 new 方法,用户必须执行 super().__new__(cls, *args, **kwargs)

标签: python python-3.x metaprogramming


【解决方案1】:

布鲁诺的评论是正确的。在 Python 中,您不会“保护”父类的属性,您只需用两个前缀下划线命名它。在您的示例中__essential_field。这意味着不要把它留给任何后代。

【讨论】:

  • 我们的目标不是让它“像 C# 一样受到保护”,而是抛出异常,然后变量偶尔会被更改或忘记并且未定义。这样确实节省了调试的时间
猜你喜欢
  • 2020-01-12
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
  • 2020-08-16
  • 2017-11-28
  • 1970-01-01
相关资源
最近更新 更多