在枚举内定义一个类常量吗? [英] Is it possible to define a class constant inside an Enum?

查看:164
本文介绍了在枚举内定义一个类常量吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python 3.4引入了新的模块 枚举 ,它为该语言添加了枚举类型 enum.Enum 的文档提供了一个示例< a>演示如何扩展:

 >>>行星(枚举):
... MERCURY =(3.303e + 23,2.4397e6)
... VENUS =(4.869e + 24,6.0518e6)
... EARTH =(5.976e + 24,6.37814e6)
... MARS =(6.421e + 23,3.972e6)
... JUPITER =(1.9e + 27,7.1492e7)
... SATURN =(5.688e + 26,6.0268e7)
... URANUS =(8.686e + 25,2.5559e7)
... NEPTUNE =(1.024e + 26,2.4746e7)
... def __init __(self,mass,radius):
... self.mass = mass#in kilograms
... self.radius = radius#in meters
... @property
... def surface_gravity(self):
...#万能引力常数(m3 kg-1 s-2)
... G = 6.67300E -11
...返回G * self.mass /(self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e + 24,6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129

此示例还演示了枚举:在 surface_gravity()属性方法中,定义了一个常量 G 这通常会在类级别定义,但是尝试在$ code>枚举中这样做只会将其添加为枚举的成员之一,因此它被定义在方法。



如果类想在其他方法中使用这个常量,那么它也必须在那里定义,这显然不是理想的。 >

有没有办法在枚举中定义一个类常量,或者有一些解决方法来实现相同的效果?

解决方案

这是高级行为,在创建的枚举的90%以内不需要。



根据文档:


允许的规则如下:名称(以单个下划线开头和结尾)由枚举保留,不能使用; _sunder _ 枚举中定义的所有其他属性将成为此枚举的成员,除了 __ dunder __ 名称和描述符(方法也是描述符)


所以如果你想要一个类常量,你有几个选择:




  • __ init __
  • 中创建
  • 在类创建后添加

  • 使用mixin

  • 创建自己的描述符



    • __ init __ 中创建常量,并在类创建后添加它们都不会收集所有的类信息在一个地方。



      适当时可以使用Mixins(请参阅dnozay的答案为了一个很好的例子),但是也可以通过建立一个基本的 Enum 类来实现这种情况,而实际的常量是内置的。



      首先, e常量,将在下面的例子中使用:

        class常量:#使用常量(对象)如果在Python 2 
      def __init __(self,value):
      self.value = value
      def __get __(self,* args):
      return self.value
      def __repr __(self)
      返回'%s(%r)'%(self .__ class __.__ name__,self.value)

      和一次性使用枚举示例:

       从枚举导入枚举

      class Planet (枚举):
      MERCURY =(3.303e + 23,2.4397e6)
      VENUS =(4.869e + 24,6.0518e6)
      EARTH =(5.976e + 24,6.37814e6)
      MARS =(6.421e + 23,39.72e6)
      JUPITER =(1.9e + 27,7.1492e7)
      SATURN =(5.688e + 26,6.0268e7)
      URANUS = (8.686e + 25,2.5559e7)
      NEPTUNE =(1.024e + 26,2.4746e7)

      #万有引力常数
      G =常数(6.67300E-11)

      def __init __(self,mass,radius):
      self.ma ss = mass#in kilograms
      self.radius = radius#in meters
      @property
      def surface_gravity(self):
      return self.G * self.mass /(self。半径* self.radius)

      打印(行星.__ dict __ ['G'])#常数(6.673e-11)
      打印(Planet.G)#6.673e-11
      print(Planet.NEPTUNE.G)#6.673e-11
      print(Planet.SATURN.surface_gravity)#10.44978014597121

      最后,枚举导入枚举$ b $的多用枚举示例:

        b 
      class AstronomicalObject(枚举):

      #万能引力常数
      G =常数(6.67300E-11)

      def __init __(self,mass ,半径):
      self.mass =质量
      self.radius = radius
      @property
      def surface_gravity(self):
      return self.G * self.mass /(self.radius * self.radius)

      class Planet(AstronomicalObject):
      MERCURY =(3.303e + 23,2.4397e6)
      VENUS =(4.869e + 24,6.0518e6)
      EARTH =(5.976e + 24,6.37814e6)
      MARS =(6.421e +23,33972e6)
      JUPITER =(1.9e + 27,7.1492e7)
      SATURN =(5.688e + 26,6.0268e7)
      URANUS =(8.686e + 25,2.5559e7 )
      NEPTUNE =(1.024e + 26,2.4746e7)

      类小行星(AstronomicalObject):
      CERES =(9.4e + 20,4.75e + 5)
      PALLAS =(2.068e + 20,2.72e + 5)
      JUNOS =(2.82e + 19,2.2e + 5)
      VESTA =(2.632e + 20,2.62e + 5

      Planet.MERCURY.surface_gravity#3.7030267229659395
      Asteroid.CERES.surface_gravity#0.27801085872576176



      < hr>

      注意



      常量 G 真的不是。可以将 G 重新绑定到其他东西:

        Planet.G = 1 

      如果你真的需要它是不变的(也就是不可重新绑定),那么使用新的aenum库 [1],将阻止尝试重新分配常量 s以及枚举成员。






      [1 ] aenum 由作者 enum34 编写。


      Python 3.4 introduces a new module enum, which adds an enumerated type to the language. The documentation for enum.Enum provides an example to demonstrate how it can be extended:

      >>> class Planet(Enum):
      ...     MERCURY = (3.303e+23, 2.4397e6)
      ...     VENUS   = (4.869e+24, 6.0518e6)
      ...     EARTH   = (5.976e+24, 6.37814e6)
      ...     MARS    = (6.421e+23, 3.3972e6)
      ...     JUPITER = (1.9e+27,   7.1492e7)
      ...     SATURN  = (5.688e+26, 6.0268e7)
      ...     URANUS  = (8.686e+25, 2.5559e7)
      ...     NEPTUNE = (1.024e+26, 2.4746e7)
      ...     def __init__(self, mass, radius):
      ...         self.mass = mass       # in kilograms
      ...         self.radius = radius   # in meters
      ...     @property
      ...     def surface_gravity(self):
      ...         # universal gravitational constant  (m3 kg-1 s-2)
      ...         G = 6.67300E-11
      ...         return G * self.mass / (self.radius * self.radius)
      ...
      >>> Planet.EARTH.value
      (5.976e+24, 6378140.0)
      >>> Planet.EARTH.surface_gravity
      9.802652743337129
      

      This example also demonstrates a problem with Enum: in the surface_gravity() property method, a constant G is defined which would normally be defined at class level - but attempting to do so inside an Enum would simply add it as one of the members of the enum, so instead it's been defined inside the method.

      If the class wanted to use this constant in other methods, it'd have to be defined there as well, which obviously isn't ideal.

      Is there any way to define a class constant inside an Enum, or some workaround to achieve the same effect?

      解决方案

      This is advanced behavior which will not be needed in 90+% of the enumerations created.

      According to the docs:

      The rules for what is allowed are as follows: _sunder_ names (starting and ending with a single underscore) are reserved by enum and cannot be used; all other attributes defined within an enumeration will become members of this enumeration, with the exception of __dunder__ names and descriptors (methods are also descriptors).

      So if you want a class constant you have several choices:

      • create it in __init__
      • add it after the class has been created
      • use a mixin
      • create your own descriptor

      Creating the constant in __init__ and adding it after the class has been created both suffer from not having all the class info gathered in one place.

      Mixins can certainly be used when appropriate (see dnozay's answer for a good example), but that case can also be simplified by having a base Enum class with the actual constants built in.

      First, the constant that will be used in the examples below:

      class Constant:  # use Constant(object) if in Python 2
          def __init__(self, value):
              self.value = value
          def __get__(self, *args):
              return self.value
          def __repr__(self):
              return '%s(%r)' % (self.__class__.__name__, self.value)
      

      And the single-use Enum example:

      from enum import Enum
      
      class Planet(Enum):
          MERCURY = (3.303e+23, 2.4397e6)
          VENUS   = (4.869e+24, 6.0518e6)
          EARTH   = (5.976e+24, 6.37814e6)
          MARS    = (6.421e+23, 3.3972e6)
          JUPITER = (1.9e+27,   7.1492e7)
          SATURN  = (5.688e+26, 6.0268e7)
          URANUS  = (8.686e+25, 2.5559e7)
          NEPTUNE = (1.024e+26, 2.4746e7)
      
          # universal gravitational constant
          G = Constant(6.67300E-11)
      
          def __init__(self, mass, radius):
              self.mass = mass       # in kilograms
              self.radius = radius   # in meters
          @property
          def surface_gravity(self):
              return self.G * self.mass / (self.radius * self.radius)
      
      print(Planet.__dict__['G'])             # Constant(6.673e-11)
      print(Planet.G)                         # 6.673e-11
      print(Planet.NEPTUNE.G)                 # 6.673e-11
      print(Planet.SATURN.surface_gravity)    # 10.44978014597121
      

      And, finally, the multi-use Enum example:

      from enum import Enum
      
      class AstronomicalObject(Enum):
      
          # universal gravitational constant
          G = Constant(6.67300E-11)
      
          def __init__(self, mass, radius):
              self.mass = mass
              self.radius = radius
          @property
          def surface_gravity(self):
              return self.G * self.mass / (self.radius * self.radius)
      
      class Planet(AstronomicalObject):
          MERCURY = (3.303e+23, 2.4397e6)
          VENUS   = (4.869e+24, 6.0518e6)
          EARTH   = (5.976e+24, 6.37814e6)
          MARS    = (6.421e+23, 3.3972e6)
          JUPITER = (1.9e+27,   7.1492e7)
          SATURN  = (5.688e+26, 6.0268e7)
          URANUS  = (8.686e+25, 2.5559e7)
          NEPTUNE = (1.024e+26, 2.4746e7)
      
      class Asteroid(AstronomicalObject):
          CERES = (9.4e+20 , 4.75e+5)
          PALLAS = (2.068e+20, 2.72e+5)
          JUNOS = (2.82e+19, 2.29e+5)
          VESTA = (2.632e+20 ,2.62e+5
      
      Planet.MERCURY.surface_gravity    # 3.7030267229659395
      Asteroid.CERES.surface_gravity    # 0.27801085872576176
      


      Note:

      The Constant G really isn't. One could rebind G to something else:

      Planet.G = 1
      

      If you really need it to be constant (aka not rebindable), then use the new aenum library [1] which will block attempts to reassign constants as well as Enum members.


      [1] aenum is written by the author of enum34.

      这篇关于在枚举内定义一个类常量吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