not able to print instance using def __str__ , in a class? - python

I'm learning Python and currently learning Classes.
I'm not able to print the instance of a class, the code is as follows.
class CreditCard:
""" This is properly intended, but CNTRL+K resulted in unindentation
(stackoverflow's cntrl+k)"""
def __init__(self,customer,bank,account,limit):
""" Initializing the variables inside the class
Setting the Initial Balance as Zero
Customer : Name of the Customer
bank : Name of the Bank
balance : will be zero, initial
account : accoount number or identifier, generally a string
limit : account limit/ credit limit
"""
self.customer = customer
self.bank = bank
self.accnt=account
self.limit = limit
self.balance = 0
def get_customer(self):
""" returns the name of the customer """
return self.customer
def get_bank(self):
""" returns the Bank name """
return self.bank
def get_account(self):
""" returns the Account Number """
return self.account
def get_limit(self):
""" returns the Credit Limit """
return self.limit
def get_balance(self):
""" returns the Balance """
return self.balance
def charge(self,price):
""" swipe charges on card, if sufficient credit limit
returns True if transaction is processed, False if
declined """
if price + self.balance > self.limit:
return False
else:
self.balance=price+self.balance
# abve can be written as
# self.balance+=price
return True
def make_payment(self,amount):
""" cust pays money to bank, that reduces balance """
self.balance = amount-self.balance
# self.balance-=amount
def __str__(self):
""" string representation of Values """
return self.customer,self.bank,self.account,self.limit
I'd run that with no error.
I've created an instance,
cc=CreditCard('Hakamoora','Duesche',12345678910,5000)
this is what I've been getting.
>>> cc
<__main__.CreditCard instance at 0x0000000002E427C8>
what should I include to make it print the instance, like
>>cc=CreditCard('Hakamoora','Duesche',12345678910,5000)
>>cc
>>('Hakamoora','Duesche',12345678910,5000)
Kindly use less technical terms(Newbie here)
pastebinlink : https://paste.ee/p/rD91N
also tried these,
def __str__(self):
""" string representation of Values """
return "%s,%s,%d,%d"%(self.customer,self.bank,self.account,self.limit)
and
def __str__(self):
""" string representation of Values """
return "({0},{1},{2},{3})".format(self.customer,self.bank,self.account,self.limit)
Thanks,
6er

You're mixing up __str__ and __repr__. Consider the following class:
class Test(object):
def __str__(self):
return '__str__'
def __repr__(self):
return '__repr__'
You can see which method is called where:
>>> t = Test()
>>> t
__repr__
>>> print(t)
__str__
>>> [1, 2, t]
[1, 2, __repr__]
>>> str(t)
'__str__'
>>> repr(t)
'__repr__'
Also, make sure both of those methods return strings. You're currently returning a tuple, which will cause an error like this to come up:
TypeError: __str__ returned non-string (type tuple)

Three points:
(1) Ensure that the indentation level of your definition of __str__ is such that it's a method of the CreditCard class. Currently it seems to be a function defined locally inside charge() and hence maybe not accessible as an instance method (But it's hard to tell for sure: charge() itself and its fellow methods are also incorrectly indented.)
(2) In __str__, return a string, rather than a tuple:
def __str__(self):
""" string representation of Values """
return str( ( self.customer,self.bank,self.account,self.limit ) )
(3) Define an additional __repr__ method: this will be used when displaying the object with
>>> cc
whereas __str__ will only be used when somebody (like print) tries to coerce the object to a str. Here's a minimal example:
def __repr__( self ): return str( self )

You forgot to turn the object into a string (or print it).
Try instead:
print(cc)
or
str(cc)

Is the file really indented properly? The last two methods (make_payment and __str__) are indented as if they are a part of the 'charge'-method.
I tested this on my system and the indentation on these two methods (especially __str__) caused the same error as yours. Removing the indentation allowed me to print the 'cc' variable the way you want it.

