2
\$\begingroup\$

I am writing a small class that has one method: get_state. It is parameterless and returns a dictionary of all the names in self (look in its dict) that are not bound to function objects (test functions by using inspect.isfunction on the objects). When a class inherits from Dumpable, its instances can call get_state() to get a dictionary of all the names in its namespace (that are not functions) and their values.

For example, if we first defined class Modular_Counter(Dumpable) and then mc = Modular_Counter(0,3) and then print(mc.get_state()), it would print the following dictionary: {'_value': 0, '_modulus': 3}.

Here is my current working code for the class:

class Dumpable:
    def get_state(self):
        no_funs = self.__dict__
        no_fun_list = [no_fun_key for no_fun_key in no_funs.keys() if inspect.isfunction(no_funs[no_fun_key])]
        for fun in no_fun_list:
            del no_funs[fun]
        return no_funs

Is there a cleaner way to get the same results? I still need to use the one function in the class. Any help would be appreciated.

\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

You can simply use thee vars() built-in function with a dictionary comprehension here:

def get_state(self):
    return {k: v for k, v in vars(self).items() if not inspect.isfunction(v)}

Note that the methods are usually defined in the class so they actually never show up in instance dictionary, while looking up for them Python can find them from the class dictionary. With that said, in case you defined a functions on the instance:

self.func = lambda: 'func called'

And then tried to run your code then you will notice that your code actually nukes that function itself from the instance when you call get_state, that's because you're deleting them from the instance dictionary. Don't do that, instead create a new dictionary.

class Dumpable:

    def __init__(self):
          self.x = 1
          self.y = 2
          self.func = lambda: 'func called'

    def get_state(self):
        no_funs = self.__dict__
        no_fun_list = [no_fun_key for no_fun_key in no_funs.keys() if inspect.isfunction(no_funs[no_fun_key])]
        for fun in no_fun_list:
            del no_funs[fun]
        return no_funs

d = Dumpable()
print(d.func())
print(d.get_state())
print(d.func())

Output:

func called
{'y': 2, 'x': 1}
Traceback (most recent call last):
  File "/home/ashwini/py/so.py", line 25, in <module>
    print(d.func())
AttributeError: 'Dumpable' object has no attribute 'func'

Other minor nitpicks:

  • To get the key as well as items from a dict use its .items() method.
  • To loop over a dict, never call its .keys() method. A dict is an iterable and iterating on it yields one key at a time. The .keys() can be very expensive in Python 2 where it actually creates a list of all keys first.
  • -
\$\endgroup\$
1
  • \$\begingroup\$ @AshwinChaudhary- Thanks. I was only allowed to use one method in the class otherwise your technique seems a lot better. \$\endgroup\$
    – LucyBen
    Feb 23, 2015 at 8:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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