Add element to list in class - python

I'm still wrestling with classes. Instead of using the classic employees in a company or car example, I've decided to create a simple game character. So far so good, only I'm having trouble adding to an item to a list which is a class.
class Player():
def __init__(self, name, items):
self.name = name
self.items = items
# initialize character
player = Player("Joey",
["movie stub", "keys", "army man"])
print(player.items)
# >> ['movie stub', 'keys', 'army man'] # this is fine
Now I'd like to add an item to the player character.
player.items.push("a rock")
# AttributeError: 'list' object has no attribute 'push'
I was trying using push - only that results in an attribute error. So I added a simple helper class:
# helper class
class List(list):
def push(self, x):
self.append(x)
player.items = List(["a rock"])
Yay! no errors...
print(player.items)
>> ['a rock']
Only instead of appending, it's replaced the list, which is not what I'm after.
Any ideas where I'm going wrong?

You should add push function inside the class itself
class Player():
def __init__(self, name, items):
self.name = name
self.items = items
def push(self, x):
self.items.append(x)
def print(self):
print(self.name,": ",self.items)
# initialize character
player = Player("Joey",
["movie stub", "keys", "army man"])
adding item to the list
player.push("a rock")
printing
player.print()
output
Joey : ['movie stub', 'keys', 'army man', 'a rock']

To be fair you're complicating things. Just made method in class, which add things to your list and you're good to go
class Player():
def __init__(self, name, items):
self.name = name
self.items = items
def add_item(item):
self.items.append(item)
With this
# helper class
class List(list):
def push(self, x):
self.append(x)
player.items = List(["a rock"])
you weren't even passing list you wanted to attach item.
So to make your helper work(you do not need it, method in Player is good enough, but I want to show it anyway, because you asked for it)
class List():
def push(self, list, x):
list.append(x)
my advise is to put method in class player to append there items

If you don't want to replace it, don't replace it? There is nothing special about the name push, and you never called it, so append never occurred, you just replaced the original list with your unnecessary List subclass.
If you must be able to call push instead of append, convert to your List subclass on construction, so it stores a push friendly list from the get-go:
class List(list):
def push(self, x):
self.append(x)
class Player():
def __init__(self, name, items):
self.name = name
self.items = List(items)
Now you can just do:
player = Player("Joey",
["movie stub", "keys", "army man"])
player.items.push("a rock")
and it just works. As a side-benefit, it is now shallow-copying the list provided by the caller, so change's made to the caller's list don't retroactively change the instance's attribute's contents, nor vice-versa.

You need to take a more complete OOP approach by encapsulating data and functionality within your class. Something like this:
class Player():
def __init__(self, name, items):
self._name = name
self._items = items
def push(self, item):
self._items.append(item)
def __repr__(self):
return f'{self._name=}, {self._items=}'
def __str__(self):
return f'Name={self._name}, Items={", ".join(self._items)}'
player = Player("Joey", ["movie stub", "keys", "army man"])
print(player)
player.push('a rock')
print(player)
Output:
Name=Joey, Items=movie stub, keys, army man
Name=Joey, Items=movie stub, keys, army man, a rock

Related

python polymorphism class and function

i am start to learn how to write python code
There is an option to write code ones onthis situation?
i want to crate class and 2 class how extend from her and i want to check if i can loop on only ones my example:
class animal:
def printDetail(self):
print(self.name)
class bird(animal):
def printDetail(self):
super(bird, self).printName()
print(self.wingsSize)
class fish(animal):
def printDetail(self):
super(fish, self).printName()
print(self.weight)
fishList = []
birdList = []
animalList = []
def main():
for a in (animalList,fishList,birdList):
a.printDetail()
main()
when i try to do it i got an error that AttributeError: 'list' object has no attribute 'printDetail' like this is an unknow function. i understand that it try to take the attribute of the list class but there is any option that i can do it more esear then:
for a in animalList:
a.printDetail()
for a in fishList:
a.printDetail()
for a in birdList:
a.printDetail()
that is work fine but to long?
The first code snippet creates a 3-tuple of lists. You're invoking .printDetail() on every list in that tuple.
To create a list that contains the elements from each list (as opposed to a list that contains the lists themselves), you can use for a in (animalList + fishList + birdList):
As others have already answered, there are a variety of quick ways to do this. I prefer the unpacking method that Wups uses in his answer.
However, I also wanted to check if we needed to add initializations to each of these classes in order for the print to work. Further, I was thinking when you called printName in some methods, you meant printDetail instead (maybe I am wrong?). Thus I also revised the class code also, I hope it may benefit you and others who may want to run the code and see a result:
class animal:
def __init__(self, name):
self.name=name
def printDetail(self):
print(self.name)
class bird(animal):
def __init__(self, name, wingsSize):
self.name=name
self.wingsSize = wingsSize
def printDetail(self):
super(bird, self).printDetail()
print(self.wingsSize)
class fish(animal):
def __init__(self, name, weight):
self.name=name
self.weight=weight
def printDetail(self):
super(fish, self).printDetail()
print(self.weight)
fishList = [fish("salmon",12)]
birdList = [bird("eagle",4)]
animalList = [animal("bear")]
def main():
for a in (*animalList, *birdList, *fishList):
a.printDetail()
main()
Output:
bear
eagle
4
salmon
12

