Python Forum
I need help understanding a program structure using classes
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
I need help understanding a program structure using classes
#11
Yes you can put them in a module and call them in your class file.
If you use:
import checkhandfunctions
Then you'll have to call the functions like this:
checkhandfunctions.checkforpair (hand)
If you use:
import checkhandfunctions as chf
Then you'll have to call the functions like this:
chf.checkforpair (hand)
And if you use:
from checkhandfunctions import *
Then you'll have to call the functions like this:
checkforpair (hand)
Got it?
Reply
#12
Yes, i got it. Thank you very much for your time. It was greatly appreciated.
Reply
#13
Please run this and see if it helps you understand whyhandandself.handare two different things.
class Player:
	flop = []
	turn = []
	river = ['This is Player.river']
	 
	def __init__(self, number, chips):
		self.number = number
		self.chips = chips
		self.hand = ['This is self.hand']
		self.show_how_to_use_class_and_local_variables ()

	def show_how_to_use_class_and_local_variables (self) :
		print ('\n')
		print (self.hand)
		print (Player.river)
		print ('Next is the error because "hand" is undefined.\n\n')
		print (hand)

player1 = Player (7, 11)
Reply
#14
(Dec-26-2021, 08:40 PM)BashBedlam Wrote: Please run this and see if it helps you understand whyhandandself.handare two different things.
class Player:
	flop = []
	turn = []
	river = ['This is Player.river']
	 
	def __init__(self, number, chips):
		self.number = number
		self.chips = chips
		self.hand = ['This is self.hand']
		self.show_how_to_use_class_and_local_variables ()

	def show_how_to_use_class_and_local_variables (self) :
		print ('\n')
		print (self.hand)
		print (Player.river)
		print ('Next is the error because "hand" is undefined.\n\n')
		print (hand)

player1 = Player (7, 11)


Okay but jsut a couple more things:

hand = 3#(1)<---------------I can have a global variable with the same name has an instance variable
deck = [['1','H'], ['2','H'], ['3','H'], ['4','H'], ['5','H']]

def pickacard(deck):
    card = deck[0]
    deck.remove(deck[0])
    return card

class Player:
    flop = []
    turn = []
    river = ['This is Player.river']
      
    def __init__(self, number, chips):
        self.number = number #(2)<---------Since it's number I need to pass an argument when I create an object of that class
        chips = 4#(3)<----------------Since there's no self. before this doesn't work
        self.hand = []#(4)<------------Since i declare it has an empty list, I don't need to give an argument when i create an object, but how do append something do this list?
        self.show_how_to_use_class_and_local_variables ()
 
    def show_how_to_use_class_and_local_variables (self) :
        print ('\n')
        print (self.hand)
        print (Player.river)
        print ('Next is the error because "hand" is undefined.\n\n')
        print (hand)#<----------------This calls the global variable, not the instance variable
        #print(self.chips)#(5)Doesn't work because you can't declare a instance variable like this


    def pickplayershand(self, deck, pickacard):  #<--------- Here (6)
        card = pickacard(deck)
        deck.remove(deck[0])
        hand.append(card)#<--------------------And here(7)
        card = pickacard(deck)
        deck.remove(deck[0])
        hand.append(card)
        return


player1 = Player (7, 11)
print(player1.hand)
How can I modifie self.hand? (4)
#(6) How do i pass the instance variable hand as an argument? self.hand or Player.hand?
#(7)How do I append something to an instance variable list ? Do I write self.hand.append(card)???? (it doesn't work...)
Reply
#15
# 1 Yes you can have a global variable by the same name but I don't recommend it.
# 2 Yes because number is an argument and self.number is a variable that is set to that value.
# 3 chips will work correctly inside of "__init__" but nowhere else.
# 4 I recommend a setter method inside of your class that contains something like "self.hand.append (argument)".
# 5 Correct.
# 6 Will work but would be better if "picacard" was a method inside of your Player class and called like this "self.picacard (deck).
# 7 Will not work. In order to modify a global variable you would have to declare it as global inside of your class

hand = 3 #(1)<---------------I can have a global variable with the same name has an instance variable
deck = [['1','H'], ['2','H'], ['3','H'], ['4','H'], ['5','H']]
 