The is the corrected code,
I've learned a grea concept today, learnt about repr and str.
Example for class
Credit card
class CreditCard:
""" Just a Normal Credit Card """
def __init__(self,customer,bank,account,limit):
""" Initializing the variables inside the class
Setting the Initial Balance as Zero
Customer : Name of the Customer
bank : Name of the Bank
balance : will be zero, initial
account : accoount number or identifier, generally a string
limit : account limit/ credit limit
"""
self.customer = customer
self.bank = bank
self.account=account
self.limit = limit
self.balance = 0
def get_customer(self):
""" returns the name of the customer """
return self.customer
def get_bank(self):
""" returns the Bank name """
return self.bank
def get_account(self):
""" returns the Account Number """
return self.account
def get_limit(self):
""" returns the Credit Limit """
return self.limit
def get_balance(self):
""" returns the Balance """
return self.balance
def charge(self,price):
""" swipe charges on card, if sufficient credit limit
returns True if transaction is processed, False if
declined """
if price + self.balance > self.limit:
return False
else:
self.balance=price+self.balance
# abve can be written as
# self.balance+=price
return True
def make_payment(self,amount):
""" cust pays money to bank, that reduces balance """
self.balance = amount-self.balance
# self.balance-=amount
def __str__(self):
""" string representation of Values """
return str((self.customer,self.bank,self.account,self.limit))
Thank you so much

Related

How to sum a list of sets? with strings and integers in a class?

I'm new to programming with python and I'm working on the python 4 everybody course. For that I need to build a budget app. In specific, this is the first two tasks:
Complete the Category class in budget.py. It should be able to instantiate objects based on different budget categories like food, clothing, and entertainment. When objects are created, they are passed in the name of the category. The class should have an instance variable called ledger that is a list. The class should also contain the following methods:
A deposit method that accepts an amount and description. If no description is given, it should default to an empty string. The method should append an object to the ledger list in the form of {"amount": amount, "description": description}.
A withdraw method that is similar to the deposit method, but the amount passed in should be stored in the ledger as a negative number. If there are not enough funds, nothing should be added to the ledger. This method should return True if the withdrawal took place, and False otherwise.
My attempt for now is the following:
class Category:
def __init__(self):
self.ledger = []
Total = 0
def deposit(self, amount, *description):
self.ledger.append({"amount": amount, "description": description})
return self.ledger
def withdraw(self, withdrawal):
for x in self.ledger:
if x == int():
return sum
self.ledger.append({"withdrawal": withdrawal})
return self.ledger
I think I have multiple questions:
What is a list with {} as one Item? Is it a 5.4. "Set"?
How can I now implement the requirement of the withdraw method "If there are not enough funds, nothing should be added to the ledger." I think I need to sum up all the integers of the list self.ledger, but idk how to grab those from it and sum it up. I tried as you can see a for loop, but I think that is incorrect syntax?
I really appreciate every help and am grateful for also some background knowledge!
Thanks in advance!
Lukas
{} is en empty dict. An empty set is set()
This should do for the withdraw function :
def withdraw(self, amount, description):
balance = sum(transaction["amount"] for transaction in self.ledger)
if balance >= withdrawal :
self.ledger.append({"amount": -amount, "description": description})
return True
else :
return False
return self.ledger
This use a generator as an argument for the builtin sum function. This may be a bit advanced if you are just starting python so you can also compute the balance with more beginner friendly code :
balance = 0
for transaction in ledger:
balance = balance + transaction["amount"]
# you can shorten the line above to
# balance += transaction["amount"]
This is roughly equivalent to what the sum and the generator syntax do.
Out of curiosity, is the * in front of description argument in your deposit function a typo ?
So, some things for clarification.
self.ledger = []: The [] makes the ledger a list, and the self. part makes it an instance variable, only applicable to a specific instance of the class Category
As stated in the comments, {"key": "value"} is a dict object. Using self.ledger.append({"key": "value"}) adds the dict object {"key": "value"} to the ledger list.
Normally if you want to keep track of a number inside a class, you create an instance variable and update it when it gets changed. See the usage of self.total below.
Recalculating the total can also be done, see the method update_total() below.
I added some testing below.
class Category:
def __init__(self):
self.ledger = []
# total also needs the "self." to make it an instance variable, just
# as the ledger above
# if you omit the "self."" it's a localized variable only available
# to the __init__ method itself.
self.total = 0
def deposit(self, amount, *description):
self.ledger.append({"amount": amount, "description": description})
# add the amount to the total
self.total += amount
return self.ledger
def withdraw(self, withdrawal):
# make the withdrawal negative
if abs(withdrawal) == withdrawal:
withdrawal = 0 - withdrawal
# check if there's enough in the total
if abs(withdrawal) <= self.total:
# update the total
self.total += withdrawal
# add to the ledger
self.ledger.append({"withdrawal": withdrawal})
else:
# you could return an error message here
pass
return self.ledger
def update_total(self):
total = 0
for item in self.ledger:
# need to check if the amount key is in the dict object
if "amount" in item:
total += item["amount"]
# this check below is not needed but it ensures future compatability
elif "withdrawal" in item:
total += item["withdrawal"]
# just because, you can check if the totals match
if self.total != total:
print(
f"""Difference in totals found. Someone is cheating :-|
Instance total: {self.total}
Calculated total: {total}"""
)
# set the instance variable to the local variable
self.total = total
return self.total
from pprint import pprint
nr1 = Category()
nr2 = Category()
for i in range(10):
nr1.deposit(i, f"deposit - {i}")
pprint(nr1.ledger)
print(f"Total: {nr1.total}")
nr1.withdraw(10)
print(f"Total: {nr1.total}")
nr1.withdraw(-10)
print(f"Total: {nr1.total}")
nr1.withdraw(99999)
print(f"Total: {nr1.total}")
pprint(nr1.ledger)
print(nr1.update_total())
nr1.total = 123
print(nr1.update_total())
# just to show that the above only updated the values inside the nr1 instance.
print(f"Total for nr2: {nr2.total}")