Using self_value in another class

I'm trying to learn more about classes so I've built a deck of cards using multiple classes. The goal is to be able to play multiple card games with the deck.
I have a basic class, called PlayingCard:
class PlayingCard:
def __init__(self, suit, value):
self.suit = suit
self.value = value
And different sub-classes for the numbered cards, the jack cards, the queen cards etc. defined as:
class NumberedCards(PlayingCard):
def __init__(self, suit, value):
self.value = value
super().__init__(suit, self.value)
class JackCard(PlayingCard):
def __init__(self, suit):
self.value = 11
super().__init__(suit, self.value)
...and so on
I then build my deck of cards in a new class, 'Deck':
class Deck:
def __init__(self):
self.deck = []
def create_deck(self):
for suit in Suit:
for i in range(2, 11):
self.deck.append(NumberedCards(suit.value, i))
self.deck.append(JackCard(suit.value))
...
Lastly, I have a class called Hand:
class Hand:
def __init__(self):
self.hand = []
where I have functions to draw cards from the deck and place them in self.hand
I now want to create yet another class with different functions, where I can use a Hand()-instance to check if there's for example any pairs in the hand or if there's a straight etc.
I have something like this in mind:
class BestHand:
def __init__(self):
...
def check_pairs(self, cards):
"""Here, for example, I want to extract the value of
each card on hand and put them in a new list for easier comparison"""
where I then can check the cards in the hand by calling something in the style of
hand = Hand()
test = BestHand()
test.check_pairs(hand)
The problem is that I can't extract the value from the hand-cards. I realize they're only defined as self.value in the class PlayingCard, but is there a way to extract them to use in the BestHand class?
You have an object called hand, it is of type Hand meaning it has an attribute called hand which is list of Card objects. hand.hand is the list of Card objects in that object. [card.value for card in hand.hand] will get the value for each card in that list of cards

Get a dict of all properties of self without including child class properties

Say I have the following two classes:
class PlayerState:
def __init__(self):
self.someStateProp = 10
# get the state of this class only as a dict
def getState(self):
return {name: attr for name, attr in self.__dict__.items()
if not name.startswith("__")
and not callable(attr)
and not type(attr) is staticmethod}
class Player(PlayerState):
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'
player = Player()
print(player.getState())
# someNonStateProp should not be shown
>> {'someStateProp': 10, 'someNonStateProp': 'foo'}
The method PlayerState.getState as it stands is able to return a dict containing all attributes of itself, excluding constructors and methods. I want to expand on it and make it also only return the direct properties of PlayerState, and not Player.
Edit: Using self.__class__.__dict__.items() instead of self.__dict__.items() just gives me all the methods of Player.
You provide no way to really differentiate between state and non-state attributes. If the object is mutable and has a mutable dict, there is really no way to determine who set the value for a particular attribute. There will be cases where children will want to add to the state. If the state is something special, keep it as a separate dictionary instead of filtering every time:
class PlayerState:
def __init__(self):
self.state = {}
self.state['someProp'] = 10
# get the state of this class only as a dict
def getState(self):
return self.state
class Player(PlayerState):
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'
self.state['otherProp'] = 'bar'
If it bothers you that you can't access state elements through normal dot access, add some properties to your class:
#property
def someStateProp(self):
return self.state['someProp']
Alternatively, hard-code a list of the names you want.
class PlayerState:
states = ['someStateProp']
def __init__(self):
self.someStateProp = 10
# get the state of this class only as a dict
def getState(self):
return {name: getattr(self, name) for name in self.names}
class Player(PlayerState):
names = PlayerState.names + ['otherStateProp']
def __init__(self):
super().__init__()
self.someNonStateProp = 'foo'

Python object keeping data from previous?

