Function not Defined in Class - python-3.x

I am having trouble with a coding project in which I am trying to use classes in python to make a card game (cheat). However, when creating the player class, one of the functions that was previously defined within the class is shown as undefined. I cannot figure out the reason, and any suggestion is appreciated. Below is the definition of the classes
class card(object):
def __init__(self,rank,suit):
self.rank = rank
self.suit = suit
class player(object):
def __init__ (self):
self.number = number
self.hand = list()
#Here, hand is a list of the card class that was distributed with a suit and a rank
def check_card(self,player_rank,player_suit):
for card in self.hand:
if card.rank == player_rank and card.suit == player_suit:
return True
break
return False
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if check_card(self,rank,suit):
print(True)
else:
print(False)
Here is the actual code that will run it
player = player()
player.play_card()
The following error was received:
NameError: name 'check_card' is not defined
I have been troubleshooting and looking at different solutions, including moving the functions outside the class, but it continues to display the same error. Can anyone point out the mistake? Thanks!

You have the following two issues in your code
The way you passed self to the check_card function is wrong. You must call it in this way
self.check_card(rank,suit)
The second issue is that the number is not defined. Thus I passed it as an argument while initializing the player. Feel free to make changes for that.
This is the corrected code :
class card(object):
def __init__(self,rank,suit):
self.rank = rank
self.suit = suit
class player(object):
def __init__ (self, number):
self.number = number
self.hand = list()
#Here, hand is a list of the card class that was distributed with a suit and a rank
def check_card(self,player_rank,player_suit):
for card in self.hand:
if card.rank == player_rank and card.suit == player_suit:
return True
break
return False
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if self.check_card(rank,suit):
print(True)
else:
print(False)
player = player(3)
player.play_card()
Output :
what is the suit?spade
what is the rank?3
False

Based on this document the function call in python class is self.xxxx(args) (xxxx is denoted function name)
therefore the correct version of play_card function is shown as following.
enter code here
def play_card(self):
suit = input('what is the suit?')
rank = input('what is the rank?')
if self.check_card(rank,suit):
print(True)
else:
print(False)

Related

Getting a value from a Class Object in Python based on User Input

so I'm in the process of learning Python, so forgive any naivety.
I'm doing some practice on Classes - and I'm making it so that when a user input their car - it looks for instantiated objects and then returns the price.
I get it to work okay for "BMW" - but when I try Ferrari - it only return the price for the BMW (20k). I'm thinking it is something not right with the price_check function part of the code.
Please could you provide some guidance here? Code below:
class Car:
car_list = []
def __init__(self, make, model, price):
self.make = make
self.model = model
self.price = price
self.car_list.append(self)
#this is the part of the code that i'm stuck with
def price_check(self):
for i in Car.car_list:
if New_Car.make == self.make:
return i.price
else:
print("Not available")
BMW = Car('BMW', '1 Series', "£20,000")
Ferrari = Car('Ferrari', 'Italia', "£90,000")
New_Car = Car(
input("What is make of your car? "), input("What is the model? "), "")
print("The cost of this car is: ", New_Car.price_check())
So essentially, I want it to return the price of the Ferrari if that's what the user typed.
Thanks in advance. And, sorry for any incorrect formatting, etc...
Okay, I agree with the comments made by #Jarvis regarding errors in your code, I would also add that in Cars init the price is a required variable and should cause an error on instantiation. In addition, in price_check, since the new_car instance has already been added to the list, price_check will also examine that entry and either find None or 0 price, so will never get to the "No Price Available" return. Here's how I would implement the Class
class Car:
car_list = []
def __init__(self, make, model, price=None): #makes providing price optional
self._make = make
self._model = model
self._price = price
Car.car_list.append(self)
#property
def make(self):
return self._make
#property
def model(self):
return self._model
#property
def price(self):
return self._price
#price.setter
def price(self, val):
self._price = val
def price_check(self):
for i in Car.car_list:
if i != self and self.make == i.make and self.model == i.model:
return i.price
return "Not available"
Two issues, first you need to append to the list not bound to your instance but the one bound to your class as a class-attribute:
def __init__(self, make, model, price):
self.make = make
self.model = model
self.price = price
# use the 'class' rather than the 'instance', you need to modify a class-attribute
Car.car_list.append(self)
Second, your issue in price check
def price_check(self):
for i in Car.car_list:
# you need to compare self's make with 'i.make' (elements in list)
if self.make == i.make:
return i.price
else:
print("Not available")

