Object Oriented Programming: Problem with self in the Constructor, Python 3 - python

I'm currently trying to learn python and am attempting to understand classes and I've ran into a weird problem.
class card:
def __init__(self, s, num, name):
self.suit = s
self.number = num
self.name = name
class aceCard(card):
def __init__(s):
card.__init__(s, 0, "ace of " + s)
value1 = 1
valye11 = 11
class numCard(card):
def __init__(s, num):
name = num, " of ", s
card.__init__(s, num, name)
value = num
class faceCard(card):
def __init__(s, num):
if (num == 11):
name = "jack of " + s
elif (num == 12):
name = "queen of " + s
elif (num == 13):
name = "king of " + s
card.__init__(s, num, name)
value = 10
class suits:
cards = []
def __init__(s):
cards = [aceCard.__init__(s)]
n = 1
while n<11:
cards.append(numCard.__init__(s, n))
n+=1
while n<14 and n>10:
cards.append(faceCard.__init__(s, n))
n+=1
class deck:
adeck = []
def __init__():
adeck = [suits.__init__("clubs"), suits.__init__("diamonds"), suits.__init__("hearts"), suits.__init__("spades")]
def print():
for suitses in adeck:
for cardses in suitses:
print(cardses.name)
deck1 = deck.__init__()
deck1.print()
The error message from the Spyder IDE is
runfile('###', wdir='###')
Traceback (most recent call last):
File "###", line 55, in <module>
deck1 = deck.__init__()
File "###", line 46, in __init__
adeck = [suits.__init__("clubs"), suits.__init__("diamonds"), suits.__init__("hearts"), suits.__init__("spades")]
File "###", line 34, in __init__
cards = [aceCard.__init__(s)]
File "###", line 10, in __init__
card.__init__(s, 0, "ace of " + s)
TypeError: __init__() missing 1 required positional argument: 'name'
The part that confuses me is the fact that the interpreter expects self to be used like a normal parameter rather than being skipped over. Pls help.
Edit:
My question doesn't seem to be fixed by anything I search. My problem is that everything I'm checking to teach me tells me to use as self as a parameter and in the code I'm to use it like "this" in java. However, when I call the constructor, I am to ignore self as the first parameter and use the succeeding ones only. What is the problem there that I'm missing?

There's several issues with your code, but the root of you problem is that you don't know how to construct parent instances.
Python uses super() to do this:
class Card:
def __init__(self, s, num, name):
self.suit = s
self.number = num
self.name = name
class AceCard(Card):
def __init__(self, s):
super().__init__(s, 0, "ace of " + s)
# This does nothing. Just creates local variables which are discarded
# once the function ends.
value1 = 1
valye11 = 11
I can recommend this tutorial as a good intro to Python's OOP implementation.

Related

Local variable referenced error when calling class

Originally I had 2 files, one named "cards" and one named "decks". The cards file contain the definition of the cards class and was imported into the "decks" file. In the decks files was the definition of the deck object. After defining the deck object, I would test the class in the lines below by typing something like "deck = deck()" and everything would work.
After verifying everything, I wanted to move the deck definition into the "cards" file, to create a library that would contain both the "card" and "deck" class definitions. However after doing this, running "deck = deck()" failed, giving the following error. This happens even if I run the "deck = deck()" line in the bottom of the cards file, or if I import cards an run in a separate file.
"card = card(name = name_of_card,suit = card_suit,value = 0)
UnboundLocalError: local variable 'card' referenced before assignment"
Below is the cards file code:
import random
class card:
def __init__(self, name, suit, value):
self.name = name
self.suit = suit
self.value = value
class deck:
def __init__(self, contents = [], num_cards = 0):
self.contents = contents
self.num_cards = num_cards
self.generate()
def generate(self):
card_values = ['Ace', *range(2,11,1),'Jack', 'Queen', 'King']
suits = ['Hearts','Clubs','Diamonds','Spades']
for i in suits:
card_suit = str(i)
for n in card_values:
name_of_card = str(n) + " of " + card_suit
card = card(name = name_of_card,suit = card_suit,value = 0)
self.contents.append(card)
self.num_cards += 1
def shuffle(self):
random.shuffle(self.contents)
def print_contents(self):
for i in self.contents:
print(i.name)
def draw_card(self):
card_drawn = self.contents[0]
self.contents.pop(0)
return card_drawn
def reveal(self,num_to_reveal = 1,from_top = True):
for i in range(0,num_to_reveal,1):
if from_top == True:
print(self.contents[i].name)
else:
print(self.contents[-1-i].name)
def return_to_deck(self,card, position = 0):
self.contents.insert(position,card)
deck = deck()
You're using the same name for the class card and for the object you create for it. Your code will work if you use different names. Typically classes have names starting with a capitol letter, so I'd suggest class Card and then later, card = Card(name=name_of_card,suit=card_suit,value = 0).

