Python 2.7, defining a base class with attributes, id with init constructor - python

I am trying to define a generic base class Geometry, with a unique id for each object starting at 0. I am using init as the method.
I am trying to create a generic base class named Geometry that I will use to organize geometry objects like point or polygon and containing an id attribute starting at 0. I know all of the objects should have a unique ID. I'm using the constructor (__init__) when creating a new Geometry object (integer). And would like for the base class to automatically assign the ID of the Geometry object.
Current code:
class Geometry(object):
def__init__(self,id):
self.id = id
I think I am on the right path but I am not positive. Should I have id = 0 above def__init__(self,id)?
Any guidance will be appreciated.

If the first line of your class is id = 0 then it becomes a class attribute and is shared by all instances of Geometry and all of its children.
Here is an example of using a class scoped variable:
#!/usr/bin/env python2
class Geometry(object):
# ident is a class scoped variable, better known as Geometry.ident
ident = 0
def __init__(self):
self.ident = Geometry.ident
Geometry.ident += 1
class Circle(Geometry):
def __init__(self, radius):
Geometry.__init__(self)
self.radius = radius
def __str__(self):
return '<Circle ident={}, {}>'.format(self.ident, self.radius)
class Equilateral(Geometry):
def __init__(self, sides, length):
# super is another way to call Geometry.__init__() without
# needing the name of the parent class
super(Equilateral, self).__init__()
self.sides = sides
self.length = length
def __str__(self):
return '<Equilateral ident={}, {}, {}>'.format(self.ident,
self.sides, self.length)
# test that ident gets incremented between calls to Geometry.__init__()
c = Circle(12)
e = Equilateral(3, 8)
f = Circle(11)
print c
assert c.ident == 0
print e
assert e.ident == 1
print f
assert f.ident == 2
Something feels wrong about this, though I've not put my finger on it.

class Geometry(object):
def __init__(self,id=0):
self.id = id
__init__ in python is invoked when you create an instance of that class
circle = Geometry(1)

Related

Why did my output change when I called the class attribute from an instance instead of the class?

(I'm fairly new to programming, so understand that my query might not make sense. I've tried my best to explain it but if you are still confused, you can ask me to clarify)
I understand the that we can call the class attribute number_of_people and increment by one so that when we create a new instance (in this context, a person), the number of people increases by one:
class Person:
# Class attribute
number_of_people = 0
# Constructor
def __init__(self, name):
self.name = name
# Every time we call the constructor, we increment the number of people.
Person.number_of_people += 1
# Driver code
p1 = Person("Jack")
print(Person.number_of_people)
# output gives 1
However, I'm having trouble with understanding the output of the code when we change the we choose to increment p1.number_of_people instead of Person.numer_of_people:
class Person:
# Class attribute
number_of_people = 0
# Constructor
def __init__(self, name):
self.name = name
# Every time we call the constructor, we increment the number of people.
p1.number_of_people += 1
# Driver code
p1 = Person("Jack")
print(p1.number_of_people)
# output gives 0 (I expected the output to be 1)
I thought that since class attributes can be accessed by both the class and instances, my change wouldn't make a difference. I suspect it has to do with p1 being mentioned in the class before it's mentioned in the driver code, but I'm not sure where to go from there.
I suspect the demonstration you were trying to do for yourself is to examine the difference between using the class attribute as a class attribute, vs as an instance attribute. Consider this difference:
class Person:
population = 0
def __init__(self,name):
self.name = name
Person.population += 1
p1 = Person("Jack")
p2 = Person("Tom")
p3 = Person("Bill")
print(p1.population)
print(p2.population)
print(p3.population)
Output:
3
3
3
Compared to:
class Person:
population = 0
def __init__(self,name):
self.name = name
self.population += 1
p1 = Person("Jack")
p2 = Person("Tom")
p3 = Person("Bill")
print(p1.population)
print(p2.population)
print(p3.population)
Output:
1
1
1
In the second example, the instance starts out using the class attribute, but as soon we change it, it creates an instance attribute that has a separate life.

Duplication of class inside two different objects

I found a bug in my program and I did some digging before making something much simpler to understand the problem.
In a nutshell: I'm creating two objects from a class where I want to store an object from another class. But When I'm doing this, both objects are getting the same result. How can I prevent this duplication?
It seems like both objects are pointing on the same class.
# Sub-class that may not be extendable
class MyClass:
def __init__(self, number):
self.number = number
#classmethod
def add_number(cls, number=0):
return cls(number)
# Main class
class MyOtherClass:
my_objects = []
"""
Initialize the class
:param List[MyClass] my_objects: List of MyClass objects
"""
def __init__(self, this_object):
self.my_objects.append(this_object)
if __name__ == "__main__":
my_object1 = MyOtherClass(MyClass.add_number())
my_object2 = MyOtherClass(MyClass.add_number())
for i in range(100):
my_object1.my_objects.append(MyClass.add_number(i))
print(f"Appending obj1 : {my_object1.my_objects[i].number}")
for y in range(100, 0, -1):
my_object2.my_objects.append(MyClass.add_number(y))
print(f"Appending obj2 : {my_object2.my_objects[y].number}")
# later
z = 0
while z < len(my_object1.my_objects):
print(f"obj1 : {my_object1.my_objects[z].number}")
print(f"obj2 : {my_object2.my_objects[z].number}")
z += 1

