Soy nuevo en el período de codificación (3 semanas) y he estado construyendo y reconstruyendo un juego de rol para ayudar a enseñarme los principios que he estado aprendiendo. Sin embargo, parece que estoy atascado en un aspecto específico de las clases de Python.

Una variable de clase que he creado para mi clase worldLocation se lee como tal donde NORTH, EAST, SOUTH, WEST todas las cadenas de referencia:

WHITEROOM = worldLocation('A Plain White Room',
                          '...\n\nWhere are you?\n\n'
                          'All around you is white...\n\n'
                          '...only white...',
                          [ROCK.GROUNDDESC],
                          [RAT.NAME],
                          {NORTH: 'A Plain White Room',
                           SOUTH: 'A Plain White Room',
                           EAST: 'A Plain White Room',
                           WEST: 'A Plain White Room'})

Pero quiero que en su lugar se lea así, donde cada una de las variables de instancia hace referencia a la variable de clase en sí:

WHITEROOM = worldLocation('A Plain White Room',
                          '...\n\nWhere are you?\n\n'
                          'All around you is white...\n\n'
                          '...only white...',
                          [ROCK.GROUNDDESC],
                          [RAT.NAME],
                          {NORTH: WHITEROOM,
                           SOUTH: WHITEROOM,
                           EAST: WHITEROOM,
                           WEST: WHITEROOM})

Sin embargo, cada vez que intento cambiarlo a este último, recibo un error undefined name WHITEROOM. ¿Qué estoy haciendo mal o falta?

El código de clase es el siguiente:

class worldLocation(object):
    def __init__(self, NAME, DESC, GROUND, ENEMIES, DIRECTIONS):
        self.NAME = NAME
        self.DESC = DESC
        self.GROUND = GROUND
        self.ENEMIES = ENEMIES
        self.DIRECTIONS = DIRECTIONS
1
Joshuah Croghan 8 oct. 2019 a las 22:30

3 respuestas

La mejor respuesta

El código que desea usar está intentando hacer referencia a la instancia en un diccionario que se pasa como argumento a __init__() antes de que exista. Eso no es factible (y podría decirse que es realmente razonable si lo piensas).

Sin embargo, puede solucionar el problema creando un valor especial que el método de inicializador de clase __init__() pueda verificar y corregir los datos que se pasan.

A continuación hay un código que ilustra lo que quiero decir. Nota He agregado algunos andamios al principio para que sea ejecutable con fines de prueba.

#### Some scaffolding for testing.
NORTH, SOUTH, EAST, WEST = 'NORTH SOUTH EAST WEST'.split()

class ROCK:
    GROUNDDESC = 'ground desc'

class RAT:
    NAME = 'Ricky'
####


class WorldLocation:
    THIS = object()  # A unique value.

    def __init__(self, NAME, DESC, GROUND, ENEMIES, DIRECTIONS):
        self.NAME = NAME
        self.DESC = DESC
        self.GROUND = GROUND
        self.ENEMIES = ENEMIES

        # Replace any values in DIRECTIONS dictionary argument that refer to the
        # instance being created (as designated by them being the class
        # attribute THIS).
        self.DIRECTIONS = {direction: self if value is self.THIS else value
                               for direction, value in DIRECTIONS.items()}


WHITEROOM = WorldLocation('A Plain White Room',
                          '...\n\nWhere are you?\n\n'
                          'All around you is white...\n\n'
                          '...only white...',
                          [ROCK.GROUNDDESC],
                          [RAT.NAME],
                          {NORTH: WorldLocation.THIS,
                           SOUTH: WorldLocation.THIS,
                           EAST: WorldLocation.THIS,
                           WEST: WorldLocation.THIS})

# Show that it works.
from pprint import pprint

print(f'id(WHITEROOM): 0x{id(WHITEROOM):08x}\n')
pprint(vars(WHITEROOM))

Salida de muestra:

id(WHITEROOM): 0x010d0390

{'DESC': '...\n'
         '\n'
         'Where are you?\n'
         '\n'
         'All around you is white...\n'
         '\n'
         '...only white...',
 'DIRECTIONS': {'EAST': <__main__.WorldLocation object at 0x010D0390>,
                'NORTH': <__main__.WorldLocation object at 0x010D0390>,
                'SOUTH': <__main__.WorldLocation object at 0x010D0390>,
                'WEST': <__main__.WorldLocation object at 0x010D0390>},
 'ENEMIES': ['Ricky'],
 'GROUND': ['ground desc'],
 'NAME': 'A Plain White Room'}
0
martineau 9 oct. 2019 a las 17:37

La variable no obtiene un valor hasta que la función regresa, por lo que no puede hacer referencia a ella en los argumentos de la función. Debe agregar esas referencias después de asignar la variable.

WHITEROOM = worldLocation('A Plain White Room', '...\n\nWhere are you?\n\nAll around you is white...\n\n...only white...', [ROCK.GROUNDDESC], [RAT.NAME], {})
WHITEROOM.DIRECTIONS = {NORTH: WHITEROOM, SOUTH: WHITEROOM, EAST: WHITEROOM, WEST: WHITEROOM}
0
Barmar 8 oct. 2019 a las 19:35

Puede lograr lo que desea lograr, pero no puede hacer referencia a una variable antes de que se declare.

Entonces, por ejemplo, no puede decir A={'key':A} porque hasta que se cree dict, no puede usarse como un valor para 'key'.

Prueba esto:

WHITEROOM = worldLocation('A Plain White Room', '...\n\nWhere are you?\n\nAll around you is white...\n\n...only white...', [ROCK.GROUNDDESC], [RAT.NAME], {})
WHITEROOM.DIRECTIONS = {NORTH: WHITEROOM, SOUTH: WHITEROOM, EAST: WHITEROOM, WEST: WHITEROOM}

¿Por qué funciona esto? Bueno, el constructor worldLocation __init__ creará el objeto worldLocation y lo asignará a la variable WHITEROOM. Luego podemos acceder a la variable WHITEROOM.DIRECTIONS con el operador de punto y pasarle una nueva dict que usa la variable WHITEROOM como referencia a la {{X7} } objeto. No es tan elegante como te gustaría, pero creo que así podrás hacer lo que intentas hacer.

0
VoNWooDSoN 8 oct. 2019 a las 19:44
58292893