Object only callable when "from" import used (Python) - python

Following an online tutorial, I typed up the following code:
class Car:
# define and initialize some attributes of Car object
def __init__(self):
self.speed = 0
self.odometer = 0
self.time = 0
# 'get' function for current speed
def say_state(self):
print("I'm going {} kph!".format(self.speed))
# 'set' function for current speed
def accelerate(self):
self.speed += 5
# 'set' function for current speed
def brake(self):
self.speed -= 5
# 'set' function for trip time and distance
def step(self):
self.odometer += self.speed
self.time += 1
# 'get' function for average speed
def average_speed(self):
return self.odometer / self.time
if __name__ == "__main__":
my_car = Car()
print("I'm a car")
while True:
action = input("What should I do? [A]ccelerate, [B]rake, "
"show [O]dometer, or show average [S]peed").upper()
if action not in "ABOS" or len(action) != 1:
print("I don't know how to do that.")
continue
if action == "A":
my_car.accelerate()
elif action == "B":
my_car.brake()
elif action == "O":
print("My car has driven {} kilometers".format(my_car.odometer))
elif action == "S":
print("My car's average speed was {} kph".format(my_car.average_speed()))
my_car.step()
my_car.say_state()
Then, I broke from the tutorial because it didn't tell me what the if __name__ == "main" business was about. Reading elsewhere, I kind of understood that this statement prevents the code following that if statement from executing if the module isn't being run as the main class, but rather is imported. So to test this out I typed up another small module "import_practice.py:
import Car
corolla = Car()
corolla.say_state()
This code would not run, with the error "Car is not callable", so I figured my import was wrong. I replaced import Car with from Car import Car and it worked, but according to the following answer, it shouldn't make a difference, right? In fact, if that answer is correct, it isn't the behavior I'm looking to get out of my import at all.

If you do this:
import Car
Then your code should be:
corolla = Car.Car()
corolla.say_state()
When you "import" a module, you are not bringing all its components to the current namespace. You are just loading it. If you want to refer to a component on that module, you must refer it through its module name: Car.Car. Here, first Car is the name of the module, and the second one is the name of the class.
If you actually want to import all module's components to the current namespace, you can do from Car import *. But I would not recommend that.
After that, you did from Car import Car. Here, the sentence is stating that you are bringing the name Car to the current namespace, from the Car module. Hence, you can just use Car on your code after this.
Please do note that the answer you are referring to is not saying that import Car is the same as from Car import Car.

The line
import Car
loads the module Car, and makes all the thing it declares (ie., the class Car) available inside the namespace Car.
The line
from Car import Car
loads the module Car (the from Car import part), then makes the name Car declared in that module (which is the class Car) available in the current namespace. That is,
import Car
Car.Car()
is equivalent to
from Car import Car
Car()
except for what the name Car in the global namespace refers to (the whole module, or just the one class).
Note that import statements also support as. With that you can change the name given in the current namespace:
import Car as CarModule
CarModule.Car()
and
from Car import Car as CarClass
CarClass()
also do the same thing as the other two, again except for names.

Import troubles
If you have a file called Car.py and you call import Car, that will add the entire module to the current scope.
import Car
print(dir(Car))
# [ ... 'Car' ]
This means you can also do things like:
# import the module and alias it
import Car as c
# add class to local scope as `Car`
Car = c.Car
On the other hand, if you use the from keyword, you are getting something in that module and adding it to the current scope:
from Car import Car
corolla = Car.Car()
corolla.say_state()
What is this __name__ == '__main__' nonsense?
When you call a file python <my-file-name> it sets the special variable __name__ to be the string __main__. if __name__ == '__main__' translates to "if someone is trying to run this as an independent script, then do the following". On the other hand, if someone calls import on that same file, that area will not trigger.

Related

How do solve the NameError: name 'api' is not defined error code?