def pickacard(deck):
    card = deck[0]
    deck.remove(deck[0])
    return card
 
class Player:
    flop = []
    turn = []
    river = ['This is Player.river']
       
    def __init__(self, number, chips):
        self.number = number #(2)<---------Since it's number I need to pass an argument when I create an object of that class
        chips = 4#(3)<----------------Since there's no self. before this doesn't work
        self.hand = []#(4)<------------Since i declare it has an empty list, I don't need to give an argument when i create an object, but how do append something do this list?
        self.show_how_to_use_class_and_local_variables ()
  
    def show_how_to_use_class_and_local_variables (self) :
        print ('\n')
        print (self.hand)
        print (Player.river)
        print ('Next is the error because "hand" is undefined.\n\n')
        print (hand)#<----------------This calls the global variable, not the instance variable
        #print(self.chips)#(5)Doesn't work because you can't declare a instance variable like this
 
    def pickplayershand(self, deck, pickacard):  #<--------- Here (6)
        card = pickacard(deck)
        deck.remove(deck[0])
        hand.append(card)#<--------------------And here(7)
        card = pickacard(deck)
        deck.remove(deck[0])
        hand.append(card)
        return
 
player1 = Player (7, 11)
print(player1.hand)
Reply
#16
So it would be impossible to change self.hand in a function inside the class without a setter?

class Player:
    flop = []
    turn = []
    river = ['This is Player.river']
      
    def __init__(self, number, chips):
        self.number = number 
        self.chips = chips
        self.hand = []


    def pickplayershandwithclassvariable(self, deck):
        card = pickacard(deck)
        variable.append(card)
        #Change self.hand here by adding card to the self.hand list
        return self.hand 
        
Reply
#17
(Dec-27-2021, 02:52 AM)CompleteNewb Wrote: So it would be impossible to change self.hand in a function inside the class without a setter?
No. It's just better to do it that way. All of your instance variables CAN be accessed from outside of the instance, it's just not the best programming practice to do so.
class Player:
	def __init__(self, number, chips):
		self.number = number 
		self.chips = chips
		self.hand = []

player1 = Player (1, 2)
player1.hand = [player1.number, player1.chips]
print (player1.hand) 
Reply
#18
I strongly disagree that setters and getters are better than directly accessing attributes. Use a setter when setting an attribute requires additional processing. For example, if your objects are entries in a database you probably want to modify the database when you set the value of an attribute. This is easy to do with a setter method and/or using the property decorator. However, if your attribute is just a variable and setting the variable doesn't require any additional processing, I would not use a setter.

The thinking that setters and getters make better code can be traced back to poorly designed languages like C++ and all their derivatives and the languages they influenced. Here you often needed setters and getters, or using setters and getters provides some level of protection by limiting how you could access the attributes. In Python a setter/getter provides no projection at all and usually just adds extra code that has to be maintained.

Never, ever use "from module import *". The reason for modules is primarily to generate name spaces, not reduce the amount of code in a file. When you create a namespace you are protection your variable and class names from colliding with variables or class names in code written by other people. Tkinter, a popular Python GUI package, has classes with names like Label and Button. These are nice names. If I make my own type of button I would probably like to call it Button. Since the tkinter Button is tkinter.Button I can do that and not worry about my program confusing my buttons with the tkinter buttons. When you "from module inport *" you strip the namespace protection and all the imported attributes.
BashBedlam likes this post
Reply
#19
I think you should look again at this post by deanhystad. It is an excellent example of how python and OOP work.
(Dec-24-2021, 01:32 PM)deanhystad Wrote: I think you should make a Card class and a Hand class. The Card class knows how to do things like print its name and sort itself among a list of cards. The Hand class would know how to identify pairs and flushes. Mine is incomplete but should give some idea of how this could be done. The Player would be delt a hand, place bets and acquire or pay out chips.
import collections
import random