Cannot append objects to a list

I'm having some troubles with my code. This is a budget app in which you can add categories and for every category you can deposit/withdraw money. The problem is that I have to save all the transactions in the format {"amount": x, "description":y} and to do this I create an object of class Amount which is defined in the code, but when I try to append the new Amount object to the list every single element of this list changes to the last object. I understood that when I add an object, all the other elements in the list refer to the same object, and that's probably the problem, but I cannot solve this. Can you help me? Thank you very much
(This bug happens in the methods deposit and withdraw)
class Amount:
tot={"amount":0,"description":""}
def __init__(self,am,descr=""):
self.tot["amount"]=am
self.tot["description"]=descr
def getTot(self):
return self.tot
class Category:
title=""
deposit_list=list()
balance=0
def __init__(self,name):
self.title=name
def __str__(self):
final_string=""
length=int((30-len(self.title))/2)
for i in range(0,length):
final_string+="*"
final_string+=self.title
for i in range(0,length):
final_string+="*"
final_string+="\n"
for x in self.deposit_list:
y=x.getTot()["description"]
y=y[0:23]
z=float(x.getTot()["amount"])
final_string+=y
l=len(y)
if l<23:
for i in range(l,23):
final_string+=" "
z=str(z)
l=len(z)
if l<7:
for i in range(l,7):
final_string+=" "
final_string+=z
final_string+="\n"
final_string+="Total: "
final_string+=str(self.balance)
return final_string
def get_balance(self):
return self.balance
def getTitle(self):
return self.title
def deposit(self,amount,description=""):
if description!="":
description=str(description)
dep=Amount(amount,description)
self.deposit_list.append(dep)
self.balance+=dep.getTot()["amount"]
def withdraw(self,amount,description=""):
if description!="":
description=str(description)
wd=Amount(-1*amount,description)
if self.check_funds(amount):
self.deposit_list.append(wd)
self.balance+=wd.getTot()["amount"]
return True
else:
return False
def transfer(self,amount,dest):
descr_dest="Transfer from "
descr_dest+=self.getTitle()
descr_src="Transfer to "
descr_src+=dest.getTitle()
if self.withdraw(amount,descr_src)==True:
dest.deposit(amount,descr_dest)
return True
else:
return False
def check_funds(self,amount):
if amount>self.balance:
return False
else:
return True
def create_spend_chart(categories):
return
Edit:
I'm sorry, here is a test you can run
import budget
from unittest import main
food = budget.Category("Food")
food.deposit(1000, "initial deposit")
food.withdraw(10.15, "groceries")
food.withdraw(15.89, "restaurant and more food for dessert")
clothing = budget.Category("Clothing")
food.transfer(50, clothing)
print(food)
It should print this:
*************Food*************
initial deposit 1000.00
groceries -10.15
restaurant and more foo -15.89
Transfer to Clothing -50.00
Total: 923.96
I also have to say that it should print only the first 23 characters of the description, but this shouldn't be important for the question.
#frno that was an attempt to avoid the problem described in the question, I edited the code as it was before that update
Thank you!

