Exceptional exception - two except blocks in python

Here's an example of what I want to do in code:

class MyClass(object):

    @classmethod
    def test_func(cls, x):

        try:
            return cls.cache[x]

        except AttributeError:
            cls.cache = {}

        except (AttributeError, KeyError):
            cls.cache[x] = "CACHE STORE"
            return cls.cache[x]

      

The idea here is that my class will cache some results based on the input x

. However, I don't want to start building the cache until I need it. So the first time I pass anyone x

to this, I want it to create a cache and fill it with something. Is there a way for it to hit both blocks except

? Now he only gets into the first

+3


source to share


3 answers


As I said in the comment, just create the class attribute cache

when creating the class. Unless you have a really good reason, you just don't need to complicate your implementation.

class MyClass(object):

    cache = {}

    @classmethod
    def test_func(cls, x):
        try:
            return cls.cache[x]
        except KeyError:
            cls.cache[x] = "CACHE STORE"
            return cls.cache[x]

      



Once you've done that, you don't even need an instruction try

; you can just use setdefault

.

@classmethod
def test_func(cls, x):
    return cls.cache.setdefault(x, "CACHE STORE")

      

+3


source


I would go for recursion:



class MyClass(object):

    @classmethod
    def test_func(cls, x):

        try:
            return cls.cache[x]

        except AttributeError:
            cls.cache = {}
            return cls.test_func(x)  # Add this line

        except KeyError:
            cls.cache[x] = "CACHE STORE"
            return cls.cache[x]

      

+2


source


Use defaultdict

:

from collections import defaultdict as dd

class MyClass(object):
    cache = dd(lambda: "CACHE STORE")
    @classmethod
    def test_func(cls, x):
        return cls.cache[x]

      

From the docs:

Returns a new dictionary-like object. defaultdict is a subclass of the built-in dict class. It overrides one method and adds one rewritable instance variable. The rest of the functionality is the same as for the dict class and is not documented here.

The first argument provides an initial value for the default_factory attribute; the default is None. All other arguments are treated the same as if they were passed to the dict constructor, including the keyword arguments.

I agree with the others that you have nothing to lose by simply adding it as a class attribute from the beginning. But if you really insist on not building the cache until needed, you can do it like this:

from collections import defaultdict as dd

class MyClass(object):
    @classmethod
    def test_func(cls, x):
        try:
            return cls.cache[x]
        except AttributeError:
            cls.cache = dd(lambda: "CACHE STORE")
            return cls.test_func(x)

      

+1


source







All Articles