Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to collate the arguments features to create a set of values from an Enum?

Given an Enum object that cannot be modified, and a custom Query class that should generate a compilation of the Enum values given different arguments:

from enum import Enum

class Fields(Enum):
    a = ["hello", "world"]
    b = ["foo", "bar", "sheep"]
    c = ["what", "the"]
    d = ["vrai", "ment", "cest", "vrai"]
    e = ["foofoo"]

class Query:
    def __init__(self, a=True, b=True, c=False, d=False, e=False):
        self.query_fields = set()
        self.query_fields.update(Fields.a.value) if a else None
        self.query_fields.update(Fields.b.value) if b else None
        self.query_fields.update(Fields.c.value) if c else None
        self.query_fields.update(Fields.d.value) if d else None
        self.query_fields.update(Fields.e.value) if e else None

It's possible to get a custom set of query_fields, as such:

[out]:

>>> x = Query()
>>> x.query_fields
{'bar', 'foo', 'hello', 'sheep', 'world'}

>>> x = Query(e=True)
>>> x.query_fields
{'bar', 'foo', 'foofoo', 'hello', 'sheep', 'world'}

Question: In the Query initialization function, we had to iterate through each class argument and do something like self.query_fields.update(Fields.a.value) if a else None, are there other ways to achieve the same behavior and output of Query().query_fields without hard-coding each argument?

like image 895
alvas Avatar asked Feb 04 '21 16:02

alvas


People also ask

How do you print an enum in Python?

The __str__() method is called by str(object) and the built-in functions format() and print() and returns the informal string representation of the object. Now you can get the value of the enum directly, without accessing the value attribute on the enum member. You can also use square brackets to access enum members.

How do you declare an enum in Python?

Enum is a class in python for creating enumerations, which are a set of symbolic names (members) bound to unique, constant values. The members of an enumeration can be compared by these symbolic anmes, and the enumeration itself can be iterated over.

How do you declare an enum?

An enum is defined using the enum keyword, directly inside a namespace, class, or structure. All the constant names can be declared inside the curly brackets and separated by a comma. The following defines an enum for the weekdays. Above, the WeekDays enum declares members in each line separated by a comma.

What is an enum value?

An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type.


3 Answers

For a more general solution, see below; for a solution for Fields specifically and which doesn't need *args (or *members as the case may be...) check out Tomer Shetah's answer.


General Solution

To make Query more generalized and usable with other Enums, I would specify which Field members you wanted:

class Query:
    #
    def __init__(self, *members):
        self.query_fields = set()
        for member in members:
            self.query_fields.update(member.value)

and in use:

>>> x = Query()
>>> x.query_fields
set()


>>> y = Query(Fields.a, Fields.c)
>>> y.query_fields
{'world', 'the', 'hello', 'what'}

If your defaults are common, you can put them in another variable and use that:

>>> fields_default = Fields.a, Fields.b

>>> z = Query(*fields_default)
>>> z.query_fields
{'foo', 'bar', 'world', 'hello', 'sheep'}
like image 97
Ethan Furman Avatar answered Oct 19 '22 02:10

Ethan Furman


You can iterate over Fields to get all the elements, and then use that .name or .value to get the respective attribute.

from enum import Enum


class Fields(Enum):
    a = ["hello", "world"]
    b = ["foo", "bar", "sheep"]
    c = ["what", "the"]
    d = ["vrai", "ment", "cest", "vrai"]
    e = ["foofoo"]


class Query:

    defaults = [True, True, False, False, False]

    def __init__(self, **kwargs):
        self.query_fields = set()

        for attr, default in zip(Fields, self.defaults):
            if attr.name in kwargs:
                if kwargs[attr.name]:
                    self.query_fields.update(attr.value)
            elif default:
                self.query_fields.update(attr.value)


x = Query()
print(x.query_fields)

x = Query(a=False, e=True)
print(x.query_fields)

Note that the number of elements in fields and their order is hardcoded in Query.defaults, but I dont think it makes sense for that not to be the case.

like image 28
ScienceSnake Avatar answered Oct 19 '22 04:10

ScienceSnake


After reading Get a list/tuple/dict of the arguments passed to a function? I figured out it can be achieved without using *args.

There is the short version:

class Query:
    def __init__(self, a=True, b=True, c=False, d=False, e=False):
        self.query_fields = set()
        local_variables = locals()
        [self.query_fields.update(Fields[local].value) for local in local_variables if local_variables[local] is True]

or the more verbose option:

class Query:
    def __init__(self, a=True, b=True, c=False, d=False, e=False):
        self.query_fields = set()
        local_variables = locals()
        for local in local_variables:
            if local_variables[local] is True:
                self.query_fields.update(Fields[local].value)

The output in both implementations for:

x = Query()
print(x.query_fields)

is:

{'hello', 'foo', 'bar', 'sheep', 'world'}

and for:

x = Query(e = True)
print(x.query_fields)

is:

{'foo', 'hello', 'sheep', 'foofoo', 'bar', 'world'}
like image 1
Tomer Shetah Avatar answered Oct 19 '22 04:10

Tomer Shetah