Python Object initialization,_init_ method - python

How Can I create class if i have to create object for my class like below.
Obj1 = Class()
Obj2 = Class(para1,para2,para3)
This is related to a task that i need to complete just started learning Python.
I tried construction overloading but it seems to not work in Python .Can anyone tell me how can i achieve this or it is technically wrong to have both line in one code.

You can use *args or **kwargs
class Class1:
def __init__(self, *args):
pass
obj1 = Class1()
obj2 = Class1(para1,para2,para3)
or
class Class1:
def __init__(self, **kwargs):
pass
obj1 = Class1()
obj2 = Class1(para1=para1,para2=para2,para3=para3)
Refer this to learn more about *args and **kwargs

If you set default values like length = 80, you don't have to set them. But if you set the values, it ll be set as you wish. The following code demonstrates almost what you want.
class Rectangle:
def __init__(self, length = 80, breadth = 60, unit_cost=100):
self.length = length
self.breadth = breadth
self.unit_cost = unit_cost
def get_perimeter(self):
return 2 * (self.length + self.breadth)
def get_area(self):
return self.length * self.breadth
def calculate_cost(self):
area = self.get_area()
return area * self.unit_cost
# r = Rectangle() <- this returns with default values
# breadth = 120 cm, length = 160 cm, 1 cm^2 = Rs 2000
r = Rectangle(160, 120, 2000)
print("Area of Rectangle: %s cm^2" % (r.get_area()))
print("Cost of rectangular field: Rs. %s " %(r.calculate_cost()))

Related

TypeError: must be real number, not Circle

import math as m
class Circle:
def __init__(self,radius):
self.radius = radius
count = 0
def area(r):
k = m.pi * m.pow(r,2)
return k
I am not sure what wrong with the code above but when I am trying execute like below
a = Circle(4)
a.area()
it throws an error like
" k = m.pi * m.pow(r,2)
TypeError: must be real number, not Circle"
Unable to understand how it's considering the float value as an instance to the circle.
The first argument of an instance method is a reference to the instance itself (usually called self) - that's where the Circe is coming from. You shouldn't be passing the radius, you should be using the member you have:
def area(self):
k = m.pi * m.pow(self.radius, 2)
return k
import math as m
DEFAULT_RADIUS = 0.5
class Circle(object):
def __init__(self, radius=DEFAULT_RADIUS):
self.radius = radius
count = 0
def area(self, r=None):
if r is not None:
self.radius = r
k = m.pi * m.pow(self.radius, 2)
return k
a = Circle(4)
a.area()

TypeError: printArea() takes 0 positional arguments but 1 was given

I created a class that finds the area of a rectangle. The problem I have is that the printArea() method gives me a type error whenever I try to check an instance of the class and I don't know what is wrong.
class Rectangle:
length = 0;
breadth = 0;
def __init__(self, length, breadth):
self.length = length
self.breadth = breadth
def setLength(self, length):
self.length = length
def getLength(self):
return self.length
def setBreadth(self, breadth):
self.breadth = breadth
def getBreadth(self):
return self.breadth
def calculateArea(self):
Area = self.getLength() * self.getBreadth()
return Area
def printArea(self):
Area = self.getLength() * self.getBreadth()
print ("The area is %d" % (Rectangle.Area))
If I try x = Rectangle(7,4) and then tryx.printArea(), I get:
Traceback (most recent call last):
File "<pyshell#229>", line 1, in <module>
x.printArea()
TypeError: printArea() takes 0 positional arguments but 1 was given
TLDR
If I run your code I get AttributeError: type object 'Rectangle' has no attribute 'Area'. The code works if you change it to
def printArea(self):
area = self.getLength() * self.getBreadth()
print("The area is %d" % (area))
Longer answer
When you write Rectangle.Area, this does not give you the area of this current rectangle (which would be given by self.getArea()), instead you get the member Area of the class Rectangle (which does not exist).
With that said, you could get what you want by making area a property and calling it like this:
class Rectangle:
def __init__(self, length, breadth):
self._length = length
self.breadth = breadth
#property
def area(self):
return self.length * self.breath
def printArea(self):
print ("The area is %d" % (self.area))
Note also that get... and set... are heavily frowned upon in python, and accessing the member is totally fine. If you truly need them, you should use properties with getters and setters
class Rectangle:
def __init__(self, length, breadth):
self.length = length
self.breadth = breadth
#property
def length(self):
return self._length
#length.setter
def length(self, value):
self._length = value

How to effectively update the attributes of an object