I am trying to use send a tweet through python code. But for some reason the code returns an error code: NameError: name 'Girl' is not defined. All my code seems to be intended properly so I'm not sure what the issue is. Unfortunately I cannot share the simple_twit library as it restricted against University guidelines but I feel like I made a simple mistake that I am not seeing so a point to the right direction would be appreciated.
Here is my code:
import sys
import time
import simple_twit
import random
def main():
api = simple_twit.create_api()
simple_twit.version()
Boy = ['David','John','Paul','Mark','James','Andrew','Scott','Steven','Robert','Stephen','William','Craig','Michael'
,'Stuart','Christopher','Alan','Colin','Kevin','Gary','Richard','Derek','Martin','Thomas','Neil','Barry',
'Ian','Jason','Iain','Gordon','Alexander','Graeme','Peter','Darren','Graham','George','Kenneth','Allan',
'Simon','Douglas','Keith','Lee','Anthony','Grant','Ross','Jonathan','Gavin','Nicholas','Joseph','Stewart',
'Daniel','Edward','Matthew','Donald','Fraser','Garry','Malcolm','Charles','Duncan','Alistair','Raymond',
'Philip','Ronald','Ewan','Ryan','Francis','Bruce','Patrick','Alastair','Bryan','Marc','Jamie','Hugh','Euan',
'Gerard','Sean','Wayne','Adam','Calum','Alasdair','Robin','Greig','Angus','Russell','Cameron','Roderick',
'Norman','Murray','Gareth','DeanEric','Adrian','Gregor','Samuel','Gerald','Henry','Benjamin','Shaun','Callum',
'Campbell','Frank','Roy','Timothy','Liam','Noah','Oliver','William','Elijah','James','Benjamin','Lucas',
'Mason','Ethan','Alexander','Henry','Jacob','Michael','Daniel','Logan','Jackson','Sebastian','Jack','Aiden',
'Owen','Samuel','Matthew','Joseph','Levi','Mateo','Wyatt','Carter','Julian','Luke','Grayson','Isaac','Jayden'
,'Theodore','Gabriel','Anthony','Dylan','Leo','Christopher','Josiah','Andrew','Thomas','Joshua','Ezra',
'Hudson','Charles','Caleb','Isaiah','Ryan','Nathan','Adrian','Christian']
Girl = ['Emma','Ava','Sophia','Isabella','Charlotte','Amelia','Mia','Harper','Evelyn','Abigail','Emily','Ella',
'Elizabeth','Camila','Luna','Sofia','Avery','Mila','Aria','Scarlett','Penelope','Layla','Chloe','Victoria',
'Madison','Eleanor','Grace','Nora','Riley','Zoey','Hannah','Hazel','Lily','Ellie','Violet','Lillian','Zoe',
'Stella','Aurora','Natalie','Emilia','Everly','Leah','Aubrey','Willow','Addison','Lucy','Audrey','Bella',
'Nova','Brooklyn','Paisley','Savannah','Claire','Skylar','Isla','Genesis','Naomi','Elena','Caroline','Eliana'
,'Anna','Maya','Valentina','Ruby','Kennedy','Ivy','Ariana','Aaliyah','Cora','Madelyn','Alice','Kinsley',
'Hailey','Gabriella','Allison','Gianna,Sarah','Autumn','Quinn','Eva','Piper','Sophie','Sadie','Delilah'
,'Josephine','Nevaeh','Adeline','Arya','Emery','Lydia','Clara','Vivian','Madeline','Peyton','Julia','Rylee',
'Brielle','Reagan','Natalia','Jade'',Athena','Maria','Leilani','Everleigh','Liliana','Melanie','Mackenzie',
'Hadley','Raelynn','Kaylee','Rose','Arianna','Isabelle','Melody','Eliza','Lyla','Katherine','Aubree',
'Adalynn','Kylie','Faith','Marly','Margaret','Ximena','Iris','Alexandra','Jasmine','Charlie','Amaya',
'Taylor','Isabel','Ashley','Khloe','Ryleigh','Alexa','Amara','Valeria','Andrea','Parker','Norah','Eden',
'Elliana','Brianna','Emersyn','Valerie','Anastasia','Eloise','Emerson','Cecilia','Remi','Josie','Reese',
'Bailey','Lucia','Adalyn','Molly','Ayla','Sara','Daisy','London','Jordyn','Esther','Genevieve','Harmony',
'Annabelle','Alyssa','Ariel','Aliyah','Londyn','Juliana','Morgan','Summer','Juliette','Trinity','Callie',
'Sienna','Blakely','Alaia','Kayla','Teagan','Alaina','Brynlee','Finley','Catalina','Sloane','Rachel','Lilly'
,'Ember']
def boyname():
global Boy
result = random.choice(Boy)
print('Your future son’s name can be', result)
Boy.remove(result)
def girlname():
global Girl
result = random.choice(Girl)
print('Your future daughter’s name can be', result)
Girl.remove(result)
sendtweet = simple_twit.send_tweet(api, girlname())
print()
if __name__ == "__main__":
main()
You have to define the global variable outside any function.

