Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

168
Vistas
Representación de todos los valores en la enumeración Flag

Me gustaría tener un indicador "TODOS" en mi enumeración de banderas de python para el cual

 myenum.EVERY_MEMBER & myenum.ALL == myenum.EVERY_MEMBER

se mantiene cierto. actualmente tengo:

 from enum import Flag, auto class RefreshFlags(Flag): NONE = 0 EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() .....

Debido a que esta enumeración podría crecer en cualquier estado de desarrollo, me gustaría tener algo como

 @property def ALL(self): retval = self.NONE for member in self.__members__.values(): retval |= member return retval

Esto no funciona:

 RefreshFlags.EVENTS & RefreshFlags.ALL TypeError: unsupported operand type(s) for &: 'RefreshFlags' and 'property'

Tenga en cuenta que esta pregunta actualmente solo se relaciona con Python 3.6 o posterior.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Hay algunas maneras de superar este problema:

  • use una propiedad de classproperty (vea Zero's answer )

  • use un decorador de clase (vea MSeifert's answer )

  • use un mixin ( currently buggy )

  • crear una nueva clase base (ver más abajo)


Una cosa a tener en cuenta con el método de propiedad de clase es que, dado que el descriptor se define en la clase y no en la metaclase, las protecciones habituales contra la configuración y la eliminación están ausentes, en otras palabras:

 >>> RefreshFlags.ALL <RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15> >>> RefreshFlags.ALL = 'oops' >>> RefreshFlags.ALL 'oops'

Creando una nueva clase base:

 # lightly tested from enum import Flag, auto from operator import or_ as _or_ from functools import reduce class AllFlag(Flag): @classproperty def ALL(cls): cls_name = cls.__name__ if not len(cls): raise AttributeError('empty %s does not have an ALL value' % cls_name) value = cls(reduce(_or_, cls)) cls._member_map_['ALL'] = value return value

Y en uso:

 class RefreshFlag(AllFlag): EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() >>> RefreshFlag.ALL <RefreshFlag.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

La diferencia interesante en la propiedad ALL es la configuración del nombre en _member_map_ -- esto permite las mismas protecciones otorgadas a los miembros de Enum:

 >>> RefreshFlag.ALL = 9 Traceback (most recent call last): .... AttributeError: Cannot reassign members.

Sin embargo, hay una condición de carrera aquí: si RefreshFlag.ALL = ... ocurre antes de que RefreshFlag.ALL se active la primera vez, entonces se golpea; por esta razón, usaría un decorador en este caso, ya que el decorador procesará el Enum antes de que pueda ser golpeado.

 # lightly tested from enum import Flag, auto from operator import or_ as _or_ from functools import reduce def with_limits(enumeration): "add NONE and ALL psuedo-members to enumeration" none_mbr = enumeration(0) all_mbr = enumeration(reduce(_or_, enumeration)) enumeration._member_map_['NONE'] = none_mbr enumeration._member_map_['ALL'] = all_mbr return enumeration

Y en uso:

 @with_limits class RefreshFlag(Flag): EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() >>> RefreshFlag.ALL = 99 Traceback (most recent call last): ... AttributeError: Cannot reassign members. >>> RefreshFlag.ALL <RefreshFlag.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15> >>> RefreshFlag.NONE <RefreshFlag.0: 0>
over 4 years ago · Santiago Trujillo Denunciar

0

TL; DR Porque la propiedad solo se evalúa en instancias de una clase, mientras que los __members__ solo son accesibles en la clase.


Si accede a una property en una clase, simplemente devuelve una property :

 >>> RefreshFlags.ALL <property at 0x2a5d93382c8>

Sin embargo, para que esto funcione, debe convertirlo en un método de clase:

 from enum import Flag, auto class RefreshFlags(Flag): NONE = 0 EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() @classmethod def ALL(cls): retval = self.NONE for member in cls.__members__.values(): retval |= member return retval >>> RefreshFlags.ALL() <RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

o acceda a la propiedad en una instancia:

 from enum import Flag, auto class RefreshFlags(Flag): NONE = 0 EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() @property def ALL(self): retval = self.NONE # One needs to access .__class__ here! for member in self.__class__.__members__.values(): retval |= member return retval >>> RefreshFlags.EVENTS.ALL <RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15>

En ambos casos puedes hacer tu comparación más adelante:

 >>> RefreshFlags.EVENTS & RefreshFlags.EVENTS.ALL <RefreshFlags.EVENTS: 1>

Usted declaró en los comentarios que desea que el miembro ALL se comporte como los demás, en ese caso, sugiero usar un decorador de clase:

 def with_ALL_member(enumeration): retval = enumeration(0) # in case NONE is not defined for name, member in enumeration.__members__.items(): retval |= member enumeration.ALL = retval return enumeration @with_ALL_member class RefreshFlags(Flag): NONE = 0 EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() >>> RefreshFlags.EVENTS & RefreshFlags.ALL <RefreshFlags.EVENTS: 1> >>> RefreshFlags.DEFENSES & RefreshFlags.ALL <RefreshFlags.DEFENSES: 8>

El decorador de clase también se puede usar en otras enumeraciones :)

over 4 years ago · Santiago Trujillo Denunciar

0

Siguiendo con la respuesta de MSeifert, es posible escribir un decorador @classproperty que le permita acceder a RefreshFlags.ALL directamente como una propiedad (en lugar de un método convencional o una propiedad en una instancia):

 from enum import Flag, auto from operator import or_ from functools import reduce class classproperty: def __init__(self, func): self._func = func def __get__(self, obj, owner): return self._func(owner) class RefreshFlags(Flag): NONE = 0 EVENTS = auto() RESOURCES = auto() BUILDINGS = auto() DEFENSES = auto() @classproperty def ALL(cls): return reduce(or_, cls)

Por supuesto, puede escribir ALL() con un bucle for explícito como en su ejemplo; lo anterior se ofrece meramente como una alternativa.

 >>> RefreshFlags.ALL <RefreshFlags.DEFENSES|BUILDINGS|RESOURCES|EVENTS: 15> >>> RefreshFlags.ALL & RefreshFlags.BUILDINGS <RefreshFlags.BUILDINGS: 4>
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda