as a beginner, I met the below problem, I created a class for complex number calculation. the problem is from the str method. can you tell me the reason and how can I solve it? thank you!
import math
class Complex(object):
def __init__(self, real, imaginary):
self.real= real
self.imaginary = imaginary
def __add__(self, other):
return Complex(self.real + other.real, self.imaginary + other.imaginary)
def __sub__(self, other):
return Complex(self.real - other.real, self.imaginary - other.imaginary)
def __mul__(self, other):
return Complex(self.real*other.real-self.imaginary*other.imaginary,self.real*other.imaginary+self.imaginary*other.real)
def __truediv__(self, other):
r=(self.real*other.real+self.imaginary*other.imaginary)/(other.real**2+other.imaginary**2)
img=(self.imaginary*other.real-self.real*other.imaginary)/(other.real**2+other.imaginary**2)
return Complex(r,img)
def mod(self):
return Complex((self.real**2+self.imaginary**2)**0.5, 0)
def __str__(self):
if self.imaginary == 0:
result = "%.2f+0.00i" % (self.real)
elif self.real == 0:
if self.imaginary >= 0:
result = "0.00+%.2fi" % (self.imaginary)
else:
result = "0.00-%.2fi" % (abs(self.imaginary))
elif self.imaginary > 0:
result = "%.2f+%.2fi" % (self.real, self.imaginary)
else:
result = "%.2f-%.2fi" % (self.real, abs(self.imaginary))
if __name__ == '__main__':
c = map(float, input().split())
d = map(float, input().split())
x = Complex(*c)
y = Complex(*d)
print(*map(str, [x+y, x-y, x*y, x/y, x.mod(), y.mod()]), sep='\n')
The __str__() method should return the strings, not assign them to a variable.
def __str__(self):
if self.imaginary == 0:
return "%.2f+0.00i" % (self.real)
elif self.real == 0:
if self.imaginary >= 0:
return "0.00+%.2fi" % (self.imaginary)
else:
return "0.00-%.2fi" % (abs(self.imaginary))
elif self.imaginary > 0:
return "%.2f+%.2fi" % (self.real, self.imaginary)
else:
return "%.2f-%.2fi" % (self.real, abs(self.imaginary))
I am creating an object that represents the hand of a blackjack player. One of the methods of the hand is to add a new Card to it. However, my Hand object always returns None when I attempt to print it.
Here is my code of the Hand object.
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def addCard(self, card):
self.list = self.list.append(card)
return self.list
def __str__(self):
return f'Your hand has {self.list}.'
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
myCard is an object that returns "Four of Diamonds" I created previously. Below is the whole code if you are interested.
class Card:
''' A class for representing a single playing card. '''
def __init__(self, value, suit):
''' Creates Card object with given suit and value. '''
self.value = value
self.suit = suit
def getSuit(self):
''' Returns the suit of the Card. '''
return self.suit
def getValue(self):
''' Returns the value of the Card. '''
return self.value
def getBlackjackValues(self):
''' Get a list of possible Blackjack values for the card. '''
# IMPLEMENT ME
if 1 < self.value:
BlackjackValue = self.value
return [BlackjackValue]
else:
BlackjackValue = [self.value, 11]
return BlackjackValue
def __str__(self):
''' #Return a string representation of the Card. '''
# IMPLEMENT ME
# Convert numerical values into letters
if self.value == 2:
Value = 'Two'
elif self.value == 3:
Value = 'Three'
elif self.value == 4:
Value = 'Four'
elif self.value == 5:
Value = 'Five'
elif self.value == 6:
Value = 'Six'
elif self.value == 7:
Value = 'Seven'
elif self.value == 8:
Value = 'Eight'
elif self.value == 9:
Value = 'Nine'
elif self.value == 10:
Value = 'Ten'
elif self.value == 11:
Value = 'Jack'
elif self.value == 12:
Value = 'Queen'
elif self.value == 13:
Value = 'King'
elif self.value == 1:
Value = 'Ace'
# Convert suit values into letter
if self.suit == 'S':
Suit = 'Spades'
elif self.suit == 'H':
Suit = 'Hearts'
elif self.suit == 'D':
Suit = 'Diamonds'
elif self.suit == 'C':
Suit = 'Clubs'
# The card is
return f'Your card is {Value} of {Suit}.'
myCard = Card (4, 'D')
print (myCard)
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def getName(self):
return self.name
def getList(self):
return self.list
def addCard(self, card):
self.list = self.list.append(card)
return self.list
def __str__(self):
return f'Your hand has {self.list}.'
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
Here is the screenshot of the output:
Output
list.append() method works in place, i.e. it returns None. That is what you assign to self.list. Note that if you try to add second card it will raise an error, because None has no append attribute.
All I need to do is use .append() at the return statement in the addCard method.
Also, credits to #Nja for pointing out that I do not need to update myHand object again, but simply initiate the method.
Try this:
class Hand:
'''An object representing the Card objects that the player has in their hands'''
def __init__(self, name):
self.name = name
self.list = []
def addCard(self, card):
self.list.append(card)
def __str__(self):
return 'Your hand has ' + ' '.join(self.list)
myCard = "ciao"
myHand = Hand('Henry')
myHand.addCard(str(myCard))
print (myHand)
for java, we can do:
for(int i=100; i>2 ; i=i/2){things to execute}
but what if in python?
is there anything like
for i in range(100:2:something)
could solve this problem?
If you need something simple which you can have at hand at several places, you can create a generator function:
def range_divide(start, end, denominator): # TODO: Think for a better name!
value = start
while value > end:
yield value
value /= denominator
and then do
for value in range_divide(100, 2, 2):
# do_stuff
You could even flexibilize this with
def range_flexible(start, end, action):
value = start
while value > end:
yield value
value = action(value)
and do
for value in range_flexible(100, 2, lambda x: x/2):
# do_stuff
or even
def for_loop(start, cont_condition, action):
value = start
while cont_condition(value):
yield value
value = action(value)
for value in for_loop(100, lambda x: x > 2, lambda x: x/2):
# do_stuff
There isn't by using a range, you could prepopulate a list and iterate over that but you'd be better off using a while loop.
i = 100
while i > 2:
...
i = i / 2
If you want it to look more like a java (or C) for loop, you can define a function that will process the parameters as a string in the C style (at the expense of execution speed):
cachedCFor = dict()
def cFor(params):
if params in cachedCFor: return cachedCFor[params]()
setup,condition,step = [ p.strip() for p in params.split(";") ]
varName = setup.split("=",1)[0].strip()
fn = dict()
code = f"""
def iterator():
{setup}
while {condition}:
yield {varName}
{step}
"""
exec(code,{},fn)
cachedCFor[params] = fn["iterator"]
return fn["iterator"]()
for i in cFor("i=100;i>2;i=i/2"):
print(i)
100
50.0
25.0
12.5
6.25
3.125
Note that the i variable in the string parameter is internal to the iterator and is not accessible within the for loop's code. We could have written for i in cFor("x=100;x>2;x=x/2") and still use i within the loop
That being said, I would still suggest that you embrace Python's way of doing things and not try to reproduce other language's syntax (i.e. use a while statement in this particular case)
for example:
x = 100
while x > 2:
i,x = x,x/2 # using x for the next value allows this to be placed
# at the beginning of the loop (rather than at the end)
# and avoids issues with the continue statement
print(i)
# ... your code ...
Or, you could use a bit of math:
# 6 = int(math.log(100,2))
for i in [100/2**i for i in range(6)]:
print(i)
# Strangely enough, this is actually slower than the cFor() folly
Here's another approach to handle special progressions in a cleaner and more generic fashion. It is a class that implements (and hides) internal workings of a loop variable.
class Loop:
def __init__(self,start=0):
self._firstPass = True
self._value = start
#property
def value(self): return self._value
def start(self,initial):
if self._firstPass : self._value = initial
return self
def next(self,nextValue=None):
if nextValue is None : nextValue = self.value + self._increment
if self._firstPass : self._firstPass = False
else : self._value = nextValue
return self
def up(self,by=1):
return self.next(self.value+by)
def down(self,by=1):
return self.next(self.value-by)
def upTo(self,last,by=1):
if self._firstPass: self._firstPass = False
else: self._value += by
return self.value <= last
def downTo(self,last,by=1):
if self._firstPass: self._firstPass = False
else: self._value -= by
return self.value >= last
def loop(self,condition=True):
self._firstPass = False
return condition
def until(self,condition=False):
self._firstPass = False
return not condition
def __getitem__(self,index): return self.value[index]
def __str__(self): return str(self.value)
def __int__(self): return int(self.value)
def __float__(self): return float(self.value)
def __add__(self,other): return self.value + other
def __sub__(self,other): return self.value - other
def __mul__(self,other): return self.value * other
def __matmul__(self,other): return self.value.__matmul__(other)
def __divmod__(self,other): return divmod(self.value,other)
def __pow__(self,other): return self.value ** other
def __truediv__(self,other): return self.value / other
def __floordiv__(self,other): return self.value // other
def __mod__(self,other): return self.value % other
def __lshift__(self,other): return self.value << other
def __rshift__(self,other): return self.value >> other
def __lt__(self,other): return self.value < other
def __le__(self,other): return self.value <= other
def __eq__(self,other): return self.value == other
def __ne__(self,other): return self.value != other
def __gt__(self,other): return self.value > other
def __ge__(self,other): return self.value >= other
def __and__(self,other): return self.value & other
def __or__(self,other): return self.value | other
def __xor__(self,other): return self.value ^ other
def __invert__(self): return -self.value
def __neg__(self): return -self.value
def __pos__(self): return self.value
def __abs__(self): return abs(self.value)
def __radd__(self, other): return other + self.value
def __rsub__(self, other): return other - self.value
def __rmul__(self, other): return other * self.value
def __rmatmul__(self, other): return other.__matmul__(self.value)
def __rtruediv__(self, other): return other / self.value
def __rfloordiv__(self, other): return other // self.value
def __rmod__(self, other): return other % self.value
def __rdivmod__(self, other): return divmod(other,self.value)
def __rpow__(self, other): return other ** self.value
def __rlshift__(self, other): return other << self.value
def __rrshift__(self, other): return other >> self.value
def __rand__(self, other): return other & self.value
def __rxor__(self, other): return other ^ self.value
def __ror__(self, other): return other | self.value
The class is designed to work with the while statement after initializing a loop variable. The loop variable behaves like a normal int (or float, or str, etc.) when used in calculations and conditions. This allows the progression and stop condition to be expressed as you would write them for an ordinary loop variable. The class adds a few method to control the loop process allowing for non-standard increments/decrements:
For example:
i = Loop()
while i.start(100).next(i//2).loop(i>2):
print(i) # 100, 50, 25, 12, 6 ,3
# Note: to use i for assignment or as parameter use +i or i.value
# example1: j = +i
# example2: for j in range(+i)
#
# i.value cannot be modified during the loop
You can also give a start value in the constructor to make the while statement more concise. The class also has an until() function to invert the stop condition:
i = Loop(start=100)
while i.next(i//2).until(i<=2):
print(i) # 100, 50.0, 25.0, 12.5, 6.25, 3.125
Finally there are a couple of helper functions to implement the simpler loops (although a for in would probably be better in most cases):
i = Loop()
while i.start(1).upTo(10):
print(i) # 1,2,...,9,10
i = Loop()
while i.upTo(100,by=5):
print(i) # 0,5,10,15,20,...,95,100
i = Loop(100)
while i.down(by=5).until(i<20):
print(i) # 100,95,90,...,25,20
I am trying to figure out how to make the values of t, j, q, and k to the int value of 10. Can someone explain where I went wrong with this?
class Card:
def __init__(self, value , suit):
self.value = value
self.suit = suit
def __repr__(self):
return "The " + self.value + " of " + self.suit
def intValue(self):
if int(self.value) > 2 or int(self.value) < 9:
return self.value
elif str(self.value) == 'a':
return 1
elif str(self.value) == 'j' or str(self.value) == 'q' or str(self.value) == 'k' or str(self.value) == 't':
return 10
Although I agree with the comments about using a dictionary to represent the values, let's fix what you have. It's mostly a matter of keeping it simple and remembering the type of your data (str) and not randomly imposing str() and int() calls when they're not needed:
class Card:
def __init__(self, value, suit):
self.value = value
self.suit = suit
def __repr__(self):
return "The {} of {}".format(self.value, self.suit)
def intValue(self):
if self.value.isdigit():
return int(self.value)
elif self.value == 'a':
return 1
else:
return 10
I have just learned about iterators in Python however I am having a hard time implementing them.
I am trying to write a class to so that this loop works:
odds = OddNumbers(13)
for i in odds:
print(i)
I want to write an iter() function and next() function to do this.
So far I have:
class OddNumbers:
def __init__(self, number):
self.number = number
def __iter__(self):
return self
def __next__(self):
current = self.number
if self.number%2 == 0:
return current
else:
raise StopIteration
But at the moment this is returning nothing. I expect the output to be
1
3
5
7
9
11
13
Help?
Your object needs to keep track of its state and update it when __next__ is called.
class OddNumbers(object):
def __init__(self, number):
self.current = ...
self.number = number
def __iter__(self):
return self
def __next__(self):
# Update self.current
# If the limit has been reached, raise StopIteration
# Otherwise, return something
You need another variable to track the current number:
def __init__(self, number):
self.number = number
self.current = 1
Then you need to compare it with the ending number, and maybe increment it:
def __next__(self):
if self.current > self.number:
raise StopIteration
current = self.current
self.current += 2
return current
There is probably a much cleaner way of doing this, but here is a quick stab:
class OddNumbers:
def __init__(self, number):
self.number = number
def __iter__(self):
self.current = self.number
return self
def __next__(self):
if self.current > 0:
if self.current % 2 == 0:
self.current -= 1
self.current -= 1
return self.current + 1
raise StopIteration
This will give you an iterator-like object which provides even or odd numbers. However, it won't satisfy your for loop semantics as it is not a true iterator.
class NumberIterator(object):
"""Returns simple even/odd number iterators."""
def __init__(self, current):
self.current = current
def next(self):
self.current += 2
return self.current
#classmethod
def getOddIterator(cls):
return cls(-1) # start at 1
#classmethod
def getEvenIterator(cls):
return cls(0) # start at 2
odd_numbers = NumberIterator.getOddIterator()
even_numbers = NumberIterator.getEvenIterator()
odd_numbers.next() # Returns 1
odd_numbers.next() # Returns 3