Why is this "no string attribute" error occurring when attempting to update account_type

I am trying to add a method to update my acct_type, but I keep getting an error when trying to print out the new account.
class BankAccount(object):
def __init__(self, acct_holder, acct_type, balance = 0):
self.holder = acct_holder
self.type = acct_type
self.balance = balance
"""
Write a constructor for a bank account below.
The following attributes:
acct_holder will be a Person object
acct_type is a string
balance should be defaulted to 0 if not provided to the constructor, is an int
"""
pass
def changeAccountType(self, newType):
self.type = str(self.newType)
def __str__(self):
return str(self.holder) + self.type + str(self.balance)
account_1 = BankAccount('James','checking',45)
account_1.type.changeAccountType("dookieball_account")
print(account_1)
From your code above, I removed the ".type" from "account_1.type.changeAccountType..." and also removed "self." from "self.newType" in your changeaccount function. newType is not contained in self. Hope this help, it's my first attempt on here!
account_1.type.changeAccountType("dookieball_account")
needs to be
account_1.changeAccountType("dookieball_account")
When you use .type, you are getting the type of account_1, which is a string, and trying to call the changeAccountType function on it. Removing it instead calls the function on account_1.
Also, change
self.type = str(self.newType)
to
self.type = str(newType)
Because the newType is a parameter of that function, it is not yet under self.

Errors in minor details in a class output

I have two files :
class Account:
def __init__(self,id=0,balance=100.0,AIR=0.0):
self.__id = id
self.__balance = balance
self.__AIR = AIR
def getd(self):
return self.__id
def getbalance(self):
return self.__balance
def getAnnualInterest(self):
return self.__AIR
def setid(self,newid):
self.__id = newid
def setbalance(self,newbalance):
self.__balance = newbalance
def setAnnualInterestRate(self,newrate):
self.__AIR = newrate
def getMonthlyInterestRate(self):
return self.__AIR/12
def getMonthlyInterest(self):
return self.__balance*self.getMonthlyInterestRate()
def withdraw(self,amount):
if amount<=self.__balance:
self.__balance -= amount
def deposit(self,amount):
self.__balance += amount
def __str__(self):
return "Account ID : {0.setid} Account Balance : {0.setbalance} Annual Interest Rate : {0.setAnnualInterestRate}".format(self)
and Test:
from Account import Account
def main():
accountA = Account(0,100,0)
accountA.setid = 1234
accountA.setbalance = 20500
accountA.setAnnualInterestRate = 0.375
print(accountA)
accountA.withdraw(500)
accountA.deposit(1500)
print(accountA)
print(accountA.getMonthlyInterest())
main()
My output is mostly correct but there are two minor deatils which I have gotten wrong and I am not sure where in the code the problem is from.
Account ID : 1234 Account Balance : 20500 Annual Interest Rate : 0.375
Account ID : 1234 Account Balance : 20500(This is supposed to be 21500) Annual Interest Rate : 0.375
0.0(And this is supposed to be 671.875 but somehow I got it wrong)
accountA.setbalance = 20500 doesn't call the setbalance method. It changes the value of the setbalance attribute to 20500 (that is, after this line, accountA.setbalance is no longer a method but an int). Instead, you want accountA.setbalance(20500).
However, what you're doing is profoundly un-pythonic in the first place (you're a Java/C#/C++ programmer, aren't you?). Getters and setters are an anti-pattern in Python: just access and change the id, balance et al. attributes, and make them properties if (and only if) you need to perform computations/checks when setting/accessing them.
In addition, __attribute is not a private attribute in Python. The pythonic way to mark an attribute as "private" is a single leading underscore. However, it's just a convention, and the attribute itself will still be public (everything always is in Python -- it has no concept of visibility modifiers).
This:
accountA.setid = 1234
accountA.setbalance = 20500
accountA.setAnnualInterestRate = 0.375
doesn't call the functions. You actually change functions into variables this way. To call the functions use this notation:
accountA.setid(1234)
accountA.setbalance(20500)
accountA.setAnnualInterestRate(0.375)