I've seen multiple instances of this question like this one, but it fails to identify what exactly I am doing wrong since I don't have default arguments.
What am I doing wrong? Python object instantiation keeping data from previous instantiation?
#Table.py
class Table:
def __init__(self, players):
self.deck = Deck()
And this is Main
t = Table(2)
print len(t.deck.cards)
t = Table(2)
print len(t.deck.cards)
I would expect this to print 48 each time, but instead it prints
48 and then 96
Why is this? Shouldn't this member variable be overridden every time?
#Deck.py
from Card import *
import random
class Deck:
suits = ['H','C','D','S']
numbers = [2,3,4,5,6,7,8,9,10,11,12,13,14]
cards = []
def __init__(self):
for num in self.numbers:
for suit in self.suits:
c = Card(num,suit)
self.cards.append(c);
random.shuffle(self.cards)
Card.py
class Card:
def __init__(self, num, suit):
self.num = num
self.suit = suit
def __repr__(self):
return str(self.num) + str(self.suit)
def __str__(self):
return str(self.num) + str(self.suit)
Initialize cards in the constructor, like this:
def __init__(self):
self.cards = []
for num in self.numbers:
for suit in self.suits:
c = Card(num,suit)
self.cards.append(c);
random.shuffle(self.cards)
That way, every time a new instance of the class is created, cards will be freshly initialized.
Your approach didn't work as you wished, since cards is a class data member, shared among all instances of class Deck.
suits, numbers and cards are class variables. So when doing self.cards.append(c) you add to a class variable, which is shared by all instances of all Deck instances.
Put them into __init__ instead:
def __init__(self):
self.cards = []
for num in self.numbers:
for suit in self.suits:
c = Card(num,suit)
self.cards.append(c);
random.shuffle(self.cards)
You are using class variables instead of instance variables. See, for example, python class variables
So even though you instantiate a new instance, you don't get a new instance of the static class variables.
Suits, numbers, cards. If you want instance variables, use "self.", and do it in the init function.
You are appending cards each time you instantiate, but you are appending them to the class variable. Thus you end up with twice as many.

Managing Instances in Python

I am new to Python and this is my first time asking a stackOverflow question, but a long time reader. I am working on a simple card based game but am having trouble managing instances of my Hand class. If you look below you can see that the hand class is a simple container for cards(which are just int values) and each Player class contains a hand class. However, whenever I create multiple instances of my Player class they all seem to manipulate a single instance of the Hand class. From my experience in C and Java it seems that I am somehow making my Hand class static. If anyone could help with this problem I would appreciate it greatly.
Thank you,
Thad
To clarify: An example of this situation would be
p = player.Player()
p1 = player.Player()
p.recieveCard(15)
p1.recieveCard(21)
p.viewHand()
which would result in:
[15,21]
even though only one card was added to p
Hand class:
class Hand:
index = 0
cards = [] #Collections of cards
#Constructor
def __init__(self):
self.index
self.cards
def addCard(self, card):
"""Adds a card to current hand"""
self.cards.append(card)
return card
def discardCard(self, card):
"""Discards a card from current hand"""
self.cards.remove(card)
return card
def viewCards(self):
"""Returns a collection of cards"""
return self.cards
def fold(self):
"""Folds the current hand"""
temp = self.cards
self.cards = []
return temp
Player Class
import hand
class Player:
name = ""
position = 0
chips = 0
dealer = 0
pHand = []
def __init__ (self, nm, pos, buyIn, deal):
self.name = nm
self.position = pos
self.chips = buyIn
self.dealer = deal
self.pHand = hand.Hand()
return
def recieveCard(self, card):
"""Recieve card from the dealer"""
self.pHand.addCard(card)
return card
def discardCard(self, card):
"""Throw away a card"""
self.pHand.discardCard(card)
return card
def viewHand(self):
"""View the players hand"""
return self.pHand.viewCards()
def getChips(self):
"""Get the number of chips the player currently holds"""
return self.chips
def setChips(self, chip):
"""Sets the number of chips the player holds"""
self.chips = chip
return
def makeDealer(self):
"""Makes this player the dealer"""
self.dealer = 1
return
def notDealer(self):
"""Makes this player not the dealer"""
self.dealer = 0
return
def isDealer(self):
"""Returns flag wether this player is the dealer"""
return self.dealer
def getPosition(self):
"""Returns position of the player"""
return self.position
def getName(self):
"""Returns name of the player"""
return self.name
From my experience in C and Java it seems that I am somehow making my Hand class static.
Actually, that is basically what you're doing. Well, not really making the class static, but making the variable static.
When you write declarations like this:
class Hand:
cards = []
that variable (cards) is associated with the class, not with the instance. To make an analogy to Java, every statement in a Python class that isn't part of a method of that class basically runs in a static initializer. You could almost think of it like this:
class Hand {
static {
cards = new object[];
}
}
(merely a rough analogy, of course)
To create an instance variable in Python, you have to set it as an attribute of the instance, which requires you to wait until you have a reference to the instance. In practice, this means you initialize it in the constructor, like so:
class Hand:
def __init__(self):
self.cards = []
Your problem is quite simple
if you assign lists to the body of python classes, when you append items to it, they will be store at Class level, not at instance level.
you can solve this problem by adding the line:
def __init__(self):
self.cards = []
this is a very known case of python pitfall, and I recommend you the reading:
http://zephyrfalcon.org/labs/python_pitfalls.html
As other answers noted, you were confused about class variables vs. instance variables. I suggest you review the basics of how Python classes work. Here is an answer I wrote for another question; reading this might help you.
How to define a class in Python

Categories

Resources