class Card():
    """A playing card that has a rank and suit"""
    # These are class variables.  They are associated with the class, not instances of the class
    suit_names = ["Clubs", "Diamonds", "Hearts", "Spades"]
    rank_names = ["", "", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"]
    short_rank_names = ["", "", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
    rank_range = range(2, 15)

    def __init__(self, rank, suit):
        # These are instance variables.  Each instance has their own rank an suit
        self.rank = rank
        self.suit = suit

    def __lt__(self, other):
        """For sorting and comparing by rank"""
        return self.rank < other.rank  # self.rank is my rank.  other.rank is the rank of another card

    def __gt__(self, other):
        """For sorting and comparing by rank"""
        return self.rank > other.rank

    def __eq__(self, other):
        """For sorting and comparing by rank"""
        return self.rank == other.rank

    def name(self):
        """Get long name for card"""
        return f"{self.rank_names[self.rank]} {self.suit}"

    def __repr__(self):
        """Get short name for card"""
        return f"{self.short_rank_names[self.rank]}{self.suit[0]}"

class Hand():
    """A list of cards"""
    def __init__(self, cards=None):
        self.cards = [] if cards is None else cards

    def ranks(self):
        """Get list of card ranks and their count.  Use to identify pairs, 3 of a kind etc"""
        def sort_key(counter):
            """Sorting key function for (rank, count) tuples"""
            return (counter[1], counter[0])

        items = list(collections.Counter([card.rank for card in self.cards]).items())
        items.sort(key=sort_key, reverse=True)
        return items

    def suit(self, suit):
        """Get list of cards in specified suit"""
        ranks = [card.rank for card in self.cards if card.suit == suit]
        ranks.sort()
        return ranks

    def suits(self):
        """Get dictionary of cards grouped by suit.  Use to identify flushes"""
        return {suit:self.suit(suit) for suit in Card.suit_names}

    def __repr__(self):
        """Print cards in hand"""
        return ", ".join([str(card) for card in self.cards])


class Deck():
    """Deck of cards"""
    def __init__(self, shuffle=False):
        self.cards = [Card(rank, suit) for rank in Card.rank_range for suit in Card.suit_names]
        if shuffle:
            random.shuffle(self.cards)

    def __len__(self):
        """Return number of cards in deck"""
        return len(self.cards)

    def deal(self, count):
        """Deal count cards from top of deck"""
        cards = self.cards[:count]
        self.cards = self.cards[count:]
        return cards

deck = Deck(True)
hands = [Hand(deck.deal(5)) for _ in range(2)]
for hand in hands:
    print("Hand", hand)
    print("Ranks", hand.ranks())
    print("Suits", hand.suits())
Output:
Hand 4C, 2D, 10D, 2S, 7D Ranks [(2, 2), (10, 1), (7, 1), (4, 1)] Suits {'Clubs': [4], 'Diamonds': [2, 7, 10], 'Hearts': [], 'Spades': [2]} Hand QS, 8H, 5D, 6C, AS Ranks [(14, 1), (12, 1), (8, 1), (6, 1), (5, 1)] Suits {'Clubs': [6], 'Diamonds': [5], 'Hearts': [8], 'Spades': [12, 14]}
Reply
#20
It is, but it's also a bit of a cognitive overload... Anyway, I have to thank you because I have learned a lot. I also have a lot more question, but they're getting less related to the original post(even if we strayed a little)

I am very grateful for your help. Thank you
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Understanding Python classes PythonNewbee 3 1,194 Nov-10-2022, 11:07 PM
Last Post: deanhystad
  Understanding Python super() for classes OmegaRed94 1 1,840 Jun-09-2021, 09:02 AM
Last Post: buran
  Understanding program blocks newbieAuggie2019 2 1,978 Oct-02-2019, 06:22 PM
Last Post: newbieAuggie2019
  help with understanding a program prompt drasil 5 2,968 Feb-14-2019, 05:54 PM
Last Post: ichabod801
  Help, not understanding how classes work... Peter_EU 1 2,335 Jan-20-2018, 06:07 PM
Last Post: wavic
  Using classes? Can I just use classes to structure code? muteboy 5 5,077 Nov-01-2017, 04:20 PM
Last Post: metulburr
  I need help understanding how to use and run this program! Thanks in advance! tc1chosen 6 4,816 Sep-01-2017, 01:56 PM
Last Post: tc1chosen

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020