An exercise from fundamentals of python [duplicate]

This question already exists:
Closed 11 years ago.
Possible Duplicate:
Fundamentals of Python Chapter 8 project 3
Hi I am a newbie programmer who just started to learn about python.
I have recently posted this same question before and I have solved it but my answer is not exactly what the question is asking.
I need help on why I need to implement a new method even though I could do the other way.
thanks
Question:
The __str__ method of the Bank class returns a string containing the
accounts in random order. Design and implement a change that causes
the accounts to be placed in the string by order of name.
[this is the part where I don't understand]
(Hint: You will also have to define a new method in the SavingsAccount class.)
class Bank(object):
def __init__(self):
self._accounts = {}
def __str__(self):
"""Return the string rep of the entire bank."""
pTemp =[]
for i in xrange(len(SavingsAccount.temp)-1):
if self._accounts.get(SavingsAccount.temp[i]).getName() >= self._accounts.get(SavingsAccount.temp[i+1]).getName():
temp = SavingsAccount.temp[i]
SavingsAccount.temp[i] = SavingsAccount.temp[i+1]
SavingsAccount.temp[i+1] = temp
for i in SavingsAccount.temp:
pTemp.append(self._accounts[i])
return '\n'.join(map(str, pTemp))
def add(self, account):
"""Inserts an account using its PIN as a key."""
self._accounts[account.getPin()] = account
def remove(self, pin):
return self._accounts.pop(pin, None)
def get(self, pin):
return self._accounts.get(pin, None)
def computeInterest(self):
"""Computes interest for each account and
returns the total."""
total = 0.0
for account in self._accounts.values():
total += account.computeInterest()
return total
class SavingsAccount(object):
"""This class represents a Savings account
with the owner's name, PIN, and balance."""
RATE = 0.02
temp = []
def __init__(self, name, pin, balance = 0.0):
self._name = name
self._pin = pin
self._balance = balance
SavingsAccount.temp.append(self)
def __str__(self):
result = 'Name: ' + self._name + '\n'
result += 'PIN: ' + self._pin + '\n'
result += 'Balance: ' + str(self._balance)
return result
def getBalance(self):
return self._balance
def getName(self):
return self._name
def getPin(self):
return self._pin
def deposit(self, amount):
"""Deposits the given amount and returns the
new balance."""
self._balance += amount
return self._balance
def withdraw(self, amount):
"""Withdraws the given amount.
Returns None if successful, or an
error message if unsuccessful."""
if amount < 0:
return 'Amount must be >= 0'
elif self._balance < amount:
return 'Insufficient funds'
else:
self._balance -= amount
return None
def computeInterest(self):
"""Computes, deposits, and returns the interest."""
interest = self._balance * SavingsAccount.RATE
self.deposit(interest)
def main():
bank = Bank()
bank.add(SavingsAccount("Zelda","1003",5000.00))
bank.add(SavingsAccount("Wilma","1001",4000.00))
bank.add(SavingsAccount("Fred","1002",1000.00))
print bank
main()
I think the question expects you to define ordering in the SavingsAccount class, that is, be able to determine whether an instance of SavingAccounts comes after or before another instance of SavingAccount. I don't want to write any spoiler here, but tell me if my hint is not enough ;).
UPDATE
Also, a common source of errors in Python with string ordering : a comes before z which comes before A which comes before Z ...
UPDATE2
more hints ;)
What you really want here is to sort a list of instances of SavingAccount according to a given criteria. There are 2 way to do this kind of thing. You can either :
have the one doing the sorting take care of it
or you can have the instances stored in your list taking care of it.
The second option is usually better because "the class to be sorted" should know better than anybody else how to sort itself (it's about encapsulation : not letting people outside control how your class works). Even though the question is not really clear, and the example is not very good (in my opinion), this is the option they would like you to chose.
The idea is that the Bank should just do something like this :
class Bank(object):
def __str__(self):
"""Return the string rep of the entire bank."""
#get a sorted copy of the list
#using default SavingAccount comparison
pTemp =sorted(self._accounts)
return '\n'.join(map(str, pTemp))
And SavingAccount contains information about how to sort.
You may want to have a look at this article from the PythonInfo Wiki.
Also: http://docs.python.org/reference/datamodel.html#object.__lt__

Categories