在更新“常量”时引发异常python 中的属性

发布于 2024-08-03 21:52:27 字数 665 浏览 4 评论 0原文

由于python没有常量的概念,如果更新“常量”属性是否可能引发异常?如何?

class MyClass():
    CLASS_CONSTANT = 'This is a constant'
    var = 'This is a not a constant, can be updated'

#this should raise an exception    
MyClass.CLASS_CONSTANT = 'No, this cannot be updated, will raise an exception'

#this should not raise an exception    
MyClass.var = 'updating this is fine'

#this also should raise an exception    
MyClass().CLASS_CONSTANT = 'No, this cannot be updated, will raise an exception'

#this should not raise an exception    
MyClass().var = 'updating this is fine'

任何将 CLASS_CONSTANT 更改为类属性或实例属性的尝试都应该引发异常。

将 var 更改为类属性或实例属性不应引发异常。

As python does not have concept of constants, would it be possible to raise an exception if an 'constant' attribute is updated? How?

class MyClass():
    CLASS_CONSTANT = 'This is a constant'
    var = 'This is a not a constant, can be updated'

#this should raise an exception    
MyClass.CLASS_CONSTANT = 'No, this cannot be updated, will raise an exception'

#this should not raise an exception    
MyClass.var = 'updating this is fine'

#this also should raise an exception    
MyClass().CLASS_CONSTANT = 'No, this cannot be updated, will raise an exception'

#this should not raise an exception    
MyClass().var = 'updating this is fine'

Any attempt to change CLASS_CONSTANT as a class attribute or as an instance attribute should raise an exception.

Changing var as a class attribute or as an instance attribute should not raise an exception.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情绪失控 2024-08-10 21:52:28

如果您确实想要无法更改的常量,请查看以下内容: http://code .activestate.com/recipes/65207/

If you really want to have constant that can't be changed then look at this: http://code.activestate.com/recipes/65207/

飘落散花 2024-08-10 21:52:28

开始阅读:

http://docs.python.org/reference/ datamodel.html#customizing-attribute-access

您基本上编写了自己的 __setattr__ 版本,它会引发某些属性的异常,但不会引发其他属性的异常。

Start reading this:

http://docs.python.org/reference/datamodel.html#customizing-attribute-access

You basically write your own version of __setattr__ that throws exceptions for some attributes, but not others.

那一片橙海, 2024-08-10 21:52:27

在每个类中自定义 __setattr__ (例如,如 @ainab 的答案所指向的我的旧食谱以及其他答案中所示例的),只能停止分配给 INSTANCE 属性而不是 CLASS 属性。因此,现有的答案都不能真正满足您所述的要求。

如果您要求的实际上正是您想要的,您可以诉诸自定义元类和描述符的某种组合,例如:

class const(object):
  def __init__(self, val): self.val = val
  def __get__(self, *_): return self.val
  def __set__(self, *_): raise TypeError("Can't reset const!")

class mcl(type):
  def __init__(cls, *a, **k):
    mkl = cls.__class__
    class spec(mkl): pass
    for n, v in vars(cls).items():
      if isinstance(v, const):
        setattr(spec, n, v)
    spec.__name__ = mkl.__name__
    cls.__class__ = spec

class with_const:
  __metaclass__ = mcl

class foo(with_const):
  CLASS_CONSTANT = const('this is a constant')

print foo().CLASS_CONSTANT
print foo.CLASS_CONSTANT
foo.CLASS_CONSTANT = 'Oops!'
print foo.CLASS_CONSTANT

这是非常高级的东西,因此您可能更喜欢中建议的更简单的 __setattr__ 方法其他答案,尽管它不符合您所述的要求(即,您可能会合理地选择削弱您的要求以获得简单性;-)。但这里的技术可能仍然很有趣:自定义描述符类型 const 是另一种方式(恕我直言,比在每个需要一些常量的类中覆盖 __setattr__ 好得多,并且使所有属性常量而不是挑选和选择...)来阻止对实例属性的赋值;代码的其余部分是关于自定义元类创建其自身独特的每类子元类,以便充分利用所述自定义描述符并实现您特别要求的确切功能。

