patternpythonMinor
Enum usage to restrict class attribute values
Viewed 0 times
enumusageattributevaluesrestrictclass
Problem
I am using enums in python3 for the first time but unsure if I am using them correctly.
I want to restrict the 'allowed values' for a class attribute
Here's my code:
Usage
This code works, but having to write an
Also, no errors are raised if I later run
Am I missing a common usage pattern?
I want to restrict the 'allowed values' for a class attribute
ArticleMetadata.article_type to those defined within an ArticleTypes Enum class.Here's my code:
from enum import Enum
class ArticleMetadata(object):
ArticleTypes = Enum('ArticleTypes', 'original modified', module=__name__)
def is_in_enum(self, value, Enum):
"""Verify that a value is contained within a defined Enum object.
Raises:
ValueError: If the value is not contained within the defined Enum.
"""
if value in Enum.__members__:
return True
else:
raise ValueError("Value {0} not in Enum list.".format(value))
def __init__(self, **kwargs):
"""Set class attributes."""
self.article_type = (kwargs['article_type'] if 'article_type' in kwargs.keys()
and self.is_in_enum(kwargs['article_type'], self.ArticleTypes)
else None
)Usage
> foo = ArticleMetadata(article_type='original')
> foo.article_type
'original'
> bar = ArticleMetadata(article_type='invalid')
*** ValueError: Value invalid not in Enum list.This code works, but having to write an
is_in_enum method seems clunky, and I would have thought that this functionality would be natively part of enums somehow?? Also, no errors are raised if I later run
foo.article_type = 'invalid', which doesn't seem right!Am I missing a common usage pattern?
Solution
I think for it to be completely safe (even against re-assigning later), you should make
In this case you don't need your helper function any more (at the price of losing this general function and having to write a getter and setter for every property for which you want this kind of protection). Note that I used
Also note that this can still be tricked, because Python has no real private members. So you can still do this:
AtricleMetadata.article_type a property:from enum import Enum
class ArticleMetadata(object):
ArticleTypes = Enum('ArticleTypes', 'original modified', module=__name__)
def __init__(self, **kwargs):
"""Set class attributes."""
self.article_type = kwargs.get('article_type', None)
@property
def article_type(self):
return self._article_type
@article_type.setter
def article_type(self, value):
if value in self.ArticleTypes.__members__:
self._article_type = value
else:
raise ValueError("Value {} not in ArticleType list.".format(value))In this case you don't need your helper function any more (at the price of losing this general function and having to write a getter and setter for every property for which you want this kind of protection). Note that I used
dict.get to make your initialization easier.Also note that this can still be tricked, because Python has no real private members. So you can still do this:
>>> a = ArticleMetadata(article_type="original")
>>> a._article_type = "invalid"
>>> a.article_type
'invalid'Code Snippets
from enum import Enum
class ArticleMetadata(object):
ArticleTypes = Enum('ArticleTypes', 'original modified', module=__name__)
def __init__(self, **kwargs):
"""Set class attributes."""
self.article_type = kwargs.get('article_type', None)
@property
def article_type(self):
return self._article_type
@article_type.setter
def article_type(self, value):
if value in self.ArticleTypes.__members__:
self._article_type = value
else:
raise ValueError("Value {} not in ArticleType list.".format(value))>>> a = ArticleMetadata(article_type="original")
>>> a._article_type = "invalid"
>>> a.article_type
'invalid'Context
StackExchange Code Review Q#162513, answer score: 3
Revisions (0)
No revisions yet.