Python Class and encapsulation methods - python

I'm new to OOP and this is my first shot at creating a Python class. I am trying to make my 3 variables private and so that only the methods update the info (enforce encapsulation). It seems that if I remove the setters and getters methods from my class, it has no impact on my code (must be the initializer method doing the work?). What can I do to improve this? Thanks.
Edit- i've updated my code and removed the init. My getters are not working now.
#Instantiate a new Pet Instance.
myPet = Pet()
#Get input from user.
myPet.setName = input("Enter the pet's name: ")
myPet.setTypes = input("Enter the pet's type (Dog, Cat, Bird, etc.): ")
myPet.setAge = input("Enter the pet's age (in years): ")
while myPet.setAge.isalpha():
print()
print("Age cannot contain numbers. Try again.")
myPet.setAge = input("Enter the pet's age (in years): ")
#Call the showPetInfo module using new instanced object.
myPet.showPetInfo()
class Pet:
#Fields of the Pet Class.
__PetName = ""
__PetType = ""
__PetAge = ""
#Setter methods.
def setName(self,name):
self.__PetName = name
def setTypes(self,types):
self.__PetType = types
def setAge(self,age):
self.__PetAge = age
#Getter methods.
#property
def getName(self):
return self.__PetName
#property
def getType(self):
return self.__PetType
#property
def getAge(self):
return self.__PetAge
def showPetInfo(self):
print("\n \n \n \n")
print("Here is your pet's information. Your pet's name is {}, it is a {} and it is {} years old.".format(self.getName,self.getType,self.getAge))
main()

you are unfortunately right, they use to say setters/getters are contracts doing restriction for adults... (if I tell you "dont touch it" then you shoulntd touch it) but there is nothing restricting you and you can modify them!
same "feature" can be observed with "constants"... do in the jupyther or the terminal this
import math
math.pi = 1
a = math.pi
a
math.pi
and you will see that you now modified the constant pi value to 1
many sugest to usse properties but that is not a capsulation at all, that is just sugar syntax for the same "adults contract" IMHO :)
so to your question
What can I do to improve this?
document the code you are writing so the other part using it is aware about how the code, instances states in objects must be handled

Related

Problems with Python OOP

I decided to study python's OOP on my own. In the "car" class, I create the "carHP" function, then I want to write the result of this function to the "power" variable, but the compiler throws an error. What could be the problem? I wrote it without class, everything works, but then the meaning of OOP is lost
class car():
nameCar=""
def carHP(self):
if self.nameCar=="BMW":
HP=666
return HP
power=carHP()
def infoCar(self):
print("You owner: ", self.nameCar)
print("HP car: ", self.power )
class person():
namePerson=""
def infoPerson(self):
print("Ваше имя: ",self.namePerson)
person1=person()
person1.namePerson=input("Enter your name: ")
car1=car()
car1.nameCar=input("Enter car name: ")
person1.infoPerson()
car1.infoCar()
you need to know the basics of python oop because you are using class variable instead of instance variables, do your research about the difference of both and simplify the logic
here is a better way for you to start
class Car:
def __init__(self, car_name, car_hp=100):
self.car_name = car_name
self.car_hp = car_hp
class Person:
def __init__(self, person_name):
self.person_name = person_name
def person_info(self):
print(f"Person Name: {self.person_name}")
I found some things to work on my end with a few tweaks on your code. Check them out...
I noticed how you have not called the function carHP() which may be important at initializing HP car: to 666
person1=person()
person1.namePerson=input("Enter your name: ")
car1=car()
car1.nameCar=input("Enter car name: ")
person1.infoPerson()
car1.infoCar()
Secondly, inheritance inside a class method do not receive instances automatically. They require the self. parameter to receive the contents of the method it came from. otherwise, you are returning an instance of that variable but without its parent method
I apologies if that does not make sense. But please have a look at https://docs.python.org/3/tutorial/classes.html for more information.
With the self parameter added and function called to be a conditional statement we get the following output...
class car:
nameCar = ""
power = None
def carHP(self):
if self.nameCar == "BMW":
HP = 666
self.power = HP # notice this change
def infoCar(self):
print("You owner: ", self.nameCar)
print("HP car: ", self.power)
class person():
namePerson = ""
def infoPerson(self):
print("Ваше имя: ", self.namePerson)
person1 = person()
person1.namePerson = input(str("Enter your name: "))
car1 = car()
car1.nameCar = input(str("Enter car name: "))
car1.carHP() # notice this change
person1.infoPerson()
car1.infoCar()
Output:
Enter your name: Name
Enter car name: BMW
Ваше имя: Name
You owner: BMW
HP car: 666
Process finished with exit code 0

