← Computer Programming II

Problem 1 (Easy): Temperature Reading

A weather station records temperatures but must ensure no reading goes below absolute zero (−273.15°C). Create a TemperatureReading class that stores a location and a temperature, using a property to validate the temperature.

  1. Define a class TemperatureReading with __init__ that accepts location (public) and temperature.
  2. Store temperature in a protected attribute _temperature.
  3. Create a @property getter for temperature that returns _temperature.
  4. Create a @temperature.setter that raises a ValueError with the message "Temperature cannot be below absolute zero" if the value is less than -273.15. Otherwise, store it.
  5. Use self.temperature = temperature in __init__ so the setter validates the initial value too.

Input

r1 = TemperatureReading("Tashkent", 35.0)
print(r1.location)
print(r1.temperature)

r1.temperature = -10.5
print(r1.temperature)

try:
    r1.temperature = -300
except ValueError as e:
    print(e)

Expected Output

Tashkent
35.0
-10.5
Temperature cannot be below absolute zero

Problem 2 (Easy+): Movie Rating

A movie review site needs to store movie information and control how ratings are assigned. Create a Movie class that validates its rating and provides a read-only property for the title.

  1. Define a class Movie with __init__ that accepts title and rating.
  2. Store title in a protected attribute _title and expose it as a read-only property (getter only, no setter).
  3. Create a @property getter for rating that returns _rating.
  4. Create a @rating.setter that raises a ValueError with "Rating must be between 1 and 10" if the value is less than 1 or greater than 10. Otherwise, store it.
  5. Use self.rating = rating in __init__ so the setter validates the initial value.
  6. Define a method display() that prints: <title> - <rating>/10

Input

m = Movie("Inception", 9)
m.display()

m.rating = 7
m.display()

try:
    m.rating = 11
except ValueError as e:
    print(e)

try:
    m.title = "New Title"
except AttributeError:
    print("Cannot change title")

Expected Output

Inception - 9/10
Inception - 7/10
Rating must be between 1 and 10
Cannot change title

Problem 3 (Medium): Product Inventory

An online store needs a Product class to manage items in its catalog. Each product has a name, a price, and a quantity in stock.

  1. The product’s name should not be changeable after creation.
  2. The price must always be a positive number.
  3. The quantity cannot be negative.
  4. A method restock(amount) adds the given amount to the current quantity. The amount must be positive.
  5. A method sell(amount) reduces the quantity by the given amount. The amount must be positive and cannot exceed the current quantity.
  6. A method total_value() returns the product’s price multiplied by its quantity.

Input

p = Product("Laptop", 999.99, 10)
print(p.name)
print(p.price)
print(p.quantity)
print(p.total_value())

p.price = 899.99
p.restock(5)
print(p.quantity)
print(p.total_value())

p.sell(3)
print(p.quantity)

try:
    p.price = -50
except ValueError as e:
    print(e)

try:
    p.sell(100)
except ValueError as e:
    print(e)

try:
    p.name = "Tablet"
except AttributeError:
    print("Cannot change product name")

Expected Output

Laptop
999.99
10
9999.9
899.99
15
13499.85
12
Price must be positive
Insufficient stock
Cannot change product name

Problem 4 (Medium+): User Account

A platform needs a UserAccount class to manage user credentials securely.

  1. Each account has a username, an email, and a password.
  2. The username should not be changeable after creation.
  3. The email must contain exactly one "@" symbol. Invalid emails should raise ValueError with "Invalid email address".
  4. The password must be stored as a private attribute (using name mangling). It should not be readable or writable through a property.
  5. A method change_password(old_password, new_password) updates the password only if old_password matches the current one. If it doesn’t match, raise ValueError with "Incorrect password". The new password must be at least 6 characters long — otherwise raise ValueError with "Password must be at least 6 characters".
  6. A method login(password) returns True if the password matches, False otherwise.
  7. A method display_info() returns a string in the format: <username> (<email>)

Input

u = UserAccount("alisher", "alisher@mail.com", "secret123")
print(u.username)
print(u.email)
print(u.display_info())

print(u.login("wrong"))
print(u.login("secret123"))

u.email = "new@email.com"
print(u.display_info())

u.change_password("secret123", "newpass456")
print(u.login("secret123"))
print(u.login("newpass456"))

try:
    u.change_password("wrong", "abc123")
except ValueError as e:
    print(e)

try:
    u.change_password("newpass456", "short")
except ValueError as e:
    print(e)

try:
    u.email = "invalid-email"
except ValueError as e:
    print(e)

try:
    u.username = "hacker"
except AttributeError:
    print("Cannot change username")

try:
    print(u.__password)
except AttributeError:
    print("Cannot access private password")

Expected Output

alisher
alisher@mail.com
alisher (alisher@mail.com)
False
True
alisher (new@email.com)
False
True
Incorrect password
Password must be at least 6 characters
Invalid email address
Cannot change username
Cannot access private password

Problem 5 (Advanced): Shopping Cart

