why __init__ is called before object created? - python

class Point(object):
def __init__(self, x=0, y=0):
self.__x = x
self.__y = y
print 'point ({x},{y}) created.'.format( x=self.__x, y=self.__y )
class Line(object):
def __init__(self, start_point=Point(), end_point=Point()):
print 'Line.__init__ called.'
self.start = start_point
self.end = end_point
def test_line():
p1 = Point(1,1)
p2 = Point(2,2)
line1 = Line(p1, p2)
if __name__=='__main__':
test_line()
When I run this script, it gives the result:
point (0,0) created.
point (0,0) created.
point (1,1) created.
point (2,2) created.
Line.__init__ called.
I don't know why Point.__init() is called before line1 is created.

def __init__(self, start_point=Point(), end_point=Point())
Default function parameters are members of the function itself and are created when the function is defined, not at runtime. So each instance of Line uses the same start and end
The common way to work around this is set them by default to None:
def __init__(self, start_point=None, end_point=None):
if start_point is None:
self.start = Point()
if end_point is None:
self.end = Point()

Related

Why Instance variables reference the same object in this code?

I want to implement the move method in Shape class in has-a relation(So Shape class does not inherit CPoint class), but have a problem in setting class variables.
The given code is:
class CPoint:
def __init__(self, x = 0, y = 0):
self.__x = x
self.__y = y
def __str__(self):
return f"pos({self.__x},{self.__y})"
def get_x(self):
return self.__x
def set_x(self, new_x):
self.__x = new_x
def get_y(self):
return self.__y
def set_y(self, new_y):
self.__y = new_y
def move(self, a, b):
self.__x += a
self.__y += b
return CPoint(self.__x,self.__y)
class Shape:
def __init__(self, color = "yellow", filled = True, pos = CPoint()):
#So each pos must reference the different CPoint() instance
self.__color = color
self.__filled = filled
self.__pos = pos
def __str__(self):
return f"{self.__pos}({self.__color},{self.__filled})"
def move(self, a, b):
self.__pos.move(a,b)
if type(self) == Shape:
return f"{self}"
else:
return f"{self.__pos}{self}"
def main():
a = Shape()
b = Shape("red")
a.move(2,3)
print(b.move(4,5))
main()
the result is:
pos(0,0)(yellow,True)
pos(0,0)(red,True)
pos(2,3)(yellow,True)
pos(6,8)(red,True)
and the result should be like:
pos(0,0)(yellow,True)
pos(0,0)(red,True)
pos(2,3)(yellow,True)
pos(4,5)(red,True)
And I executed the code on the python tutor, and the visualization of the code is like this:
python tutor visualization
So Shape() and Shape("red") objects should reference different CPoint instance (cuz they have their own position data), but they reference the same instance even though I set the default parameter like 'pos = CPoint()'.
Can someone please explain why they're referencing the same instance, and how to get around it?
This is how python does argument defaults, default arguments are initialized once during function declaration and not every time when the function is called like you might expect if you've used other languages like Javascript https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments
Because of this, the same CPoint() instance is shared between different constructor calls.
To avoid this behavior you could try setting it inside the function itself.
class Shape:
def __init__(self, color = "yellow", filled = True, pos = None):
if pos is None:
pos = CPoint()
#So each pos must reference the different CPoint() instance
self.__color = color
self.__filled = filled
self.__pos = pos

comunication between parent and child class python

Does anyone know how i can get the name of an object with a class function?
I want to use this because i have a class that is supposed to have multiple players in a list, and get their cordinates
object that wants to give their cordinates:
import math
class Pixel:
"""Represents a posision in a grid with a x posistion, a y position and
a character, the x and y position are saved in one tuple"""`
def __init__(self, char='#', pos=(0, 0)):
assert type(char) == str
assert type(pos[0]) == int and type(pos[1]) == int
self.pos = pos
self.x = self.pos[0]
self.y = self.pos[1]
self.char = char
def __str__(self):
return self.char
def __repr__(self):
return self.char
# possible debug repr 'Pixel object with
# char = ' + str(self.char) + ' and pos = ' + str(self.pos)`
class TestObject(Pixel):
def __str__(self, parent):
return '+'
The parent object wants to know what self.pos is from theTestObject (the parent has a list with different testObjects) is there a way for me to give the TestObject the name of the parent object when i am creating it so that he can push that information (parent.funcname(position)) I need it for a function that doesn't return values.
if anyone knows another way to get TestObject.pos to my parent object please tell too, thanks in advance
You could give your instances of TestObject a reference to the parent. This could be done via the __init__ method of TestObject. This way however, the parent has to be known at the time of the instance's construction. I would make it an optional (keyword) parameter and implement a setter method. For example:
class Pixel:
def __init__(self, char='#', pos=(0, 0), parent=None):
assert type(char) == str
assert type(pos[0]) == int and type(pos[1]) == int
self.pos = pos
self.x = self.pos[0]
self.y = self.pos[1]
self.char = char
self._parent = parent
def set_parent(self, parent):
self._parent = parent
class TestObject(Pixel):
def somemethod(self):
position = 0
# do what ever you need to do here
if isinstance(self._parent, Pixel):
self._parent.set_value(self)
When you add an instance obj of TestObject to the list in the parent object, the parent object should call obj.set_parent(self) to set itself as the object's parent.
Here is an example for a parent class:
class PixelList:
def __init__(self):
self._pixels = []
def add_pixel(self, pixel):
self._pixels.append(pixel)
pixel.set_parent(self)
def set_value(self, pixel):
# do stuff here
position = pixel.pos
If you then call obj.somemethod, your parent object's set_value method is called with the pixel as argument. In the set_value method you can thus access any information of the pixel you like (e.g. pixel.pos).