I am creating a "pet game" in order to train my computing skills in python (that is just an excuse: it is because it is fun).
I decided to do a simple RPG game. For that, I defined the class hero:
class hero:
#Common class for the main character
def __init__(self, name, lvl, str, agi, vit, int, luk, prof):
self.name = name
self.lvl = lvl
self.str = str
self.agi = agi
self.vit = vit
self.int = int
self.luk = luk
self.prof = prof
self.exp = 0
if prof==1:
self.dmg=3*(self.str)+1*(self.agi)
self.skillList=['heavySlash01']
self.strUp=3
self.agiUp=1
self.vitUp=2
self.intUp=1
self.lukUp=1
if prof==2:
self.dmg=1*(self.str)+3*(self.agi)
self.skillList=['doubleAttack02']
self.strUp=1
self.agiUp=3
self.vitUp=1
self.intUp=1
self.lukUp=2
if prof==3:
self.dmg=4*(self.int)
self.skillList=['fireBall03']
self.strUp=1
self.agiUp=1.5
self.vitUp=0.5
self.intUp=3.5
self.lukUp=1.5
self.hp=19*vit
However, I noticed that whenever the hero leveled up, I needed to update all of its status separately. For instance, I needed to manually update the hero.dmg. Changing the agi, str and int did not automatically change the dmg as I would expect.
My question is then: Is there a way to make the dmg automatically update itself, based on its formula?
Make dmg a property instead of setting in the __init__ function. The __init__ only runs when the instance is initialized, which is why things aren't updating. However, making it a property runs the method whenever the property is accessed.
#property
def dmg(self):
if prof==1:
return 3*(self.str)+1*(self.agi)
if prof==2:
...
It's better to use inheritance in your case:
class Hero(object):
def __init__(self, name, lvl, _str, agi, vit, _int, luk):
self.name = name
self.lvl = lvl
self._str = _str # Should not use "str" because of reserved keyword of the same name
self.agi = agi
self.vit = vit
self._int = _int # Should not use "int" because of reserved keyword of the same name
self.luk = luk
self.exp = 0
#property
def hp(self):
return 19 * self.vit
class HeroProf_1(Hero):
skillList = ['heavySlash01']
strUp = 3
agiUp = 1
vitUp = 2
intUp = 1
lukUp = 1
#property
def dmg(self):
return 3 * self._str + 1 * self.agi
class HeroProf_2(Hero):
skillList = ['doubleAttack02']
strUp = 1
agiUp = 3
vitUp = 1
intUp = 1
lukUp = 2
#property
def dmg(self):
return 1 * self._str + 3 * self.agi
class HeroProf_3(Hero):
skillList = ['fireBall03']
strUp = 1
agiUp = 1.5
vitUp = 0.5
intUp = 3.5
lukUp = 1.5
#property
def dmg(self):
return 4 * self._int

Would I be able to separate variables into another class but keep the usage the same?