Python3 custom update functions for lists/dictionary

I'm creating a terminal based game and after using an answer from my last question, I realized I ran into another problem. I needed to figure out how to properly update stats on a character based on set class, and their solution worked. But now I need to figure out how to update it if it's not a number. So far I generated one for strings, but now I need one for a list of data.
For example, the player class so far consists of a base character with default stats and values.
class BaseCharacter:
#define what to do when the object is created, or when you call player = BaseCharacter()
def __init__(self):
#generate all the stats. these are the default stats, not necessarily used by the final class when player starts to play.
#round(random.randint(25,215) * 2.5) creates a random number between 25 and 215, multiplies it by 2.5, then roudns it to the nearest whole number
self.gold = round(random.randint(25, 215) * 2.5)
self.currentHealth = 100
self.maxHealth = 100
self.stamina = 10
self.resil = 2
self.armor = 20
self.strength = 15
self.agility = 10
self.criticalChance = 25
self.spellPower = 15
self.speed = 5
self.first_name = 'New'
self.last_name = 'Player'
self.desc = "Base Description"
self.class_ = None
self.equipment = [None] * 6
The update function that I used from my last question goes as follows:
#define the function to update stats when the class is set
def updateStats(self, attrs, factors):
#try to do a function
try:
#iterate, or go through data
for attr, fac in zip(attrs, factors):
val = getattr(self, attr)
setattr(self, attr, val * fac)
#except an error with a value given or not existing values
except:
raise("Error updating stats.")
So when I create a WarriorCharacter based off of the BaseCharacter...
class WarriorCharacter(BaseCharacter):
#define data when initialized, or the Object is created
def __init__(self, first_name, last_name):
super().__init__()
#update the class value since its a copy of BaseCharacter
self.class_ = 'Warrior'
#update the first name
self.first_name = first_name
#update the last name
self.last_name = last_name
#update description value
self.desc = 'You were born a protector. You grew up to bear a one-handed weapon and shield, born to prevent harm to others. A warrior is great with health, armor, and defense.'
self.updateStats(['stamina', 'resil', 'armor', 'strength', 'speed'], [1.25, 1.25, 1.35, 0.75, 0.40])
... I can run self.updateStats(['stamina', 'resil', 'armor', 'strength', 'speed'], [1.25, 1.25, 1.35, 0.75, 0.40]) in the Warrior class to properly update the new stats of the created player.
However I had to slightly revise the updateStats function for the shops class, because it uses mostly strings instead of numbers, by updating the for loop.
for attr, fac in zip(attrs, factors):
setattr(self, attr, fac)
With the shop class...
class BaseShop:
def __init__(self):
#generate shop information
self.name = "Base Shop"
self.gold = round(random.randint(325, 615) * 2)
self.desc = "Base Description"
self.stock = [None] * random.randint(3, 8)
self.vendor = "Base Vendor"
#set responses
#. . .
... This allows me to call shop.updateShopInfo(["vendor"], ["Test Vendor"]) to change the shops vendor name from 'Base Vendor' to 'Test Vendor'
The Problem
Now I don't know how to revise this function for an array/list data type. As you saw in the example I had a few variables such as self.equipment = [None] * 6 and self.stock = [None] * random.randint(3, 8). I want to be able to update these stats with items from the item class which is going to built like so:
class BaseItem:
def __init__(self):
self.name = "Base Item Name"
self.desc = "Base Item Description"
self.itemType = None
self.itemSize = None
self.stats = {
'Strength': 0,
'Agility': 0,
'Critical Chance': 0,
'Spell Power': 0,
'Speed': 0,
'Health': 0,
'Stamina': 0,
'Armor': 0,
'Resilience': 0
}
self.slot = None
#my attempt at it so far
def updateItemStats(self, attrs, factors):
try:
#iterate, or go through data
for attr, fac in zip(attrs, factors):
val = getattr(self, attr)
setattr(self, attr, val + fac)
#except an error with a value given or not existing values
except:
raise("Error updating stats.")
class OneHandedSword(BaseItem):
def __init__(self):
super().__init__()
self.itemType = "Sword"
self.itemSize = "One Hand"
self.name = "Jade Serpentblade"
self.desc = "Sharp cutlass."
self.slot = "Weapon"
#something like this? would update the stats value of the new item to have +5 strength and +2 stamina
self.update([self.stats["strength"], self.stats["stamina"]], [5, 2])
What I tried
The update function throws this error:
Traceback (most recent call last):
File "/home/ubuntu/workspace/Python/game_Test/test.py", line 33, in <module>
item2 = OneHandedSword()
File "/home/ubuntu/workspace/Python/game_Test/assets/items.py", line 46, in __init__
self.updateItemStats([self.stats["Strength"], self.stats["Stamina"]], [5, 2])
File "/home/ubuntu/workspace/Python/game_Test/assets/items.py", line 33, in updateItemStats
raise("Error updating stats.")
TypeError: exceptions must derive from BaseException
When I take out the try/except, it returns this error:
Traceback (most recent call last):
File "/home/ubuntu/workspace/Python/game_Test/test.py", line 33, in <module>
item2 = OneHandedSword()
File "/home/ubuntu/workspace/Python/game_Test/assets/items.py", line 43, in __init__
self.updateItemStats([self.stats["Strength"], self.stats["Stamina"]], [5, 2])
File "/home/ubuntu/workspace/Python/game_Test/assets/items.py", line 28, in updateItemStats
val = getattr(self, attr)
TypeError: getattr(): attribute name must be string
I then tried editing val = getattr(self, attr) to val = gettattr(self, self.stats[attr] it then returns KeyError: 0
What I need
So I essentially need two update functions, one for updating the item.stats dictionary, and one for updating the stock and equipment lists with item objects. I cannot for the life of me figure out how to do this. Any ideas?

Having errors in inheritance in Python

I am trying to create a program with a real estate agent in mind. In this program, I am trying to cover the aspects of a home to rent with all the basic parameters in mind. However I am having some errors.
class Apartment:
def __init__(self, aptNumber, address, bedrooms, baths):
self._aptNumber = aptNumber
self._address = address
self._bedrooms = int(bedrooms)
self._baths = float(baths)
def _securiyDep(self):
securityDeposit = 330(bedrooms)
def _rent(self):
rent = 250(bedrooms) + 150(bathrooms)+200
def _renter(self):
renter = "vacant"
def setSecDep(self, deposit):
self._deposit = 1000
def setRent(self, rentMoney):
self._rentMoney = 800
def setRenter(self, renter):
self._renter = "Vacant"
def getData(self, Data):
self._Data = Data
def isVacant(self, vacancy):
self._vacancy = "True" or "False"
def __repr__(self):
s = self._aptNumber+ " located at " + str(self._address) + " is rented at" + self._rent
s+= " and has a security deposit = " + self._deposit + " and is = " + self._vacancy
return s
# Test code for the Apartment Class
if __name__ == "__main__":
apts = []
apts.append(Apartment("10C", "107 E. Main", 3, 1.5))
apts.append(Apartment("14B", "109 E. Main", 4, 2))
apts.append(Apartment("13", "2207 W. Broadway", "5", "2.5"))
for apt in apts:
print(apt)
print()
apts[0].setRent("1245")
apts[0].setRenter("Rocky Quartzite")
apts[1].setSecDep("1000")
apts[1].setRenter("Millie Milton")
print(apts[0].getData())
print()
for apt in apts:
if not apt.isVacant():
print(apt)
print()
apts[0].setRenter("")
print(apts[0])
I am having the error
print(apts[0].getData())
<__main__.Apartment object at 0x0000000003124208>
TypeError: getData() missing 1 required positional argument: 'Data'
<__main__.Apartment object at 0x0000000003124240>
Can someone please help with the errors?
You call getData with no arguments on line 60: print(apts[0].getData()). In your definition it takes a parameter called Data.
You define getData to take two arguments, namely self which is a refernce to the instance you are operating on, and which is "automatically" supplied, and the second argument is Data
def getData(self, Data):
self._Data = Data
But when you call getData you don't supply the second argument Data
apts[0].getData()
Thus the interpreter tells you that 1 required argument is missing, which in your case is Data.
Since getData in your case actually sets the Data variable, it would be better to call it setData
If you want to retrive the Data variable the getter would have to looke something like this
def getData(self):
return self._Data

eTypeError: __init__() missing 1 required positional argument: 'Type'

I have two programs.
The first one animalGenerator.py:
# This program generates a name and an animal type
import Animals
print("Welcome to the animal generator!")
print("This program creates Animal objects")
def main():
animals = make_list()
print("\nAnimal List")
print("-------------")
display_list(animals)
def make_list():
animal_list = []
again = 'y'
while again.lower() == 'y':
typ = input("\nWhat type of animal would you like to create? ")
nam = input("What is the animal's name? ")
ani = Animals.Animal(typ, nam)
animal_list.append(ani)
again = input("\nWould you like to add more animals (y/n)? ")
return animal_list
def display_list(animal_list):
for item in animal_list:
print("\n" + item.get_name() + "the" + item.get_Type() + "is" + item.get_mood())
main()
Second program Animals.py:
import random
class Animal:
def __init__(self, name, mood, Type):
self.__name = name
self.__mood = mood
self.__animal_type = Type
def set_name(self, name):
self.__name = name
def set_mood(self, mood):
self.__mood = mood
def set_animal_type(self, Type):
self.__animal_type = Type
def toss(self):
if random.randint(1, 2, 3) == 1:
self.__mood = 'Happy'
elif random.randint(1, 2, 3) == 2:
self.__mood = 'Hungry'
elif random.randint(1, 2, 3) == 3:
self.__mood = 'Sleepy'
def get_name(self):
return self.__name
def get_mood(self):
return self.__mood
def get_animal_type(self):
return self.__animal_type
I receive an error(title) when I run the first program
This is the traceback:
Traceback (most recent call last):
File "C:\Users\Dahlia\Desktop\McCuneShannonAnimals\animalGenerator.py", line 42, in <module>
main()
File "C:\Users\Dahlia\Desktop\McCuneShannonAnimals\animalGenerator.py", line 11, in main
animals = make_list()
File "C:\Users\Dahlia\Desktop\McCuneShannonAnimals\animalGenerator.py", line 30, in make_list
ani = Animals.Animal(typ, nam)
TypeError: __init__() missing 1 required positional argument: 'Type'
Could someone please help me figure out how/why "Type" is a missing positional argument?
You defined Animals's __init__() as def __init__(self, name, mood, Type). However, you call it with ani = Animals.Animal(typ, nam) - that's two arguments out of the expected three. Ensure that each method is defined properly and that methods are always called properly, according to their definition.
The second program does not look like valid python, there is a level of indentation missing so I am surprised this actually runs at all.
However, to the original problem - you are instantiating Animal with (typ, nam), however in your constructor it also takes a third parameter - Type - (name, mood, Type) - this is the positional argument the interpreter is complaining about.

Python :TypeError: this constructor takes no arguments

When the user enters an email address, and the program reads the email and display it according to its criteria (e.g yeo.myy#edu.co), like criteria:
username is yeo.myy
domain is edu.co
I know its something to do with the "#".
this is the code
class Email:
def __int__(self,emailAddr):
self.emailAddr = emailAddr
def domain(self):
index = 0
for i in range(len(emailAddr)):
if emailAddr[i] == "#":
index = i
return self.emailAddr[index+1:]
def username(self):
index = 0
for i in range(len(emailAddr)):
if emailAddr[i] == "#" :
index = i
return self.emailAddr[:index]
def main():
emailAddr = raw_input("Enter your email>>")
user = Email(emailAddr)
print "Username = ", user.username()
print "Domain = ", user.domain()
main()
this is the error I got:
Traceback (most recent call last):
File "C:/Users/Owner/Desktop/sdsd", line 29, in <module>
main()
File "C:/Users/Owner/Desktop/sdsd", line 24, in main
user = Email(emailAddr)
TypeError: this constructor takes no arguments
def __int__(self,emailAddr):
Did you mean __init__?
def __init__(self,emailAddr):
You're also missing a couple selfs in your methods, and your returns are improperly indented.
def domain(self):
index = 0
for i in range(len(self.emailAddr)):
if self.emailAddr[i] == "#":
index = i
return self.emailAddr[index+1:]
def username(self):
index = 0
for i in range(len(self.emailAddr)):
if self.emailAddr[i] == "#" :
index = i
return self.emailAddr[:index]
Result:
Username = yeo.myy
Domain = edu.co
Incidentally, I recommend partition and rpartition for splitting a string into two pieces on a given separator. Sure beats keeping track of indices manually.
def domain(self):
return self.emailAddr.rpartition("#")[2]
def username(self):
return self.emailAddr.rpartition("#")[0]
This error may happen if you type def _init_ with a single underline instead of def __init__ with double underlines before and after init.
class Employee:
def __init__(self,Name,Age,Salary,Gender):
self.Name = Name
self.Age = Age
self.Salary= Salary
self.Gender = Gender
def show_employee_deatils(self):
print("Name of the employee is ",self.Name)
print("Age of the employee is ",self.age)
print("Salary of the employee is ",self.salary)
print("gender of the employee is ",self.gender)
e1 = Employee('Shubham',25,25000,'male')
e1. show_Employee_deatils( )

Categories