Python AttributeError: property cannot overwrite inherited attribute?

I still don't fully understand when and how to use properties. Here I have a class SpecialCar which is inheriting Car. The variable summer_tire should basically be equivalent to tire, except for the name. So whenever I am asking for either of those two, I want to get summer_tire.
Using #property results in an error. Deleting the #property line will print 0, but I want to get 2.
class Car():
def __init__(self):
self.tire = 0
class SpecialCar(Car):
def __init__(self):
Car.__init__(self)
self.summer_tire = 2
self.winter_tire = 5
#property
def tire(self):
return self.summer_tire
i = SpecialCar()
print(i.tire)
You declared a property that doesn't have a setter, thus self.tire = 0 in Car.__init__ fails.
You could give your new property a setter:
class SpecialCar(Car):
def __init__(self):
Car.__init__(self)
self.summer_tire = 2
self.winter_tire = 5
#property
def tire(self):
return self.summer_tire
#tire.setter
def tire(self, new_tire):
self.summer_tire = new_tire
or you could avoid calling Car.__init__ altogether, or make Car.tire a class attribute, set as part of the class and replaced with the property in subclasses.

python using __init__ vs just defining variables in class - any difference?

I'm new to Python - and just trying to better understand the logic behind certain things.
Why would I write this way (default variables are in __init__):
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
Instead of this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
I mean - why do I need to use __init__ -> if I can just as easily add default variables to a class directly?
When you create variables in the Class, then they are Class variables (They are common to all the objects of the class), when you initialize the variables in __init__ with self.variable_name = value then they are created per instance and called instance variables.
For example,
class TestClass(object):
variable = 1
var_1, var_2 = TestClass(), TestClass()
print var_1.variable is var_2.variable
# True
print TestClass.variable is var_1.variable
# True
Since variable is a class variable, the is operator evaluates to True. But, in case of instance variables,
class TestClass(object):
def __init__(self, value):
self.variable = value
var_1, var_2 = TestClass(1), TestClass(2)
print var_1.variable is var_2.variable
# False
print TestClass.variable is var_1.variable
# AttributeError: type object 'TestClass' has no attribute 'variable'
And you cannot access an instance variable, with just the class name.
When you write this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
Those are not instance variables, they're class variables (meaning: the same variables with the same values are shared between all instances of the class.) On the other hand, this:
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
... Is declaring instance variables, meaning: the values are different for each instance of the class. As you see, each snippet means a completely different thing, and you have to pick the one that is appropriate for you. Hint: most of the time you're interested in instance variables, because class variables define a kind of shared global state for your objects, which is error prone.

Creating an object with a reference to the object that created it

I have a program where an object creates another object. However, the second object that gets created needs to be able to access the first. Is this possible?
EG (pseudocode)
class parentObject():
parentVar = 1
# Create Child
x = childObject()
class childObject():
#Assign Var to the Var of the childs parent
childVar = parent.parentVar
>>> x.childVar = 1
is there a straitforward way to do this?
UPDATE:
I don't want to inheret the class, I need to be able to access the actual object that created it, as each object created from that class has different values.
Why not inherit the class?
class parentObject():
parentVar = 1
class childObject(parentObject):
childVar = parentObject.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you are going to have different instances of the class, you should do it as this instead:
class parentObject(object):
def __init__(self):
self.parentVar = 1
class childObject(parentObject):
def __init__(self):
super(childObject, self).__init__()
self.childVar = self.parentVar
>>> x = childObject()
>>> print(x.childVar)
1
If you want a reference to the "parent" class, but inheritance is illogical, consider sending self in to the constructor:
class Room:
def __init__(self, name):
self.name = name
self.furniture = []
def add_chair(self):
self.furniture.append(Chair(self))
def __str__(self):
return '{} with {}'.format(self.name, self.furniture)
class Chair:
def __init__(self, room):
self.room = room
def __str__(self):
return 'Chair in {}'.format(self.room.name)
r = Room('Kitchen')
r.add_chair()
r.add_chair()
print r
print r.furniture[0]
Output:
Kitchen with [<__main__.Chair instance at 0x01F45F58>, <__main__.Chair instance at 0x01F45F80>]
Chair in Kitchen

Categories

Resources