taking input from user to decide which object will be used in python class

i am new here and i am trying to learn python. i want to create a simple atm program but i also want to try something that i haven't seen yet. i want to take input from user and select one of objects of a class regard to this selection, here is the part of my code
class bankaccount():
def __init__(self,name,money):
self.name=name
self.money=money
def show(self):
print(self.name,self.money)
johnaccount=bankaccount("john",500)
mikeaccount=bankaccount("mike",1000)
sarahaccount=bankaccount("sarah",1500)
selection= input("please write the name: ")
for example i will write john and program should run johnaccount.show is this possible? could you please help about this issue.
Below
class bankaccount():
def __init__(self,name,money):
self.name=name
self.money=money
def show(self):
print(self.name,self.money)
# build the accounts 'DB' (which is just a dict)
# read more here: https://cmdlinetips.com/2018/01/5-examples-using-dict-comprehension/
accounts = {name: bankaccount(name,balance) for name,balance in [("john",500),("mike",1000)]}
user = input("please write the name: ")
account = accounts.get(user)
if account:
account.show()
else:
print(f'no account for {user}')
There is a "hacky" way to do that (see below). Usually you'd rather have a dictionary or list containing all of the accounts and then get the account from there.
For example:
accounts = {
'john': bankaccount("john",500),
'mike': bankaccount("mike",1000)
}
selection = input("please write the name: ")
if selection in accounts:
print(f"Balance: {accounts[selection].show()}")
else:
print("Account not found")
The "hacky" way is to use Python's built-in locals function:
johnaccount=bankaccount("john",500)
mikeaccount=bankaccount("mike",1000)
sarahaccount=bankaccount("sarah",1500)
selection = input("please write the name: ")
account_name = f"{selection}account"
if account_name in locals():
print(f"Balance: {locals()[account_name].show()}")
else:
print("Account not found")
The f"Balance: {accounts[selection].show()}" syntax that I'm using is called f-strings, or formatted string literals.
PS. it's common practice to use CamelCase for class names, e.g. BankAccount, and to use lowercase and underscores for variable names, e.g. john_account.

Python error: object has no attribute

I'm new to coding -- taking a Python college course. I know this will be obvious to many of you, but I can not figure out why I continue to get this error attribute error:
prodworker = employee.ProductionWorker(shift_num, pay_rate)
AttributeError: 'Employee' object has no attribute 'ProductionWorker'
Any help is greatly appreciated :)
class Employee: #writing new class called Employee:
def __init__(self, name, number): #accepts arguments for employee name and
self.__name = name #employee number
self.__number = number
def set_name(self, name): #mutator methods to set name and number
self.__name = name
def set_number(self, number):
self.__number = number
#accessor methods returns name and number
def get_name(self):
return self.__name
def get_number(self):
return self.__number
class ProductionWorker(Employee): #write subclass
def __init__(self, shift_num, pay_rate):
Employee.__init__(self, 'ProductionWorker')
self.__shift_num = shift_num
self.__pay_rate = pay_rate
def set_shift_num(self, shift_num):
self.__shift_num = shift_num
def set_pay_rate(self, pay_rate):
self.__pay_rate = pay_rate
def get_shift_num(self):
return self.__shift_num
def get_pay_rate(self):
return self.__pay_rate
#This program creates an instance of Employee Class
#and an instance of Production Worker Class:
again = 'Y'
while again.upper() == 'Y':
print('Enter the following data for the employee: \n')
name = input('What is the employee name?: ')
number = input('What is the employee number? ')
shift_num = input('What is the employee shift number? 1 = Day, 2 = Night :')
while shift_num != '1' and shift_num != '2':
shift_num = input('Invalid entry! Enter 1 for Day shift or 2 for Night shift!')
else:
if shift_num == '1':
shift_num = 'Day'
if shift_num == '2':
shift_num = 'Night'
pay_rate = float(input('What is the employee pay rate? '))
print()
print('This is an instance of the Employee class:')
employee = Employee(name, number)
print('EMPLOYEE: \t\t'+ employee.get_name())
print('EMPLOYEE NUMBER: \t' + employee.get_number())
print()
print('This is an instance of the Production Worker class: ')
prodworker = employee.ProductionWorker(shift_num, pay_rate)
print('SHIFT: \t\t\t' + ProductionWorker.get_shift_num())
print('PAY RATE: \t\t$' + format(ProductionWorker.get_pay_rate(), ',.2f'), sep='')
print('--------------------------------------------')
again = input('Enter Y to add another: ')
if again.upper() != 'Y':
print('Program End')
The ProductionWorker class is a subclass of the Employee class, but that doesn't mean you can call it through an instance of Employee. It's still a top-level class that you should call directly. Try replacing employee.ProductionWorker(...) with just ProductionWorker(...).
You'll get past the current error, but you may have new ones. For instance, I think the current attempt to call Employee.__init__ from ProductionWorker.__init__ will fail because it doesn't pass the right number of arguments. You may also have logic issues, if you expected employee.ProductionWorker to create a ProductionWorker instance that was related in some way to the employee object.
I'd also discourage you from using __double_leading_underscore names for your attributes. That invokes Python's name mangling system, which is mostly intended to help prevent accidental reuse of the same name from different classes in a large or unpredictable inheritance hierarchy. If you just want your attributes to be "private", use a single underscore. That doesn't protect them from being accessed by outside code, but it serves as documentation that they're not part of the object's public API. One of Python's design philosophies is that it's programmers are responsible for their own behavior (often described with the phrase "We're all consenting adults"). If a programmer wants to access an object's private data they can do so (which can be very useful for debugging). But if they break stuff, they have no one to blame but themselves.

