7

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?

4
  • 1
    Looking out if there's other ways to get the effect without using *args. Otherwise the bounty goes to Ethan
    – alvas
    Commented Feb 15, 2021 at 14:23
  • In Query.__init__ do you want each member name present? In other words, Query will only work with Fields? Commented Feb 16, 2021 at 15:53
  • Query's init should not only work with Fields type, it should be able to take other types. E.g. maybe there's an f variable of str type.
    – alvas
    Commented Feb 17, 2021 at 4:30
  • I don't understand your last comment -- could you add an example to your question? Commented Feb 23, 2021 at 1:59

3 Answers 3

6

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'}
0
2

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.

1
+100

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'}
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.