ThisGuy
ThisGuy

Reputation: 2883

__init__ function appears to be executing on definition, not instantiation

I have something akin to the following code:

class thingy(object):
    def __init__(creds=get_credentials()):
        # does stuff
        pass

def get_credentials():
    # produces different values sometimes. Ie: retrieves values from a db
    return db.get(some_query)

dc.connect(credentials_and_stuff)

This fails on import, not runtime, defining the __init__(), saying 'the database has no connection'. This doesn't make sense to me, since the __init__() function hasn't even been run yet!

Upvotes: 1

Views: 47

Answers (1)

ThisGuy
ThisGuy

Reputation: 2883

I found this: http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments

Turns out, values for optional arguments are evaluated at their definition, not when executed. Here's an extreme example:

def default_value():
    print("ERMAGERD DIS FUNCTION WAS RUN!")
    return False

def fake_function(an_arg=default_value()):
    pass

Before this discovery, I'd say this code would do nothing; no functions are run, just some definitions. Now I know (and have tested) that this code alone will print out ERMAGERD DIS FUNCTION WAS RUN!.

This means two things for the code in the above question:

  1. In order to not crash, the db.connect() would have to be run before the class thingy(object) definition happens.
  2. The get_credentials() would only get run once, and said db query would never get re-run (stale credentials!)

So to make this actually do what it's intended to do (query the database for credentials when none are provided), you have to do something akin to this:

class thingy(object):
    def __init__(creds=None):
        if creds is None:
            creds = get_credentials()
        # does stuff
        pass

This way get_credentials() is run at runtime, not at definition. This both allows the db.connect() to be done elsewhere (so long as it's before an instance of thingy is instantiated), and fixes the stale credentials issue.

Upvotes: 4

Related Questions