An e-commerce platform needs a ShoppingCart class to manage a customer’s selected items, calculate totals, and handle discount codes.

  1. Each cart is created with a customer_name and a discount_code. The customer name should not be changeable after creation. The discount code must be stored as a private attribute (name mangling) — it should not be accessible from outside the class.
  2. Items are stored internally. Each item has a name, a unit price, and a quantity.
  3. A method add_item(name, price, quantity) adds an item to the cart. Price must be positive and quantity must be a positive integer. If an item with the same name already exists, only its quantity should increase (the price stays the same).
  4. A method remove_item(name) removes an item entirely. Raise ValueError with "Item not found" if the item doesn’t exist.
  5. A read-only property item_count returns the total number of individual items (sum of all quantities).
  6. A read-only property subtotal returns the sum of price × quantity for all items, rounded to 2 decimal places.
  7. A method apply_discount(code) checks the code against the stored private discount code. If it matches, a 10% discount is activated. If the code is wrong, raise ValueError with "Invalid discount code". If a discount has already been applied, raise ValueError with "Discount already applied".
  8. A read-only property total returns the subtotal with the discount applied (if any), rounded to 2 decimal places.
  9. A method summary() returns a string: <customer_name>: <item_count> items, total: $<total>
  10. Add type hints to all method parameters and return types. Add a docstring to the class.

Input

cart = ShoppingCart("Nodira", "SAVE10")

cart.add_item("Notebook", 12.99, 3)
cart.add_item("Pen", 1.50, 10)
cart.add_item("Notebook", 12.99, 2)

print(cart.customer_name)
print(cart.item_count)
print(cart.subtotal)
print(cart.total)
print(cart.summary())

cart.apply_discount("SAVE10")
print(cart.total)
print(cart.summary())

cart.remove_item("Pen")
print(cart.item_count)
print(cart.total)

try:
    cart.add_item("Eraser", -5, 1)
except ValueError as e:
    print(e)

try:
    cart.remove_item("Marker")
except ValueError as e:
    print(e)

try:
    cart.apply_discount("SAVE10")
except ValueError as e:
    print(e)

try:
    cart.apply_discount("WRONG")
except ValueError as e:
    print(e)

try:
    cart.customer_name = "Someone"
except AttributeError:
    print("Cannot change customer name")

try:
    print(cart.__discount_code)
except AttributeError:
    print("Cannot access private discount code")

Expected Output

Nodira
15
79.95
79.95
Nodira: 15 items, total: $79.95
71.95
Nodira: 15 items, total: $71.95
5
58.46 (or 58.45)
Price must be positive
Item not found
Discount already applied
Discount already applied
Cannot change customer name
Cannot access private discount code

Problem 6 (Advanced): Bank Account

A banking application needs a BankAccount class to manage customer funds with transaction logging and PIN-based security.

  1. Each account is created with an owner name, an initial balance, and a pin (a string). The owner should not be changeable after creation. The pin must be stored as a private attribute (name mangling) — it should not be accessible from outside the class.
  2. The balance must be exposed as a read-only property. It should not be settable directly. The balance must never be negative — if an invalid initial balance is given, raise ValueError with "Balance cannot be negative".
  3. Every successful deposit or withdrawal is recorded internally as a transaction tuple: (type, amount, resulting_balance) where type is "deposit" or "withdrawal". The transaction list should not be accessible from outside.
  4. A method deposit(amount, pin) adds money to the account. The pin must match — otherwise raise ValueError with "Invalid PIN". The amount must be positive — otherwise raise ValueError with "Amount must be positive".
  5. A method withdraw(amount, pin) removes money. Same validations as deposit, plus if the amount exceeds the balance, raise ValueError with "Insufficient funds".
  6. A read-only computed property transaction_count returns the total number of transactions recorded.
  7. A method get_statement(pin) verifies the pin and returns a multi-line string listing all transactions, one per line in the format: <type>: $<amount> | Balance: $<resulting_balance>. If no transactions exist, return "No transactions yet".
  8. A method transfer(amount, pin, other_account) withdraws from this account and deposits into the other account. The pin is only required for this account (deposit into the other account does not require the other account’s pin — call the internal logic directly). If the withdrawal fails, the deposit should not happen.
  9. Add type hints to all method parameters and return types. Add a docstring to the class.

Input

a1 = BankAccount("Dilnoza", 1000.0, "1234")
a2 = BankAccount("Jasur", 500.0, "5678")

print(a1.owner)
print(a1.balance)
print(a1.transaction_count)

a1.deposit(250.0, "1234")
print(a1.balance)
print(a1.transaction_count)

a1.withdraw(100.0, "1234")
print(a1.balance)

print(a1.get_statement("1234"))

a1.transfer(200.0, "1234", a2)
print(a1.balance)
print(a2.balance)
print(a1.transaction_count)
print(a2.transaction_count)

try:
    a1.deposit(50.0, "wrong")
except ValueError as e:
    print(e)

try:
    a1.withdraw(5000.0, "1234")
except ValueError as e:
    print(e)

try:
    a1.withdraw(-10.0, "1234")
except ValueError as e:
    print(e)

try:
    a1.balance = 999999
except AttributeError:
    print("Cannot set balance directly")

try:
    a1.owner = "Hacker"
except AttributeError:
    print("Cannot change owner")

try:
    print(a1.__pin)
except AttributeError:
    print("Cannot access private PIN")

try:
    print(a1.get_statement("wrong"))
except ValueError as e:
    print(e)

Expected Output

Dilnoza
1000.0
0
1250.0
1
1150.0
deposit: $250.0 | Balance: $1250.0
withdrawal: $100.0 | Balance: $1150.0
950.0
700.0
3
1
Invalid PIN
Insufficient funds
Amount must be positive
Cannot set balance directly
Cannot change owner
Cannot access private PIN
Invalid PIN