0

I've created a class called Card, which takes a number and gives the following output depending on the methods called:

class Card:

def __init__(self, number):
    self.number = number

def suit(self):
    if self.number in range(0, 13):
        return 0
    elif self.number in range(13, 26):
        return 1
    elif self.number in range(26, 39):
        return 2
    elif self.number in range(39, 52):
        return 3

def rank(self):
    if self.number in range(0, 13):
        return self.number
    elif self.number in range(13, 26):
        return self.number - 13
    elif self.number in range(26, 39):
        return self.number - 26
    elif self.number in range(39, 52):
        return self.number - 39

def points(self):
    if self.number in (12,25,38,51):
        return 4
    elif self.number in (11,24,37,50):
        return 3
    elif self.number in (10,23,36,49):
        return 2
    elif self.number in (9,22,35,48):
        return 1
    else:
        return 0
def __repr__(self):
    ranks = ['2','3','4','5','6','7','8','9','10','J','Q','K','A']

    if self.number in range(0, 13):
        return ranks[self.number] + '\u2663'

    elif self.number in range(13, 26):
        return ranks[self.number - 13] + '\u2666'

    elif self.number in range(26, 39):
        return ranks[self.number - 26] + '\u2665'

    elif self.number in range(39, 52):
        return ranks[self.number - 39] + '\u2660'

def __lt__(self,other):
    if str(self.rank) < str(other.rank):
        return True
    else:
        return False

* any tips on making the code better are appreciated

Now I have to write a class called BlackjackCard with Card class inherited:

class BlackjackCard(Card):

def __init__(self, number):
    Card.__init__(self, number)

def points(self):

    if self.rank == 12:
        return 11
    elif self.rank in (11,10,9):
        return 10
    elif self.rank < 11:
        return self.rank

I am trying to overload the method points() by rewriting but I can't seem to implement self.rank from class Card. When I assign y = BlackjackCard(38) and executey.points(), it gives me a type error: unorderable types: method() < int().

What am I doing wrong here?

3
  • Tip: The repetitiveness of the checks should clue you in that there's a better way. How could you calculate the suit, rank, and points using math instead of a chain of if/else statements? (As a hint, try using the division and modulus operators.) Commented Apr 13, 2015 at 23:54
  • I very much agree the code is repetitive but how could I make it simpler? Could you give me an example on one of them? Commented Apr 14, 2015 at 0:06
  • I've figured out the mathematical relationships for method rank and method suit. Thanks again! Commented Apr 14, 2015 at 1:14

2 Answers 2

2

self.rank is a method. Either call it by adding parens (self.rank()), or convert it into a property.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I didn't know that's how you had to call it
0

Ignacio's answer is the right one (using property), but in terms of improving your code in general, a few suggestions.

First, instead of if foo in range(a, b):, you can just do if a <= foo < b: But in your case, you can simplify this further using math. The suit is just floor(number/13), or more simply number//13. Similarly, the rank is the the remainder of number/13, the modulo of 13, which is number%13.

Second, rather than re-calculate everything every time, you can re-use the result of one method in another. For example, you re-calculate the suit in __repr__.

Finally, boolean tests in python, like x < y, resolve to True or False. So rather than return True if the test passes and False if it doesn't, you can just return the result of the test exactly.

Also, I don't think you want to return the str of the rank in __lt__, but rather the numerical rank.

So here is my improved version:

class Card:
    def __init__(self, number):
        self.number = number

    @property
    def suit(self):
        return self.number // 13

    @property
    def rank(self):
        return self.number % 13

    @property
    def points(self):
        return max(0, self.rank-8)

    @property
    def suit_str(self):
        suits = ['\u2663', '\u2666', '\u2665', '\u2660']
        return suites[self.suit]

    @property
    def rank_str(self):
        ranks = {9: 'J', 10: 'Q', 11: 'K', 12: 'A'}
        return ranks.get(self.rank, str(self.rank+2))

    def __repr__(self):
        return self.rank_str+self.suit_str

    def __lt__(self, other):
        return self.rank < other.rank

2 Comments

oh wow thank you so much. this helped alot! But what does @property stand for? What does it do? Not sure if we've learned that yet
That is what Ignacio was recommending. Normally, when you want to do a method, you do something like myhand.rank(). However, if the method takes no inputs (except the object, self), you can use the @property decorator to change it so you can use this syntax: myhand.rank. It seems the same as getting an attribute to the user (like myhand.number), but in this case it is read-only. You can also make a property writable, but you don't need that in this case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.