How can I save an instance of a class in it's own class as a class variable in Python?

I'm trying to define a class that has an instance of itself as a class variable so I can reference a common instance of it all over the place.
How can I get something like this to work?
class Point():
ORIGIN = Point()
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p0 = Point.ORIGIN
p1 = Point(3,4)
distance = (p1.x*p1.x + p1.y*p1.y) ** .5
print(distance)
You can add the class attribute after the class has been created:
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y
Point.ORIGIN = Point()
You can probably also make it work so that the origin is created lazily via descriptors, or you can probably do something funky using a metaclass -- but that seems unlikely to be worth your while.
You could use a meta class:
>>> class SingletonMeta(type):
... def __init__(cls, name, bases, dct):
... cls.ORIGIN = cls()
...
>>> class Point(metaclass=SingletonMeta):
... def __init__(self, x=0, y=0):
... self.x = x
... self.y = y
...
>>> p0 = Point.ORIGIN
>>> p1 = Point(3,4)
>>> p0
<__main__.Point object at 0x110b7e7b8>
>>> p0.x, p0.y
(0, 0)
Simply create class variables that represent the values you want instead of encapsulating those values in an instance:
class Point:
x = 0
y = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
x,y = Point.x, Point.y
p1 = Point(3,4)
distance = ((p1.x-x)**2 + (p1.y-y)**2) ** .5
print(distance) # prints 5.0
Or, better yet:
class Point:
x = 0
y = 0
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def distance(self, other=None):
if other is None:
x,y = Point.x, Point.y
else:
x,y = other.x, other.y
return ((self.x-x)**2 + (self.y-y)**2) ** .5
And then you can do this:
>>> p1 = Point(3,4)
>>> p1.distance()
5.0
>>> p1.distance(Point(3,5))
1.0

inserting a node into a tree in python

I am trying to write a node class to create a tree structure. There seems to be
some problem when I'm trying to add a child node to the root node with the method "addChild" because the child node appears to have itself in its children list. I couldn't figure out why, so any help is appreciated.
class node(object):
def __init__(self, name, x, y, children = []):
self.name = name
self.children = children
self.x = x
self.y = y
def addChild(self):
b=node('b', 5, 5)
self.children.append(b)
return
root=node('a',0.,0.)
print root.children
root.addChild()
print root.children
print root.children[0].children
Yields:
[<__main__.node object at 0x7faca9f93e50>]
[<__main__.node object at 0x7faca9f93e50>]
Whereas the second "print" line should have returned an empty array.
The default parameter value children = [] assigns a single list object to the __init__ function that is then used on every call all children. This is a common mistake. Instead, create children in the __init__ function itself:
class node(object):
def __init__(self, name, x, y, children=None):
self.name = name
self.children = [] if children is None else children
self.x = x
self.y = y
# ...

How can I create a 3d object/class in Python?

My end goal right now is to take points that are read from a text file, and turn them into 3d objects. They do not need to be visualized, but they need to be stored in objects instead of just a string containing the x, y, and z values. The file gives me six numbers, two of each x, y, and z, and I was wondering how I would go about creating a point class/object that will take all three variables and then a line object/class that will take two of the points.
Just define a Point and a Line class:
class Point(object):
def __init__(self, x=0, y=0 ,z=0):
self.x = x
self.y = y
self.z = z
class Line(object):
def __init__(self, point1=None, point2=None):
self.point1 = point1 or Point() # (0,0,0) by default
self.point2 = point2 or Point() # (0,0,0) by default
To create points and lines objects:
>>> p1 = Point(1, 2, 3)
>>> p2 = Point(4, 5, 6)
>>> line = Line(p1, p2)
Once you have got the data from the file (for this Regular Expressions are applicable), you will want to input that into a class which is defined as to store the two points (which can be objects themselves) e.g.
class Point(tuple):
#property
def x:
return self[0]
#property
def y:
return self[1]
#property
def z:
return self[2]
class Vector(object):
def __init__(self, x1, y1, z1, x2, y2, z2):
self._a = Point(x1, y1, z1)
self._b = Point(x2, y2, z2)
#property
def a(self):
return self._a
#property
def b(self):
return self._b
# Other methods here e.g.
#property
def i(self):
return self.b.x - self.a.x
#property
def j(self):
return self.b.y - self.a.y
#property
def k(self):
return self.b.z - self.a.z
def length(self):
return ( self.i**2 + self.j**2 + self.k**2 ) ** (1/2)

Categories

Resources