2

I'm trying to use a function of a class object to create a new class object and running into problems. Here's the code I have so far:

class Room(object):
    def __init__(self, name):
        self.name = name
        self.N = None
        self.E = None
        self.S = None
        self.W = None
    '''relevant code'''
    def north(self,room):
        self.N = Room(room)
        self.N.S = self
    def south(self,room):
        self.S = Room(room)
        self.S.N = self

So I want at least one of these print statements

room1 = Room('room1')
room1.north('room2')

print(room2.S)
print(Room(room2).S)
print(Room('room2').S)

to spit out 'room1', but the first two don't work because room2 as a variable is yet to be defined, and the last one doesn't work because it seems to be creating a new object instead of referencing the existing one, so it just prints the default 'None'.

Does there actually exist a way to reference an existing object with no variable set to it? Or is my only option to do something like this?

    def north(self,room):
        roomDict[room] = Room(room)
        self.N = roomDict[room]
        self.N.S = self

Edit: I realize I should probably be calling the new Room's south() function instead of directly changing the S variable, but that seems intuitively like it would cause a loop so I haven't touched it yet.

0

2 Answers 2

2

* Edited based on OP's clarification *

If you have a large number of objects you want to refer to without binding them to variables, dict is the way to go.

You can use @Berci's solution. But note that with that solution, if you already have a room named foo, you can't overwrite it by simply calling Room('foo') again -- doing that will just return the original foo room. To overwrite an existing room you must first do del Room.roomDict['foo'], and then call Room('foo'). This may be something you want, but maybe not.

The implementation below is less fanciful and doesn't require __new__ (in fact, Berci's solution doesn't need __new__ either and can be all done in __init__):

class Room:
    registry = {}
    def __init__(self, name):
        self.registry[name] = self
        # the rest of your __init__ code

If you want rooms to be non-overwritable, as they are in Berci's solution, just add two lines:

class Room:
    registry = {}
    def __init__(self, name):
        if name in self.registry:
            raise ValueError('room named "{}" already exists'.format(name))
        self.registry[name] = self

It's not necessary to nest registry inside Room. You can make it an external dict if you want. The advantage of having the registry as a class attribute is that your Room object can access it as self.registry without knowing its global name. The (slight) disadvantage is that you need to type Room.registry or someroom.registry instead of just, say, registry, every time you access it.

Sign up to request clarification or add additional context in comments.

6 Comments

The problem here is that there will be many other rooms, so if I'm not able to refer to them directly I'll end up calling them like room1.N.E.E.W.N.S or something ridiculous.
@aryst0krat So what is the larger context of this problem? Depending on what you want to do with the rooms, there may be a better way to organize them, but I need to know what you want to with them in order to help.
The larger context is that it's for a text-based adventure game. In terms of my Room objects, I need to be able to refer to them to tell where the player is located, what in game objects are around, etc. So being able to refer to them by names is important, but I'd rather not have to manually create variables for them all. The reason they're connected is just for moving from room to room. So if you say to move north, it will move you to the room in your room's N variable.
@aryst0krat I see. See my edited answer. Hope it helps!
Goodness gracious, never mind anything I said. I'm thinking about this in completely ridiculous terms. Obviously I'm going to need to write out code for each individual room anyway, so none of that even matters.
|
0

Your dict solution can be brought to work. Use a class level roomDict and a new constructor not to create an already existing object referred by its name:

class Room(object):
    roomDict = {}
    def __new__(cls, name):
        if name in cls.roomDict:
            return cls.roomDict[name]
        self = object.__new__(cls, name)  # here the object is created
        cls.roomDict[name] = self
        return self
    def __init__(self, name):
        ...

So that you can refer to room2 as Room('room2') afterwards.

1 Comment

I think this implementation is probably above my current skill level haha. I don't recognize 'cls' or understand how the __new__ function (which looks like a built-in one?) is called or why it would be different from __init__, nor what that function as a whole does exactly. I'll try to puzzle it out and if nothing else will definitely keep it in mind for the future, though.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.