Accessing items within a class in Python?

I am very new to Object oriented programming and I am having trouble accessing items in my class when I run my main method. My program is trying to allow a user to add item prices to a cart until they are finished and prints the number of items and total.
class CashRegister:
print("Welcome to shopping world!")
def __init__(self, price):
self.price = price
def addItem(self, price):
CashRegister.totalPrice = CashRegister.totalPrice + price
CashRegister.itemCount = CashRegister.itemCount + 1
#property
def getTotal(self):
return totalPrice
#property
def getCount(self):
return itemCount
def main():
selection = "Y"
while selection != "N":
selection = input("Would you like to add another item to the
cart Y or N")
selection = selection.upper()
if selection == "Y":
price = input("What is the price of the item?")
CashRegister.addItem(price)
else:
print(CashRegister.getCount)
print(CashRegister.getTotal)
print(selection)
main()
Here is the error I am getting when I select yes:
TypeError: addItem() missing 1 required positional argument: 'price'
Here is the output I am getting when I select no:
Welcome to shopping world!
Would you like to add another item to the cart Y or Nn
<property object at 0x0000022CFFCA2598>
<property object at 0x0000022CFFCA2548>
N
first, you don't use the class name for declaring variables in its methods: you have self for that (which you can rename to whatever you like, but 'self' is convention)
second, you have to initialize your class object in the main function, otherwise Python won't know what to do with the methods you call (when you define a method in a class, the first argument self stands for the class object, so each time you initialize an object and then call a method on that, the argument you pass inside the brackets is actually the second argument, first one being the object itself)
third: this is more of a style thing, but you don't really use CamelCase in python except for names of classes, all the rest is in snake_case
fourth: += is more readable and faster than example = example + 1
class CashRegister(object) :
def __init__(self) :
self.total_price = 0
self.item_count = 0
def add_item(self, price) :
self.total_price += int(price)
self.item_count += 1
def get_total(self) :
return self.total_price
def get_count(self) :
return self.item_count
def main() :
register = CashRegister()
selection = True
while selection :
selection = input("Would you like to add another item to the cart Y or N\n\t").upper()
if selection == "Y" :
price = input("What is the price of the item?\n\t")
register.add_item(price)
else :
print(register.get_total())
print(register.get_count())
print(selection)
selection = False
main()
this is how I would probably do it, I've taken out the #property decorators because I don't know if you really have a need for them there, you can just call the methods with brackets () at the end to get what you want
Then, there's a bunch more stuff you should do if you really want to to use this, and that would be exception catching, determine how the cash register behaves if a negative value is passed as price, and so on... good luck and enjoy Python
you have many mistakes you need the determine totalprice and itemcount in self, you need to determine a variable with cashregister class
class CashRegister:
print("Welcome to shopping world!")
def __init__(self):
self.totalPrice=0
self.itemCount=0
def addItem(self, price):
self.totalPrice = self.totalPrice + price
self.itemCount = self.itemCount + 1
#property
def getTotal(self):
return self.totalPrice
#property
def getCount(self):
return self.itemCount
def main():
selection = "Y"
box=CashRegister()
while selection != "N":
selection = input("Would you like to add another item to thecart Y or N\n\t:")
selection = selection.upper()
if selection == "Y":
price = input("What is the price of the item?\n\t:")
box.addItem(int(price))
else:
print(box.getCount)
print(box.getTotal)
print(selection)
main()

Trying to initialize a list, getting __init__ type error

When I try to run an iteration of my Player object, I get this error: init() missing 2 required positional arguments: 'player' and 'number'.
My confusion lies in the idea that I did not think I needed to provide an argument for 'player' and 'number' because I am only trying to show the entire starting-players list. Here is my relevant code:
class Player:
def __init__(self, player, number):
self.player = player
self.number = number
self.starting_players = []
def player_build(self):
for p in ["Player"]:
for n in range(1, 5):
self.starting_players.append(Player(p, n))
print('{} {}'.format(self.player, self.number))
def show(self):
for s in self.starting_players:
s.show()
If you define:
class Player:
def __init__(self, player, number):
...
Then in order to initialize, you must do:
player1 = Player('John', 14)
To be honest, you are better off defining a new class, class Team and having it contain a number of players, class Player.

Sorting a dictionary that contains a class holding 5 variable by one of the class variables

I have a dictionary that contains keys that are made from a class containing 5 variables. I want to sort this dictionary by one of the class vars.
here is what i currently have
class Player:
def __init__(self,name,wins,losses,ties,winpercent):
self.__name = name
self.__wins = wins
self.__losses = losses
self.__ties = ties
self.__winpercent = winpercent
# mutators
def setname(self,name):
self.__name = name
def setwins(self,wins):
self.__wins = wins
def setlosses(self,losses):
self.__losses = losses
def setties(self,ties):
self.__ties = ties
def setwinpercent(self,winpercent):
self.__winpercent = winpercent
# accessors
def getname(self):
return self.__name
def getwins(self):
return self.__wins
def getlosses(self):
return self.__losses
def getties(self):
return self.__ties
def getwinpercent(self):
return self.__winpercent
def displayHighScores(self):
print("\n"," "*2,self.__name," "*(24-len(self.__name)),self.__wins)
def displayplayers(self):
print(self.__name)
I store Players like this:
def addplayer(players):
newName = input("\nEnter new Player name or 9 to quit: ")
wins = "0"
losses = "0"
ties = "0"
winpercent = "0"
if not newName:
print("\nNo name detected try again")
addplayer(players)
elif newName == '9':
print("\nReturning to Options menu")
else:
players[newName] = Player(newName,wins,losses,ties,winpercent)
saveData(players)
return players
Finally i am working on a sorted hi scores list. right now i can print my dictionary unsorted like this:
def printhiscores(players):
print("\n"," "*13,"HiScores")
print(" "*3,"Name"," "*20,"Wins")
if len(players) == 0:
print("\nNo current Players in memory.")
else:
for x in players.keys():
players[x].displayHighScores()
DisplayHighScores () being a part of the class object.
I have been reading on dictionary sorting using
OrderedDict(sorted(players.items(), key=itemgetter(1)))
but this returns edit:TypeError: '<' not supported between instances of 'Player' and 'Player'
Again I am looking to sort my dictionary of players by their win attribute and then print this new order to a high score screen. Any help would be greatly appreciated. I will post if i make any more progress on my own on this.
Your Player instances are not orderable however, as they don't implement comparison methods:
TypeError: '<' not supported between instances of 'Player' and 'Player'
If you wanted to sort them by the value returned, say, wins, then just access that information instead of just returning the value:
OrderedDict(sorted(players.items(), key=lambda kv: kv[1].getwins()))
Otherwise, give your Player class rich comparison methods; methods by which to determine when one instance should be sorted before or after another. You'll also need an equality test. It's easier to just implement support for < (lower then) and equality, then use the #functools.total_ordering decorator to provide the rest:
from functools import total_ordering
#total_ordering
class Player:
def __lt__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins < other.__wins
def __eq__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins == other.__wins
The above makes two Player instances equal when their wins are equal, and orders them by that attribute. You'll need to adjust this for your application as needed.

Calling attributes from classes in Python

I am playing around with classes and I want to do the following:
class Hi (object):
def __init__(self, bloop):
self.bloop = bloop
thing = Hi("bloop")
name = input("Input a thing") # Let`s assume you input thing
print(name.bloop)
What I want it to do is for it to print "bloop" because you entered thing and it gets bloop from thing kinda like thing.bloop.
How about storing thing in a dict:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name].bloop)
except KeyError:
print("Sorry, I dont know that thing :(")
There are, of course, other ways to call an attribute of a class. You could implement a __call__() method, which allows you to call the class instance like a function, and in your case return .bloop:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
def __call__(self):
return self.bloop
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name]())
except KeyError:
print("Sorry, I dont know that thing :(")
This way, you can rename your attribute later, or return another attribute (or do something entirely different altogether), without having to replace .bloop in your main python file.
A third way, which directly relates to your question's title calling attributes from[of] classes in Python: you can use the #Property decorator to make your .bloop attribute callable like a function like so:
class Hi:
def __init__(self, bloop):
self.bloop = bloop
#Property
def bloop():
return self.bloop
#bloop.setter
def bloop(self, new_value)
self.bloop = new_value
things = {'thing': Hi('bloop')}
name = input("Input a thing") # Let`s assume you input 'thing'
try:
print(things[name].bloop())
except KeyError:
print("Sorry, I dont know that thing :(")
To fully understand the Property decorator, I recommend this article.
Btw, according to the tags on your question, you're using Python3.x - you don't have to declare that your class inherits from Object in Python3 and later.

Resources