Homework Help - Object-Oriented Programming

In my intro class, we just started the section on object-oriented programming. This class is the first I've ever been exposed to programming, and I'm really not understanding it.
We have an assignment where we have to create an Animal class, a Zoo class, and then a zookeeper program to run the information from the first two classes. I have the programs typed up based off of examples in my book, but am still not doing it correctly.
If you could look over my codes and give me some feedback or help, that would be greatly appreciated!
class Animal:
def __innit__(self, animal_type, name):
self.animal_type = animal_type
self.name = name
def get_animal_type(self, animal_type):
self.__animal_type = animal_type
def get_name(self, name):
self.__name = name
def check_mood(self, mood):
input random.txt
print random.random()
Class Zoo:
def __innit__(self):
self.__animals = animal_list
def add_animals(self, animal):
self.__animals.append(animal)
def show_animals(animal_list):
return animal_list
input Animal.py
input Zoo.py
def main():
ADD_ANIMAL = 1
SHOW_ANIMALS = 2
EXIT = 3
def get_manu_choice():
print()
print("Zoo Options")
print("-----------")
print("1. Add Animal")
print("2. Show Animals")
print("3. Exit")
print()
choice = int(input("What would you like to do? "))
while choice < ADD_ANIMAL or choice > EXIT:
choice = int(input("Please choose a valid option: "))
return choice
main()
innit should be init
Looks to me like you are missing a chunk of functionality. You need an instance of zoo, and then in response to the input, either add another animal to the zoo or print the list of animals.

Python input Job Code

I'm Code doesn't seem to work, I am trying to get input of a job, category, and salary, and store the input
class Jobs:
def GetJob(self):
name = raw_input('Enter a Job Title: ')
category = raw_input('Enter what Category that Job is: ')
salary = raw_input('Enter the salary of that Job: ')
print name,category, salary
def __init__(self,name,category,salary):
self.name = Jobs.GetJob(name)
self.category = Jobs.GetJob(category)
self.salary = Jobs.GetJob(salary)
GetJob = Jobs()
print GetJob
Your code is totally out of good OOP practices, and the first part eandersson's answer too…
A class has for role to store values, get/set them and return (or apply) transformations to its encapsulated values. What you tried to achieve is totally nonsense: you're calling the GetJob method of the Jobs class inside another method. It could work if you would have written:
def __init__(self,name…):
self.name = Jobs.GetJob(self, name)
…
But that would be a wrong way to design your program. You'd better stick your class to hold your values and making it good at that, and make another function that helps populate your class:
class Jobs:
def __init__(self, name, category, salary):
self.name = name
self.category = category
self.salary = salary
def __repr__(self):
return "Jobs<%s,%s,%s>" % (self.name, self.category, self.salary)
def GetJob():
name = raw_input('Enter a Job Title: ')
category = raw_input('Enter what Category that Job is: ')
salary = raw_input('Enter the salary of that Job: ')
return Jobs(name, category, salary)
print GetJob()
I do not agree with eandersson's approach because it deceives the purpose of the constructor, by directly calling the GetJob method. Then GetJob is not useful. And one would want to be able to use the Job class without always having the raw inputs at construction. EDIT: valid only as a comment on the first part of his answer.
And finally, I think that you really misunderstands a lot about programming. You should better read thoroughly a python course like the ones on http://wiki.python.org/moin/BeginnersGuide/NonProgrammers, because there's really a lot of concepts you ignored to be able to write something like that.
go have a look at:
http://hetland.org/writing/instant-hacking.html
http://www.learnpython.org/
http://cscircles.cemc.uwaterloo.ca/
http://learnpythonthehardway.org/book/

Categories