1

Say I have a python class which may set a dictionary upon instantiating:

class myClass():
    def __init__(self, some_dict=None):
        self.some_dict = some_dict

and then in another place in my code, I want to look up a key in that dict - but of course only if it exists. Is the best Python style then to 1) make a "checking method" in the class, even if it's only one line, or 2) directly reference the class' dictionary attribute? Let's say the class was instantiated as myClassInstance the options are then

1) Class method:

    def is_key_in_dict(self, query_key):
        return self.some_dict and query_key in self.some_dict

which is then used as

if myClassInstance.is_key_in_dict(query_key):
    do_something()

or, 2) directly reference in the code where its used.

if myClassInstance.some_dict and query_key in myClassInstance.some_dict:
    do_something()

Is it okay (style-wise) to reference class attributes directly or is it considered bad/unsafe practice? I am somewhat familiar with the @property decorator, as discussed in this post: What's the pythonic way to use getters and setters?, but not sure if that answers my question.

Kaspar H
  • 179
  • 4
  • 10
  • I wouldn't do either of these. I'd set the attribute to an empty dict if the parameter is none, then just do the `if...in`. – Daniel Roseman Nov 26 '18 at 08:10

2 Answers2

1

According to the EAFP-Principle, using exceptions for control flow is pythonic. Currently, you are looking before you leap.

I would code (either as a function or method):

def do_something(myClassInstance, query_key): # additional arguments omitted
    try:
        query_value = myClassInstance.some_dict[query_key]
    except TypeError, KeyError: # could also consider AttributeError
        pass # or whatever logic you need
    else: # no exception
        # code that does something

If you have multiple functions/methods that need the same exception handling, for reusability it would make sense to write an additional wrapper around the exception handling which returns query_value if no exception occured and a appropriate sentinel value (e.g. None) if an exception occured.

You could also consider to use the line

self.some_dict = some_dict or {}

in __init__, then you don't have to think about TypeErrors any longer.

timgeb
  • 76,762
  • 20
  • 123
  • 145
0

Maybe you need object.__contains__ method

class SomeClass:
    def __init__(self, some_dict):
        self.some_dict = some_dict or {}

    def __contains__(self, item):

        if item in self.some_dict:
            return True

        return False

And in your code

c = SomeClass({'a': 1})

if 'a' in c:
    print('c contains key "a"')
Crazy
  • 324
  • 2
  • 8