Customizing __setattr__ in every class (e.g. as exemplified in my old recipe that @ainab's answer is pointing to, and other answers), only works to stop assignment to INSTANCE attributes and not to CLASS attributes. So, none of the existing answers would actually satisfy your requirement as stated.

If what you asked for IS actually exactly what you want, you could resort to some mix of custom metaclasses and descriptors, such as:

class const(object):
  def __init__(self, val): self.val = val
  def __get__(self, *_): return self.val
  def __set__(self, *_): raise TypeError("Can't reset const!")

class mcl(type):
  def __init__(cls, *a, **k):
    mkl = cls.__class__
    class spec(mkl): pass
    for n, v in vars(cls).items():
      if isinstance(v, const):
        setattr(spec, n, v)
    spec.__name__ = mkl.__name__
    cls.__class__ = spec

class with_const:
  __metaclass__ = mcl

class foo(with_const):
  CLASS_CONSTANT = const('this is a constant')

print foo().CLASS_CONSTANT
print foo.CLASS_CONSTANT
foo.CLASS_CONSTANT = 'Oops!'
print foo.CLASS_CONSTANT

This is pretty advanced stuff, so you might prefer the simpler __setattr__ approach suggested in other answers, despite it NOT meeting your requirements as stated (i.e., you might reasonably choose to weaken your requirements in order to gain simplicity;-). But the techniques here might still be interesting: the custom descriptor type const is another way (IMHO far nicer than overriding __setattr__ in each and every class that needs some constants AND making all attributes constants rather than picking and choosing...) to block assignment to an instance attribute; the rest of the code is about a custom metaclass creating unique per-class sub-metaclasses of itself, in order to exploit said custom descriptor to the fullest and achieving the exact functionality you specifically asked for.

听,心雨的声音 2024-08-10 21:52:27

你可以这样做:
(来自http://www.siafoo.net/snippet/108

class Constants:
  # A constant variable
  foo = 1337

  def __setattr__(self, attr, value):
    if hasattr(self, attr):
      raise ValueError, 'Attribute %s already has a value and so cannot be written to' % attr
    self.__dict__[attr] = value

然后像这样使用它这:

>>> const = Constants()
>>> const.test1 = 42
>>> const.test1
42
>>> const.test1 = 43
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __setattr__
ValueError: Attribute test1 already has a value and so cannot be written to
>>> const.test1
42

You could do something like this:
(from http://www.siafoo.net/snippet/108)

class Constants:
  # A constant variable
  foo = 1337

  def __setattr__(self, attr, value):
    if hasattr(self, attr):
      raise ValueError, 'Attribute %s already has a value and so cannot be written to' % attr
    self.__dict__[attr] = value

Then use it like this:

>>> const = Constants()
>>> const.test1 = 42
>>> const.test1
42
>>> const.test1 = 43
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __setattr__
ValueError: Attribute test1 already has a value and so cannot be written to
>>> const.test1
42
不必你懂 2024-08-10 21:52:27

您可以使用元类来实现此目的:

class ImmutableConstants(type):
    def __init__(cls, name, bases, dct):
        type.__init__(cls, name, bases, dct)

        old_setattr = cls.__setattr__
        def __setattr__(self, key, value):
            cls.assert_attribute_mutable(key)
            old_setattr(self, key, value)
        cls.__setattr__ = __setattr__

    def __setattr__(self, key, value):
        self.assert_attribute_mutable(key)
        type.__setattr__(self, key, value)

    def assert_attribute_mutable(self, name):
        if name.isupper():
            raise AttributeError('Attribute %s is constant' % name)

class Foo(object):
    __metaclass__ = ImmutableConstants
    CONST = 5
    class_var = 'foobar'

Foo.class_var = 'new value'
Foo.CONST = 42 # raises

但是您确定这是一个真正的问题吗?您真的不小心到处设置常量吗?您可以使用 grep -r '\.[AZ][A-Z0-9_]*\s*=' src/ 轻松找到其中的大部分内容。

You can use a metaclass to achieve this:

class ImmutableConstants(type):
    def __init__(cls, name, bases, dct):
        type.__init__(cls, name, bases, dct)

        old_setattr = cls.__setattr__
        def __setattr__(self, key, value):
            cls.assert_attribute_mutable(key)
            old_setattr(self, key, value)
        cls.__setattr__ = __setattr__

    def __setattr__(self, key, value):
        self.assert_attribute_mutable(key)
        type.__setattr__(self, key, value)

    def assert_attribute_mutable(self, name):
        if name.isupper():
            raise AttributeError('Attribute %s is constant' % name)

class Foo(object):
    __metaclass__ = ImmutableConstants
    CONST = 5
    class_var = 'foobar'

Foo.class_var = 'new value'
Foo.CONST = 42 # raises

But are you sure this is a real issue? Are you really accidentally setting constants all over the place? You can find most of these pretty easily with a grep -r '\.[A-Z][A-Z0-9_]*\s*=' src/.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文