I'm trying to rewrite a script and I'm stuck on making it easy to use. Basically it's an assembly script (like the reverse of destruction), where you input a load of variables such as location, whether the location is absolute or relative, scale, rotation, visibility, random offset, etc, to create an animation. The first version was very non user friendly, so I'm trying to get it working nicely from the start this time.
I've thought of how I'd like it to work, and I've managed to keep it clean, but there is a flaw. As you can see below, it'd be possible to use anything like SetGroup.frame[i].save(), which I don't want (and I don't want to put checks on if name is None throughout the class).
Here is the code I have:
class SetGroup(object):
def __init__(self, name=None, _frame_only=False):
if name is None and not _frame_only:
raise TypeError('name of group must be provided')
self.selection = None
self.origin = None
self.start = None
self.end = None
self.offset = 0
self.distance = None
self.random = 0
self.location = None
self.rotation = None
self.scale = None
self.visibility = None
if not _frame_only:
self.frame = defaultdict(lambda: SetGroup(_frame_only=True))
def save(self):
self.load()
#do a bit of error checking here
self.data[self.name] = {'ObjectSelection': self.selection,
'ObjectOrigin': self.origin,
'FrameStart': self.start,
'FrameEnd': self.end,
'FrameOffset': self.offset,
'FrameDistance': self.distance,
'FrameRandom': self.random,
'StartLocation': self.location,
'StartRotation': self.rotation,
'StartScale': self.scale,
'StartVisibility': self.visibility,
'ExtraFrames': self.frame}
pm.fileInfo['AssemblyScript'] = StoreData().save(self.data)
def load(self):
try:
self.data = StoreData().load(pm.fileInfo['AssemblyScript'])
except KeyError:
pm.fileInfo['AssemblyScript'] = StoreData().save({})
The way I'd like it to work is like this:
a = SetGroup('test')
a.location = ((0, 0, 0), True)
a.start = 0
a.end = 10
a.frame[5].location = ((10, 10, 10), False)
a.frame[5].scale = ((2, 1, 1), True)
a.save()
Unless anyone can think of a way which would make it more friendly to use, how would I separate location, rotation, scale, and visibility into another class and link them up again, so that they still work at the core level of the class, but also work for the frame dictionary too?
Edit - Got it working to a basic level:
class _MovementInfo(object):
def __init__(self, location=None, rotation=None, scale=None, visibility=None):
self.location = location
self.rotation = rotation
self.scale = scale
self.visibility = visibility
def __repr__(self):
return '_MovementInfo(location={x.location}, rotation={x.rotation}, scale={x.scale}, visibility={x.visibility}'.format(x=self)
Then I used this in the main class to merge the dictionaries:
self.__dict__.update({k: v for k, v in _MovementInfo().__dict__.iteritems() if '__' not in k})
self.frame = defaultdict(_MovementInfo)
I would change the code like this:
class SetGroup(_Movement):
def __init__(self, name=None):
if name is None:
# ...
super().__init__()
# ...
self.random = 0 # __init__ should end here
# ...
But you should check that all _MovementInfo's in all frames are _MovementInfo's or have inherited from them (to check this: isinstance(x, _MovementInfo)), but are not SetGroup's (to check this: not isinstance(x, SetGroup)).
super() is short for super(SetGroup, self) (you have to use the last option for python2), and is basicly an object that holds all things that the base class has, and allows you to call methods that modify the class calling it.
Or in code:
class A(object):
def __init__(self, y):
self.x = 2
self.y = y
class B(A):
def __init__(self, y, z):
super().__init__(y) # equivalent to: A.__init__(self, y)
self.z = z
b = B(3, 4)
# b's x is 2, b's y is 3 (both set by A.__init__, the last one was passed by B), and b's z is 4 (set by B.__init__)
I hope this helped,
CodenameLambda

error when executing same loop

I'm new to Python and I really want to understand why I get this error.
It happens in my findLargest function, while trying to execute the second for loop. The thing is that the second for loop does basically the same thing as the first one, but for some reason I get an error as I try to call on a (class)method. How can this be? Am I not allowed to have 2 for loops for same iterable in the same function?
shapeArea=shape.area()
throws:
TypeError: 'float' object is not callable
The objective of findlargest() is to loop through the set of classes twice, first in order to find the largest value(Area) while the second tries to find if there are other values that are equal.
class Shape(object):
def area(self):
raise AttributeException("Subclasses should override this method.")
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
self.area = (self.base * self.height) / 2
return self.area
def __str__(self):
return "{} with base {} and height {}".format(self.__class__.__name__, self.base, self.height)
def __eq__(self, other):
return type(other) == Triangle and self.base == other.base and self.height == other.height
class ShapeSet:
def __init__(self):
self.shape_list = []
def addShape(self, sh):
if sh not in self.shape_list:
self.shape_list.append(sh)
else:
print ("{} is already existing".format(sh.__str__()))
def __iter__(self):
return (self.shape_list)
def __str__(self):
s = ''
for shape in self.__iter__():
s+= shape.__str__() + "\n"
return s
ss = ShapeSet()
ss.addShape(Triangle(1.2,2.5))
ss.addShape(Triangle(1.4,2.5))
ss.addShape(Triangle(1.3,2.5))
ss.addShape(Triangle(1.5,2.5))
def findLargest(shapes):
maxs = None
maxA = 0.0
for shape in shapes.__iter__():
shapeArea = shape.area()
if shapeArea > maxA or maxs == None:
maxs = shape
maxA = shapeArea
maxTuple = (maxs)
for shape in shapes.__iter__():
shapeArea = shape.area()
With this:
def area(self):
self.area=(self.base*self.height)/2
return self.area
You enter the method and then immediately mask it by assigning a different name to its reference. From then on, self.area refers to that number and you can no longer access that method. Fortunately, the fix is easy: don't save a reference at all.
def area(self):
return self.base * self.height / 2
Python does not separate the names for function/method objects and for other objects. Use unique reference names for any objects you'd like to retain.
I think your problem is here:
class Triangle(Shape):
def __init__(self, base, height):
self.base=base
self.height=height
def area(self):
self.area=(self.base*self.height)/2 ###################### HERE
return self.area
If you have
shape = Triangle(1.5,2.5)
shape.area() # returns float assigned at "HERE" to shape.area
shape.area() # try to call that float assigned in previous step at "HERE"

Categories