Accessing Classes via Variable

I am attempting to make a small game, and what I will be doing is using classes to dictate the stats of the user's preferred class. I need to make the classes so when it comes time to fight a monster (which will also be in it's own class), I will be able to have their stats callable.
This may be a "big picture" problem, but to avoid writing the code three times (for each class), I only want to call the variable "chosenClass.HP" instead of "Mage.HP" because if I did it that way, I would need to have a bunch of if statements for each class among the story. There must be a better way.
I have worked on this both ways, and I hate having to write
if userChoice is 'Mage':
HP = 150
I have looked around at the self.something, but I don't completely understand how that works. If that is the required or recommended solution, what is the best resource for learning?
print("Welcome to the game")
name = input("Choose your name\n")
print(name)
class Warrior:
HP = 100
ATK = 200
DEF = 0
class Mage:
HP = 100
ATK = 200
DEF = 0
class Rouge:
HP = 150
ATK = 250
DEF = 100
user_class = input("Choose a class between Warrior, Mage, or Rouge\n")
print(user_class)
while(user_class != 'Warrior' and user_class != 'Mage' and user_class != 'Rouge'):
print("You did not choose from the required classes, try again")
user_class = input()
theClass = user_class()
theClass.HP = 1000
My error that I get from this code is:
TypeError: 'str' object is not callable
I understand it's being given a String, but it's a variable. Why is it causing problems?
Any recommendations to make this program better?
user_class returns a string and not an actual Class that you've defined above. This is because input() returns a string and you store that in user_class. In order to create a new instance of the classes you created in your code need to instantiate the class using some sort of logic based on the player's input such as:
if user_class.lower() == 'warrior':
theClass = Warrior()
theClass.HP = 1000
Obviously this wouldn't be the best way but is just an example to show how to instantiate the class.
You need a mapping of strings to classes if you want to create an instance like this.
pc_classes = {'Mage': Mage, 'Warrior': Warrior, 'Rogue': Rogue}
while True:
try:
user_class = input("Enter Mage, Warrior, or Rogue)
if user_class in pc_classes:
break
pc = pc_classes[user_class]()

NameError after importing a file

I have two files. One called "variables.py" with this function in:
def get_players():
'''
(NoneType) -> Dictionary
Asks for player names
'''
loop = True
players = {}
while loop == True:
player = input("Enter player names: ")
player = player.strip()
if player in players or player == "":
print("Choose a different name!")
elif "player1" in players:
players["player2"] = [player, 0]
elif player not in players:
players["player1"] = [player, 0]
if len(players) >= 2:
loop = False
return players
And another file in the same directory called "game.py" with this inside:
import variables
players = get_players()
When i try to run "game.py" i get this errorNameError: name 'get_players' is not defined
why?! I have tried everything!
It should be
players = variables.get_players()
Since you have imported only the module variables, and not the method get_players.
Or you could also do:
from variables import get_players
players = get_players()
Read more on importing modules here
You have imported variables, not get_players. You can either keep the import as it is and call variables.get_players(), or do from variables import get_players and then call get_players().
This is a fairly fundamental thing in Python: looks like you could benefit from a basic tutorial.
With Python, when you import a module, a module variable is created of that name which is where all the imported module's variables live:
import variables
players = variables.get_players()
You can also import from a module which will just introduce that name by itself:
from variables import get_players
players = get_players()
You can also do the following to import all names from a module, but it is discouraged because it leads to hard-to-read code:
from variables import *
players = get_players()

I don't understand code behaviour

I have the folowing code:
from random import randint
from medical_room import *
from Library import *
from basement import *
from End import *
class start_Game(object):
def __init__(self):
print "You landed on planet and see three rooms."
print "You approach and see that you need to enter password..."
self.door=raw_input("Pick number of door>>>")
self.password=('%d')%(randint(1,9))
self.entered_password=int(raw_input("Enter password of one digit>>>"))
self.ROOMs={'1':Medical_room,'2':Library,'3':basement,'4':End}
while True:
# break
room=self.ROOMs[self.door]
# print room()
self.door=room()
a=start_Game()
When asked about door number I pick '1' and class Medical_room is launched (code of class is below):
class Medical_room(object):
def __init__(self):
self.play()
def play(self):
print "Medical_room plays"
return '2'
But I can't switch to Library class since get error:
room=self.ROOMs[self.door]
KeyError: <medical_room.Medical_room object at 0x0000000002906978>
For me everything is ok, but Python doesn't like my 'great logic'. Please help.
Before the loop runs, self.door is a string. On the first iteration of the loop, you set self.door as a reference to an object on the first iteration. On the second iteration, you try to use that object as a key on self.ROOMS, but that dictionary has only strings for keys.
You need to set self.door to the string returned by play, I believe:
while True:
room=self.ROOMs[self.door]
self.door=room().play()
However, this doesn't allow you to choose a new door in each room (unless you change the definition of play).

Python - Importing 2 classes into main file

I not very sure how to phrase the question subject...
I have 3 files laid out:
bank.py:
class Bank(object):
def __init__(self, money):
self.money = money
def currentMoney(self):
print "You currently have $%d" %self.money
def useMoney(self, money_use):
self.money = self.money - money_use
print "You used $%d" %money_use
self.currentMoney()
def getMoney(self, money_get):
self.money = self.money + money_get
print "You received $%d" %money_get
self.currentMoney()
event.py:
class Event(object):
def Event1(self):
print "Your dad needs money. Will you give him?"
decision = raw_input("Yes or No")
if decision == "Yes":
Bank.useMoney(500)
elif decision == "No":
print "Your father is sad"
else:
print "I do not know what are you talking about"
main.py:
import bank
import event
Bank = bank.Bank(1000)
Event = event.Event()
Event.Event1()
When I execute the code. I get the following error:
NameError: global name 'Bank' is not defined
Basically, what I would like to do is to use event.py to create a series of events that will affect the money, and I can use main.py to run different series of events.
Would you be able to enlighten me how to do this? Thank you!
As mentioned in the other answer, you need to import Bank in event.py
from bank import Bank
Having said that, looking at the code in event.py, you're going to run into another error on the line:
Bank.useMoney(500)
As useMoney() takes self as the first argument, so it needs to be run on a Bank instance rather than on the class itself (in Java-type speak, useMoney is an instance method, not a static method).
I think what your intent is is to have a Bank instance be contained inside Event, and then call useMoney on that whenever Event1 is called.
You need to import bank in event.py, and use
if decision == "Yes":
bank.Bank(...)
or you could use at the beginning of your event.py:
from bank import Bank
class Event(object):
...
Otherwise, Python cannot know that the Bank object is defined in the bank module when it loads the event module.

Categories