0

In C and also PHP if I declare some variables in a file then include it(in PHP in c it's part of the compiled binary). It just works. Why doesn't this work in python.

Here is what I can do in PHP.

file a.php

$a=1;
$b=2;

file b.php

function add(){
   global $a,$b;
   return $a+$b;
}

File c.php

require('a.php')
require('b.php')
echo add().PHP_EOL;

You get back 3.

But in python if I do something similar it says that the variable is undefined. In data.py I have the following object/class created. It is not part of any function and the indentation here reflects the same level/scope as the file itself.

player=Player()

In textadventure.py I have the following code.

from data import *
from lib import *

in lib.py I have

def check_input(usr_input):
    inputs=usr_input.split(' ')
    verb=inputs[0]
    global player
    if len(inputs) >= 2:
        obj=inputs[1]
    else:
        obj=None

    if verb in verbs:
        if verb == 'move':
            player.location.move(obj)
        elif verb == 'look':
            look(obj)
    else:
        print('not valid')

def look(obj):
    global player
    current_room=player.location
    if obj is None:
        print(current_room.desc)
    else:
        if obj in current_room.items:
            print(current_room.items[obj].desc)
        elif obj in current_room.mobs:
            print(current_room.mobs[obj].desc)

I then get the following error though.

Traceback (most recent call last):
  File "text_adventure.py", line 84, in <module>
    main_loop()
  File "text_adventure.py", line 81, in main_loop
    check_input(usr_input)
  File "/home/macarthur/misc_proj/python_projects/text_adventure/lib.py", line 23, in check_input
    look(obj)
  File "/home/macarthur/misc_proj/python_projects/text_adventure/lib.py", line 48, in look
    current_room=player.location
NameError: name 'player' is not defined

So my question is why doesn't this work. Don't tell me I have to import every single file into every single other file to make sure that it's actually part of the global namespace.

data.py

from templates import *

letter=Item()
letter.desc="It's a letter you found in the mailbox."
letter.interact="The letters have faded but you can make out a single sentence 'Those in the dark fear the light.'"
mailbox=Mailbox()
mailbox.desc='It is a mailbox with the flag up and the front closed'
mailbox.action='interact'
mailbox.contains=letter
starter=Room("You are in a room with four exits \033[1m north east south west\033[0m. There is a single mailbox before you.",mailbox,None)
letter.location=starter._id
mailbox.in_room=0
north=Room("You are in a room with a single source of light. A \033[1m flashlight.\033[0m")
west=Room("You are in a wet room. There is a \033[1mfish\033[0m flopping on the ground before you.")
east=Room("You are in an empty room. You can see nothing else")
south=Room("You are in a dark room. There is nothing that can be seen.")
starter.add_moves({'n':north,'e':east,'s':south,'w':west})
west.add_moves({'e':starter})
east.add_moves({'w':starter})
south.add_moves({'n':starter})

player=Player()
inventory=Inventory()

templates.py

class Item:
    _id=0
    desc=''
    interaction=''
    location=None
    def __init__(self,desc=desc,interact=interaction,location=location):
        self.desc=desc
        self.interaction=interact
        self.location=location
        self._id=Item._id
        Item._id+=1
    def get_item(self,player):
        move_location(self,-1)
        print("You have grabbed {} and put it into your \033[1minventory".format(self.desc))

    def move_location(self,location):
        self.location=location

class Weapon(Item):
    damage=0
    desc='It is a weapon'
    def __init__(self,damage=damage,desc=desc):
        self.damage=damage
        self.desc=desc


class World():
    rooms={}
    def __init__(self):
        pass
    def add_room(self,room):
        self.rooms[(room.x,room.y)]=room

class Mailbox(Item):
    contains='letter'
    def __init__(self,contains=contains):
        Item.__init__(self)
        self.contains=contains

class Player:
    x=0
    y=0
    location=None
    weapon=None
    dead=False
    hp=10
    def __init__(self):
        self.x=0
        self.y=0
        self.weapon=None
        self.dead=False
        self.location=None
        self.hp=10

    def damaged(amount):
        self.hp=self.hp-amount

class Inventory(Player):
    items={}
    def __init__(self,items=items):
        self.items=items

    def add(self,item):
        self.items.append(item)

    def show(self):
        for item in self.items:
            print(item._id.desc)

    def use(self,item):
        if item in items:
            print(item.interaction)
        else:
            print("You don't have that item")

class Room:
    desc="You're in a room"
    items=None
    mobs=None
    x=0
    y=0
    _id=0
    exits={}
    def __init__(self,desc=desc,items=items,mobs=mobs,x=x,y=y,exits=exits):
        self.exits=exits
        self.desc=desc
        self.items=items
        self.mobs=mobs
        self.x=x
        self.y=y
        self._id=Room._id
        Room._id+=1

    def add_moves(self,moves=exits):
        self.exits.update(moves)

    def move(self,movement,player):
        selected_move=self.exits.get(movement,None)
        if  selected_move:
            player.location=selected_move
        else:
            return None


class Mob:
    _id = 0
    desc="You can't discern anything about it."
    interact="It just looks at you."
    room=None
    alive=True
    name='None'
    hp=5
    def __init__(self,desc=desc,interact=interact,alive=alive,name=name,hp=hp):
        self.name=name
        self.desc=desc
        self.interact=interact
        self._id=Mob.id
        Mob._id+=1
        self.alive=alive
        self.hp=hp

class Grue(Mob):
    def __init__(self):
        super().__init__(desc='A giant grue stands before you',interact='You were eaten by a grue',name='Grue',hp=10)
sinoroc
  • 18,409
  • 2
  • 39
  • 70
133794m3r
  • 5,028
  • 3
  • 24
  • 37
  • 1
    As programmers we should *all* try very, *very*, **very** hard not to have global variables. You are passing parma obj, so perhaps you can pass player as well. – quamrana Dec 15 '19 at 19:57
  • I am setting player as global as the player is a global object that is accessible by the rest of the game loop. How else would I declare this item. It has to be intialized and modified by various functions within the project. If game state isn't supposed to be global what else should be. The obj is passed to the input because it's part of the player's input and thus was created within the function. The player object represents the current player state within the game world. – 133794m3r Dec 15 '19 at 19:58
  • 1
    Just because instances could be global doesn’t mean they have to be. Just pass objects into the functions that need them. – quamrana Dec 15 '19 at 20:04
  • `lib.py` needs to import `player` from `data.py`. If a module needs to know about something in a different module, then yes, you must import it. – John Gordon Dec 15 '19 at 20:04
  • @JohnGordon So it works the way it seemed like. I don't know why it wouldn't be part of the global namespace when I added it. Python doesn't have "require" or "include" as far as I can tell. This whole language is full of weirdness that I never would've imagined before. I guess I'll just pass it as an argument to the functions to make my life simpler. – 133794m3r Dec 15 '19 at 20:06
  • Slightly unrelated question, but why is Inventory a subclass of Player? Why do certain classes, like room, have a bunch of class variables which are seemingly just defaults for the instance variables? – AMC Dec 15 '19 at 20:09
  • Also using `import *` is generally considered a bad idea. – AMC Dec 15 '19 at 20:11
  • @AlexanderCécile I have no idea. It made sense when I was making it. This is the first time I tried to design something in an OOP style. I normally just use data structures for everything. So it looks like it is. A guy who has refused to use objects/classes/inheritance attempting to use it. This is part of my work-study writing projects for the students in the class(to be taught next semester) to do. I'm going to have them extend the code. with new classes. My work-study is basically whatever I want. So I'm writing projects to be done by other students for the course. – 133794m3r Dec 15 '19 at 20:12
  • @AlexanderCécile I didn't feel like enumerating over the functions/classes right now. This is super early in the process. This is the starting stages. I'm no going to enumerate my imports until I actually know _what_ I'm going to include. Also One other thing is that this is the first thing I could think of that'd require using most of the features of python to show off the language to the students as this'll be their first experience with the language. – 133794m3r Dec 15 '19 at 20:14
  • @133794m3r You mentioned C and PHP, but do you come from a functional background? I’m sure you’ll figure it out! Unfortunately right now I can’t actually think of any solid resources on the subject I would recommend... This sounds like a nice project though, let me know if you would like to discuss it any further :) – AMC Dec 15 '19 at 20:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/204310/discussion-between-133794m3r-and-alexander-cecile). – 133794m3r Dec 15 '19 at 20:19
  • 1
    Python's recommendation for [How do I share global variables across modules](https://docs.python.org/3/faq/programming.html?highlight=global#how-do-i-share-global-variables-across-modules) – DarrylG Dec 15 '19 at 20:31

1 Answers1

0

According to @JohnGordon any module(a script) that needs to know about variables/objects declared in another module(or script). You have to import it so that it knows about it. Global namespace isn't really global like PHP or other languages.

Much alike how you cannot assign variables within a conditional python seems to be forcing "best practices".

133794m3r
  • 5,028
  • 3
  • 24
  • 37
  • What do you mean by _cannot assign variables within a conditional_? – AMC Dec 15 '19 at 20:19
  • You can, but only since version 3.8, so you require the code to run in 3.8 if you use it. – progmatico Dec 15 '19 at 20:22
  • I was trying to port https://stackoverflow.com/questions/617647/where-is-my-implementation-of-rot13-in-javascript-going-wrong/617685#617685 to python for my own rot13 encoder. But python 2 and 3 won't let me do it. – 133794m3r Dec 15 '19 at 21:12