New to python and this might be a silly question, but how does one properly implement the repr method?
I wrote a quick little program to simulate a game of cards but I don't know what to write for the repr method. The repr method for the Card class was pretty straight forward, but I don't know what to do for the DeckOfCards class Here's my code:
import random
class Card:
'''Create a single card, by id number'''
# Class variables, created once for the class
suits = [ '\u2660', '\u2661', '\u2662', '\u2663' ]
ranks = [ 'A','2','3','4','5','6','7','8','9','10','J','Q','K' ]
def __init__(self, n=0):
# instance variables for _num, _rank, _suit, _value
if 0 <= n < 52:
self._num = n
self._rank = Card.ranks[n%13] # note referencing class vars
self._suit = Card.suits[n//13]
self._value = n%13 + 1
if self._rank == 'A':
self._value = 14
else: # invalid card indicators
self._rank = 'x'
self._suit = 'x'
self._value = -1
def __repr__(self):
return self._rank + self._suit
def __lt__(self,other):
return self._value < other._value
def __le__(self,other):
return self._value <= other._value
def __eq__(self,other):
return self._value == other._value
class DeckOfCards:
'''A Deck is a collection of cards'''
def __init__(self):
self._deck = [ Card(i) for i in range(52) ]
def __repr__(self):
return 'Deck : ', self._deck
def shuffle(self):
return random.shuffle(self._deck)
def deal_a_card(self, i=-1):
#that way player can choose where to draw from
return self._deck.pop(i)
def cards_left(self,count):
return len(self._deck)
new_deck = DeckOfCards()
Also, feel free to comment on anything you'd like, whether it be a design flaw or redundancy in code, literally anything. Thanks in advance!
You should return a string type, for example in Deck:
def __repr__(self):
...
return 'Deck : '+str(self._deck)
__repr__ ideally could return the representation of the object that you would use to create this instance.
From repr():
For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval(), otherwise the representation is a string enclosed in angle brackets that contains the name of the type of the object together with additional information often including the name and address of the object.
First, It should be noted that you don't have to implement the __repr__ method. Python provides a somewhat reasonable default (it'll at least tell you the type).
If you want to implement __repr__, the "rule of thumb" is that where it makes sense, you should provide enough information about the object that a user could reconstruct it. In your case, there doesn't seem to be any real difference from one deck to another, so
def __repr__(self):
return 'Deck()'
might be a reasonable return value. This doesn't get the state right (after shuffling), but you don't provide an interface for constructing a deck in a particular state. If you did, it might look like:
def __repr__(self):
return 'Deck(%s)' % self._deck
Related
While trying to come up with a Hand class for a card game
I encountered a strange behavior from an attribute
if I try to set self.number as seen below it wont show the proper output
but if I make the same argument through a function total() it works properly
my question is: why does the attribute self.number not getting the value of len(self.cards)?
class Hand (object):
def __init__(self,number=0,cards=[]):
self.cards=cards
self.number=len(self.cards)
def total(self):
return len(self.cards)
hand=Hand()
hand.cards.append(9)
print hand.cards
print len(hand.cards)
print hand.number
print hand.total()
output:
[9]
1
0 #I want this to be equal to 1
1
The attribute self.number is set at instantiation, use a property instead.
class Hand (object):
def __init__(self, cards=None):
self.cards = cards or []
#property
def number(self):
return len(self.cards)
def total(self):
return len(self.cards)
Setting an instance variable to an expression does not create a binding between the inputs of that expression and the value of the instance variable. In other terms, setting self.number to len(self.cards) does not mean that self.number will get updated whenever you update self.cards.
Your program is functioning properly: When you create your object, len(self.cards) is 0, so self.number gets set to 0. When you change hand.cards, there are no statements changing self.number, so it stays 0.
The proper way to make your self.number attribute update is to use a getter-setter pair in order to make sure that self.number changes whenever self.cards changes.
The Pythonic way to create a getter-setter pair is to use the #property decorator.
In your case, you could do it like this:
class Hand(object):
def __init__(self, number = 0, cards = None):
self.cards = cards or []
#property
def number(self):
return len(self.cards)
This way, even though it looks to anyone uses your class that they are reading an attribute, what actually happens under the hood is that the number() method gets called and correctly computes the current length of self.cards.
Still somewhat perplexed by python and it's magic functional programming, so I tend to find myself writing code that is more towards the Java paradigm of programming as opposed to Idiomatic Python.
My question is somewhat related to: How do I make a custom class a collection in Python
The only difference is I have nested objects (using composition). The VirtualPage object is comprised of a list of PhysicalPage objects. I have a function which can take a list of PhyscialPage objects and coalesce all of the details into a single named tuple I call PageBoundary. Essentially it's a serialization function which can spit out a tuple comprised of an integer range which represents the physical page and the line number in the page. From this I can easily sort and order VirtualPages among one another (that's the idea at least):
PageBoundary = collections.namedtuple('PageBoundary', 'begin end')
I also have a function which can take a PageBoundary namedtuple and de-serialize or expand the tuple into a list of PhysicalPages. It's preferable that these two data storage classes not change as it will break any downstream code.
Here is a snippet of my custom python2.7 class. It is composed of lot things one is list which contains a the object PhysicalPage:
class VirtualPage(object):
def __init__(self, _physical_pages=list()):
self.physcial_pages = _physcial_pages
class PhysicalPage(object):
# class variables: number of digits each attribute gets
_PAGE_PAD, _LINE_PAD = 10, 12
def __init__(self, _page_num=-1):
self.page_num = _page_num
self.begin_line_num = -1
self.end_line_num = -1
def get_cannonical_begin(self):
return int(''.join([str(self.page_num).zfill(PhysicalPage._PAGE_PAD),
str(tmp_line_num).zfill(PhysicalPage._LINE_PAD) ]))
def get_cannonical_end(self):
pass # see get_cannonical_begin() implementation
def get_canonical_page_boundaries(self):
return PageBoundary(self.get_canonical_begin(), self.get_canonical_end())
I would like to leverage some templated collection (from the python collections module) to easily sort and compare as list or set of VirtualPage classes. Also would like some advice on the layout of my data storage classes: VirtualPage and PhysicalPage.
Given either a sequence of VirtualPages or as in the example below:
vp_1 = VirtualPage(list_of_physical_pages)
vp_1_copy = VirtualPage(list_of_physical_pages)
vp_2 = VirtualPage(list_of_other_physical_pages)
I want to easily answer questions like this:
>>> vp_2 in vp_1
False
>>> vp_2 < vp_1
True
>>> vp_1 == vp_1_copy
True
Right off the bat it seems obvious that the VirtualPage class needs to call get_cannonical_page_boundaries or even implement the function itself. At a minimum it should loop over it's PhysicalPage list to implement the required functions (lt() and eq()) so I can compare b/w VirtualPages.
1.) Currently I'm struggling with implementing some of the comparison functions. One big obstacle is how to compare a tuple? Do I create my own lt() function by creating a custom class which extends some type of collection:
import collections as col
import functools
#total_ordering
class AbstractVirtualPageContainer(col.MutableSet):
def __lt__(self, other):
'''What type would other be?
Make comparison by first normalizing to a comparable type: PageBoundary
'''
pass
2.) Should the comparison function implementation exist in the VirtualPage class instead?
I was leaning towards some type of Set data structure as the properties of the data I'm modeling has the concept of uniqueness: i.e. physical page values cannot overlap and to some extend act as a linked list. Also would setter or getter functions, implemented via # decorator functions be of any use here?
I think you want something like the code below. Not tested; certainly not tested for your application or with your data, YMMV, etc.
from collections import namedtuple
# PageBoundary is a subclass of named tuple with special relational
# operators. __le__ and __ge__ are left undefined because they don't
# make sense for this class.
class PageBoundary(namedtuple('PageBoundary', 'begin end')):
# to prevent making an instance dict (See namedtuple docs)
__slots__ = ()
def __lt__(self, other):
return self.end < other.begin
def __eq__(self, other):
# you can put in an assertion if you are concerned the
# method might be called with the wrong type object
assert isinstance(other, PageBoundary), "Wrong type for other"
return self.begin == other.begin and self.end == other.end
def __ne__(self, other):
return not self == other
def __gt__(self, other):
return other < self
class PhysicalPage(object):
# class variables: number of digits each attribute gets
_PAGE_PAD, _LINE_PAD = 10, 12
def __init__(self, page_num):
self.page_num = page_num
# single leading underscore is 'private' by convention
# not enforced by the language
self._begin = self.page_num * 10**PhysicalPage._LINE_PAD + tmp_line_num
#self._end = ...however you calculate this... ^ not defined yet
self.begin_line_num = -1
self.end_line_num = -1
# this serves the purpose of a `getter`, but looks just like
# a normal class member access. used like x = page.begin
#property
def begin(self):
return self._begin
#property
def end(self):
return self._end
def __lt__(self, other):
assert(isinstance(other, PhysicalPage))
return self._end < other._begin
def __eq__(self, other):
assert(isinstance(other, PhysicalPage))
return self._begin, self._end == other._begin, other._end
def __ne__(self, other):
return not self == other
def __gt__(self, other):
return other < self
class VirtualPage(object):
def __init__(self, physical_pages=None):
self.physcial_pages = sorted(physcial_pages) if physical_pages else []
def __lt__(self, other):
if self.physical_pages and other.physical_pages:
return self.physical_pages[-1].end < other.physical_pages[0].begin
else:
raise ValueError
def __eq__(self, other):
if self.physical_pages and other.physical_pages:
return self.physical_pages == other.physical_pages
else:
raise ValueError
def __gt__(self, other):
return other < self
And a few observations:
Although there is no such thing as "private" members in Python classes, it is a convention to begin a variable name with a single underscore, _, to indicate it is not part of the public interface of the class / module/ etc. So, naming method parameters of public methods with an '_', doesn't seem correct, e.g., def __init__(self, _page_num=-1).
Python generally doesn't use setters / getters; just use the attributes directly. If attribute values need to be calculated, or other some other processing is needed use the #property decorator (as shown for PhysicalPage.begin() above).
It's generally not a good idea to initialize a default function argument with a mutable object. def __init__(self, physical_pages=list()) does not initialize physical_pages with a new empty list each time; rather, it uses the same list every time. If the list is modified, at the next function call physical_pages will be initialized with the modified list. See VirtualPages initializer for an alternative.
I am using Python to implement an Earley Parser that has Context Free rules defined as follows:
class Rule:
def __init__(self,string,i,j,dot):
self.i = 0
self.j = 0
self.dot = 0
string = string.split('->')
self.lhs = string[0].strip()
self.rhs1 = string[1].strip()
self.rhs = []
self.rhs1 = self.rhs1.split(' ')
for word in self.rhs1:
if word.strip()!= '':
self.rhs.append(word)
def __eq__(self, other):
if self.i == other.i:
if self.j == other.j:
if self.dot == other.dot:
if self.lhs == other.lhs:
if self.rhs == other.rhs:
return True
return False
To check whether an object of class Rule exists within a chart array or not, I have used the following:
def enqueue(self, entry, state):
if state in self.chart[entry]:
return None
else:
self.chart[entry].append(state)
where chart is an array that is supposed to contain lists of objects of class Rule:
def __init__(self, words):
self.chart = [[] for i in range(len(words))]
Further I check whether a rule exists as that in the chart[entry] as follows (and if it does not exist, then simply append):
def enqueue(self, entry, state):
if state in self.chart[entry]:
return None
else:
self.chart[entry].append(state)
However this gives me an error as
TypeError: 'in <string>' requires string as left operand, not classobj
To circumvent this, I even declared an __eq__ function in the class itself but it doesn't seem to work. Can anyone help me with the same?
Assuming that your object has only a title attribute which is relevant for equality, you have to implement the __eq__ method as follows:
class YourObject:
[...]
def __eq__(self, other):
return self.title == other.title
Of course if you have more attributes that are relevant for equality, you must include those as well. You might also consider implementing __ne__ and __cmp__ for consistent behaviour.
How can you extend "in" keyword to a class I made? I am making a card game with a Card class. There is another class which is a Hand of a player. Basically I want to see if a certain card is in a hand. An analogy is below:
>>> 5 in range(0, 5)
True
This is my code. I have a Hand class and I want to see if a Card() is in a Hand()
Also, I'm new to this concept of classes. I'm just starting to understand how this whole thing works. Did I implement len method correctly?
class Card:
def __init__(self, suit, rank):
# self.suit > str
# self.rank > str
if (suit in SUITS) and (rank in RANKS):
self.suit = suit
self.rank = rank
else:
self.suit = None
self.rank = None
print "Invalid card:", suit, rank
def __str__(self):
return self.suit + self.rank
def get_suit(self):
return self.suit
def get_rank(self):
return self.rank
# define hand class
class Hand:
# A list of Card objects
# adding cards to the hand should remove cards from the deck.
def __init__(self):
self.hand = []
def __str__(self):
cards = []
for card in self.hand:
cards += [card.get_suit() + card.get_rank()]
return str(cards)
def add_card(self, card):
return self.hand.append(card)
def __len__(self):
counter = 0
for card in self.hand:
counter +=1
return counter
OK, so I added this code in the hand class:
def __contains__(self, card):
return card in self.hand
but I tried testing my code and it doesn't work:
c = Card('H','A')
h = Hand()
h.add_card(Card('S','K'))
h.add_card(Card('D','A'))
h.add_card(Card('H','A'))
print 'hand=', h
print 'c=', c
print 'c in h', c in h
It says False in terminal... Why??
You're looking for the __contains__ magic method.
As for len, your implementation gives the right result, but is needlessly complicated. You can just do:
def __len__(self):
return len(self.hand)
#BrenBarn gave you a pointer in the right direction to look at __contains__. However, as I commented on his answer, implementing that method will probably require that your Card objects be comparable. Right now, two cards will only appear equal if they are both the same object.
For an example of what I mean, try this:
c1 = Card("H", "A")
c2 = Card("H", "A")
print c1 == c2 # False!
To fix this, you need to add the __eq__ method to your Card class (and probably the __ne__ method too, so you'll be able to use != tests). Here's a possible implementation:
def __eq__(self, other):
return self.suit == other.suit and self.rank == other rank
def __ne__(self, other):
return not self == other
There's one other thing I'd like to point out (unrelated to your question). Your Card class has "getter" methods for the suit and rank. Those are usually unnecessary in Python, where you can generally program everything using public variables at first. That is, anything that currently calls card.get_suit should just access card.suit instead.
In less common situation where you need to do complicated things in response to variable access (like calculating certain values when they're requested, or preventing certain values from being assigned), you can put a Property instance in the class (usually as a decorator to a function), and external code can still access it just as if it was still a public variable. Code with lots of getters is common in other programming languages which can't switch between regular variables and Properties like Python can.
In python, I can alter the state of an instance by directly assigning to attributes, or by making method calls which alter the state of the attributes:
foo.thing = 'baz'
or:
foo.thing('baz')
Is there a nice way to create a class which would accept both of the above forms which scales to large numbers of attributes that behave this way? (Shortly, I'll show an example of an implementation that I don't particularly like.) If you're thinking that this is a stupid API, let me know, but perhaps a more concrete example is in order. Say I have a Document class. Document could have an attribute title. However, title may want to have some state as well (font,fontsize,justification,...), but the average user might be happy enough just setting the title to a string and being done with it ...
One way to accomplish this would be to:
class Title(object):
def __init__(self,text,font='times',size=12):
self.text = text
self.font = font
self.size = size
def __call__(self,*text,**kwargs):
if(text):
self.text = text[0]
for k,v in kwargs.items():
setattr(self,k,v)
def __str__(self):
return '<title font={font}, size={size}>{text}</title>'.format(text=self.text,size=self.size,font=self.font)
class Document(object):
_special_attr = set(['title'])
def __setattr__(self,k,v):
if k in self._special_attr and hasattr(self,k):
getattr(self,k)(v)
else:
object.__setattr__(self,k,v)
def __init__(self,text="",title=""):
self.title = Title(title)
self.text = text
def __str__(self):
return str(self.title)+'<body>'+self.text+'</body>'
Now I can use this as follows:
doc = Document()
doc.title = "Hello World"
print (str(doc))
doc.title("Goodbye World",font="Helvetica")
print (str(doc))
This implementation seems a little messy though (with __special_attr). Maybe that's because this is a messed up API. I'm not sure. Is there a better way to do this? Or did I leave the beaten path a little too far on this one?
I realize I could use #property for this as well, but that wouldn't scale well at all if I had more than just one attribute which is to behave this way -- I'd need to write a getter and setter for each, yuck.
It is a bit harder than the previous answers assume.
Any value stored in the descriptor will be shared between all instances, so it is not the right place to store per-instance data.
Also, obj.attrib(...) is performed in two steps:
tmp = obj.attrib
tmp(...)
Python doesn't know in advance that the second step will follow, so you always have to return something that is callable and has a reference to its parent object.
In the following example that reference is implied in the set argument:
class CallableString(str):
def __new__(class_, set, value):
inst = str.__new__(class_, value)
inst._set = set
return inst
def __call__(self, value):
self._set(value)
class A(object):
def __init__(self):
self._attrib = "foo"
def get_attrib(self):
return CallableString(self.set_attrib, self._attrib)
def set_attrib(self, value):
try:
value = value._value
except AttributeError:
pass
self._attrib = value
attrib = property(get_attrib, set_attrib)
a = A()
print a.attrib
a.attrib = "bar"
print a.attrib
a.attrib("baz")
print a.attrib
In short: what you want cannot be done transparently. You'll write better Python code if you don't insist hacking around this limitation
You can avoid having to use #property on potentially hundreds of attributes by simply creating a descriptor class that follows the appropriate rules:
# Warning: Untested code ahead
class DocAttribute(object):
tag_str = "<{tag}{attrs}>{text}</{tag}>"
def __init__(self, tag_name, default_attrs=None):
self._tag_name = tag_name
self._attrs = default_attrs if default_attrs is not None else {}
def __call__(self, *text, **attrs):
self._text = "".join(text)
self._attrs.update(attrs)
return self
def __get__(self, instance, cls):
return self
def __set__(self, instance, value):
self._text = value
def __str__(self):
# Attrs left as an exercise for the reader
return self.tag_str.format(tag=self._tag_name, text=self._text)
Then you can use Document's __setattr__ method to add a descriptor based on this class if it is in a white list of approved names (or not in a black list of forbidden ones, depending on your domain):
class Document(object):
# prelude
def __setattr__(self, name, value):
if self.is_allowed(name): # Again, left as an exercise for the reader
object.__setattr__(self, name, DocAttribute(name)(value))