Python coding best practices - python

Is it a good idea to handle all the arguments in the constructor? instead of handling them in the particular methods where the arguments are actually needed?
Method 1:
def __init__(self,name,rollno,dob,city,state,zip):
self.name=name
..
..
self.zip = zip
def address(self):
return self.city+self.state+self.zip
def unique_identifier(self):
return self.name+self.rollno
test.py
example = Example("Programming","941","1997-09-07","Nashville","TN","37311")
print(example.address())
print(example.unique_identifier())
Method 2:
Class Example:
def address(self,city,state,zip):
return self.city+self.state+self.zip
def unique_identifier(self,name,rollno):
return self.name+self.rollno
test.py
example = Example()
print(example.address("ab","cd","111")
print(example.unique_identifier("Programmer","123")
Any explanation/reasoning to help understand Which method is more preferable for best practices.

Either is fine, it just depends on if the data belongs to the object (method 1) or if the data comes from outside the object (method 2). It can also be a mix of both. A short example:
class Person:
# store data specific to the instance
def __init__(self, name, birthdate, hometown):
self.name = name
self.birthdate = birthdate
self.hometown = hometown
# here I only need data from the instance
def introduce(self):
print("Hello, I am", self.name,
", I come from", self.hometown,
" and was born on ", self.birthdate,
".")
# food shouldn't be part of the Person,
# so it is passed in as an argument
def order_food(self, food):
print("I am ", self.name,
" and would like some ", food, " please.")

Related

How can I make the OOP code print my classes objects name?

I've tried to make an OOP based program in python. I gave it an object to work with and tried to make it print the name, but its not working.
class human:
def __init__(self, name):
print("this is a human")
def name(self, name):
print("this is {}".format(bob.name))
bob = human("bob")
Anyone know what the problem could be?
Beyond the answers you already received (which solve your problem), I'd suggest not having a method that prints the name. Rather, you should have a __str___ dunder method that defines the object's behavior when an instance is printed.
class human:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
person = human("bob")
print(person)
'bob'
You can also define the object's behavior when the instance name is entered in the console, for instance just running the line
>>> person
You can do it with __repr__:
def __repr__(self):
return f'when entering the instance name in the console: {self.name}'
This will print:
when entering the instance name in the console: bob
This appears more pythonic to me than having a method that simply prints the name.
You're never storing the name on the instance, where would it get the name from? Your __init__ needs to do something along the lines of self.name = name
the name method and attribute are going to conflict, the latter will shadow (hide) the former, and it should look up whatever attribute its using on self
You never assigned the passed name to the object. Try:
class human:
def __init__(self, name):
print("this is a human")
self.name = name
def print_name(self):
print("this is {}".format(self.name))
bob = human("bob")
bob.print_name()
there are couple of things to update in the code:
bob is an instance which is not defined at human class
notice that init, name functions expect external param but you never use it in the function. (in self. = name)
in order to use it:
define a var in the class named 'name' and update you function to:
class human:
_name = ""
def __init__(self, name):
print("this is a human")
self._name = name
def name(self):
print("this is "+ self._name)
bob = human("bob")
bob.name()
bob = human("bob") only init function and you should call bob.name() in order to call the print-name function

How print call work on my newly created Python Class

I am trying to learn how classes work on Python and new to this, I have the following class defined as 'Animal':
class Animal(object):
def __init__(self, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance o f the class, when an instance
# is created.
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return "The", self.color, str(self), " is feeling", self.mood, "."
def colors(self, other):
return "The", str(self), "is", self.color, "and the", str(other), "is", other.color, "."
I then create an instance of the Animal object as follow:
hippo = Animal("large", "purple", 'amused')
Finally I call a method on my object as follow:
print(hippo.feeling())
My expectation is to get an output like below:
"The purple hippo is feeling amused."
But what I get in output if I print the same argument as above is:
('The', 'purple', '<__main__.Animal object at 0x7f43cc978160>', ' is feeling', 'amused', '.')
Can someone explain please why the output is similar to a list? also why str(self) returned the object name rather than the word hippo.
The original code in the tutorial was written in Python 3.5, I thought that may have caused it, but I tried the online IDE on https://www.jdoodle.com/python3-programming-online/ for Python 3.5.1 and the result was the same.
You need to pass the animal name when you initialize it — the class won't know the variable name.
class Animal(object):
def __init__(self, name, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance of the class, when an instance
# is created.
# pass the name to the class
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str("The " + self.color + " " + self.name + " is feeling " + self.mood + ".")
def colors(self, other):
return str("The ", self.name, " is " + self.color + " and the " + other.name, " is ", other.color, ".")
The output:
hippo = Animal("hippo", "large", "purple", 'amused')
print(hippo.feeling())
# The purple hippo is feeling amused.
Your method uses commas to separate arguments. Use an f-string, and print instead of returning, as such:
print(f”The {self.size} {self.color} Animal is feeling {self.mood}.”)
Also, you expect self to somehow return the name of the variable. Instead, pass the animal type to the function in init.
As answered by # Ch3steR, you can use __repr__ or __str__. Both serve for the purpose. example is as below:
>>> class Test:
... def __repr__(self):
... return "Test()"
... def __str__(self):
... return "member of Test"
...
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test
There are few things to address here
The value return from the def feeling(self) function is a tuple, whenever the return values are seprated by a comma, the function returns a tuple consiting of all the return values. Hence we you try to print it it comes looking like a list. So either return a string or modify how you are printing the returned values from the tuple.
You want to get the instance name of class object when you are printing it. i.e
hippo = Animal("large", "purple", 'amused') for this you expect str(self) to return the instance name, which is a bit non trivial. First define this funtion def __str__(self): to get desired output whenever you use str(self). Second to get the variable name either supply the name as a class variable in constructor and use it, which would be easier way or you can use python-varname package to use the varname() function to acheive this.
class Klass:
def __init__(self):
self.id = varname()
k = Klass()
# k.id == 'k'
Expandable using list comprehension,
class Animal:
def __init__(self, name, size, color, mood):
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str(f"The {self.color} {self. name} is feeling {self.mood}.")
def colors(self, other):
return str(f"The {self.name} is {self.color} and the {other.name} is {other.color}.")
n = int(input("No of Animals:"))
Animals = []
for i in range(n):
print(f"Enter Details for Animal No.{i+1}")
s = Animal(*[input(f'Enter {info}: ')for info in ["Name", "Size", "Color", "Mood"]])
Animals.append(s)
for i in range(len(Animals)):
print(f"\nAnimal {i+1}")
print(Animals[i].feeling())
No of Animals:1
Enter Details for Animal No.1
Enter Name: Hippo
Enter Size: large
Enter Color: purple
Enter Mood: happy
Animal 1
The purple Hippo is feeling happy.
[Program finished]

Calling a method returns <__main__ XYZ object at 0x01234567>

I'm going through a web-based python tutorial and the code below executes in the web environment the class has provided.
However, when I try to run the code locally in Anaconda I get the following result:
I'm Fido. I feel <bound method Pet.mood of <__main__.Pet object at 0x00000223BD4B74E0>>.
I see how using class and superclass can make my code better, and trying to figure out how to get the web based examples to work locally.
Here's the code:
class Pet:
def __init__(self, name = 'Kitty'):
self.name = name
def mood(self):
#code simplified for SO example
return 'happy'
def __str__(self):
state = " I'm {}. I feel {}.".format(self.name, self.mood)
return state
class Cat(Pet):
def chasing_rats(self):
return "I'll get you!"
p1 = Pet("Fido")
print(p1)
self.mood is an instance method of the class Pet. So you need to call it as a method by including the parentheses as self.mood()
class Pet:
def __init__(self, name = 'Kitty'):
self.name = name
def mood(self):
#code simplified for SO example
return 'happy'
def __str__(self):
state = " I'm {}. I feel {}.".format(self.name, self.mood())#updated this line
return state
class Cat(Pet):
def chasing_rats(self):
return "I'll get you!"
p1 = Pet("Fido")
print(p1)
OUTPUT
I'm Fido. I feel happy.

unbound method error - Text Based Adventure

I am creating a text based adventure in python. I have ready two books on python and taken an online course, so I think I really have all the basics down.
Now I am creating my items currently. My setup is
Item->Weapon->(specific weapon here).
All classes inherit the previous.
I am unable to print the values of the items such as Holy_Sword and Stick. I am able to print them if I don't create them as classes and just use a variable to create the instance of weapon. However, due to what I want to do further down the line, I really would like them to be classes.
The error I am getting is:
unbound method str() must be called with Holy_Sword instance as first argument (got nothing instead)
My code is:
class Item(object):
def __init__(self, name, value, description):
self.name = name
self.value = value
self.description = description
def item_description(self):
return "Your %s is worth %d gold and is a %s" % (self.name, self.value, self.description)
class Weapon(Item):
def __init__(self,name, value,description, attack):
self.attack = attack
super(Weapon, self).__init__(name, value, description)
def __str__(self):
return "Your %s is worth %d gold and has an Attack Damage of %d, it is %s" % (self.name, self.value, self.attack, self.description)
class Stick(Weapon):
def __init__(self, name, value, description, attack):
super(Stick, self).__init__(name = "Stick", value= 1, description = "A stick...there may be potential here....or not.", attack = 1)
class Holy_Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Holy_Sword, self).__init__(name = "The Holy Sword of Antioch", value= 20, description = "A Sword whose potential far outweighs it's lack of stylishness ", attack = 20)
class Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Sword, self).__init__(name = "Sword", value= 3, description = "A Wooden Sword.", attack = 5)
print Holy_Sword.__str__()
Keep in mind that, in the code you have here, Holy_Sword refers to a class. It is not itself an instance of Item.
Holy_Sword.__str__ is an instance method. It can't be called on its own like you're trying to do here; it must be called through an instance of the Holy_Sword class.
(Note that it's usually better to not invoke __str__ directly. This method should usually only be called through the str() function, e.g. str(Holy_Sword).)
What you can do is create an instance of Holy_Sword and print the string value of that:
sword = Holy_Sword()
print str(sword)
However, you may want to instead consider making Holy_Sword be a instance of Weapon with specific attributes, rather than being a subclass. If the only way it needs to differ from other weapons is in its attributes, there's no need for it to be a separate class.
You need to instantiate the class first:
my_sword = Holy_sword(...)
print my_sword.__str__()

Calling method from previous class

I'm trying to call a method from a previous Class for the Class I'm currently working on. It's a mock GPS system using classes for different things. The class I'm trying to get the method from looks like the following :
class GPS_POI:
def __init__(self, location, name , kind):
self.location= location
self.name = str(name)
self.kind = str(kind)
def __str__ (self):
return (str(self.location) + ": "+ self.name +", " + self.kind )
The current class and method I am working on:
class GPS :
def __init__ (self, current, map = None):
self.current = current
self.map= map
self.route= []
def display_map(self):
for i in self.route:
display= GPS_POI()
return (display.__str__ + "\n")
When I run it, I just end up getting the result of "None" when the output I want (example) would be :
"(3,1): kmart, clothes \n(2,3): burger king, food\n" etc.
Would I need to include my parameter self.map from the class GPS into the display_map function for it work properly? What am I not understanding about calling a method from a previous class?
You aren't calling display.__str__; you are just referencing it. You shouldn't call __str__ explicitly anyway. Its purpose is to provide a hook for when you try to treat the object as a string, such as when passing it to str as an argument:
return str(display) + "\n"

Categories