Maggie Ewing
Maggie Ewing

Reputation: 3

Can I refer to instance attributes when instantiating a class in python?

I'm a new programmer, trying to make a simple multiplayer text adventure. I have a class called Situation that among other things has attributes for the player the situation is happening to (an object of a Player class, but for now let's pretend it's just a string representing the player's name) and the story of what's happening (a string).

When I write these situations, I want to be able to have the story text depend on the player, for example, I'm trying to do something like this:

class Situation:
    def __init__(self, player, story):
        self.player = player
        self.story = story

my_story = Situation("Maggie", "once upon a time there was a kid named %s" % (my_story.player))

Trying that, I get an error message "local variable 'my_story' referenced before assignment" which makes sense. I tried self.player instead, but that also doesn't work.

Is there a way to make one instance attribute depend on another?

Upvotes: 0

Views: 70

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121744

When Python evaluates the statement my_story = Situation(...), it has to evaluate the arguments first, because otherwise there is nothing to pass to the Situation() class. At this point there is no instance, because the class hasn't been called yet. The assignment to my_story name only takes place once the instance is created, so you can't use that name either.

So no, you cannot refer to the instance yet, because it doesn't yet exist.

You can store the player in a separate variable first:

player = 'Maggie'
my_story = Situation(player, "once upon a time there was a kid named %s" % (player,))

Alternatively, you can pass on responsibility of filling the template to the __init__ method; you can just give it a string with a %s placeholder for example:

class Situation:
    def __init__(self, player, story):
        self.player = player
        self.story = story % (self.player,)

my_story = Situation("Maggie", "once upon a time there was a kid named %s")

There are better ways of doing this, using named placeholders:

class Situation:
    def __init__(self, player, story):
        self.player = player
        self.story = story % {'player': self.player}

my_story = Situation("Maggie", "once upon a time there was a kid named %(player)s")

I'd personally use the newer str.format() method here, because the format is clearer:

class Situation:
    def __init__(self, player, story):
        self.player = player
        self.story = story.format(player=self.player)

my_story = Situation("Maggie", "once upon a time there was a kid named {player}")

Upvotes: 3

Claudiu
Claudiu

Reputation: 229341

As Martijn said, you can't access attributes of the instance-to-be-created, because it doesn't exist yet.

However, the way to make an instance attribute depend on another instance attribute is to include logic which does just that - uses one instance attribute to compute another instance attribute.

In your case, instead of passing a story string, you can pass a format string which will turn into the story string using str.format(), to wit:

class Situation:
    def __init__(self, player, story_fmt):
        self.player = player
        self.story = story_fmt.format(player=self.player)

situation = Situation("Maggie", "once upon a time there was a kid named {player}")

Now situation.story is:

'once upon a time there was a kid named Maggie'

Upvotes: 2

Related Questions