Can you please clarify about the perimeter variable in the below class.
I understand that the self.vertices is to a particular instance. Since perimeter is not defined with self, does that mean its a class variable here? Then is it not common to all the instances?
Is it not the right way to code the perimeter as self.perimeter, so its aptly declared to each instance?
This code is from a book.
Polygon.py
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, p2):
return math.sqrt((self.x-p2.x)**2 + (self.y-p2.y)**2)
class Polygon:
def __init__(self):
self.vertices = []
def add_point(self, point):
self.vertices.append((point))
def perimeter(self):
perimeter = 0
points = self.vertices + [self.vertices[0]]
for i in range(len(self.vertices)):
perimeter += points[i].distance(points[i+1])
return perimeter
>>> square = Polygon()
>>> square.add_point(Point(1,1))
>>> square.add_point(Point(1,2))
>>> square.add_point(Point(2,2))
>>> square.add_point(Point(2,1))
>>> square.perimeter()
4.0
New type
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, p2):
return math.sqrt((self.x-p2.x)**2 + (self.y-p2.y)**2)
class Polygon:
def __init__(self):
self.vertices = []
def add_point(self, point):
self.vertices.append((point))
def perimetermethod(self):
self.perimeter = 0
points = self.vertices + [self.vertices[0]]
for i in range(len(self.vertices)):
self.perimeter += points[i].distance(points[i+1])
return self.perimeter
if __name__=='__main__':
p1 = Polygon()
p1.add_point(Point(1,1))
p1.add_point(Point(1,2))
p1.add_point(Point(2,2))
p1.add_point(Point(2,1))
print(p1.perimetermethod())
Assigning a new variable with
some_name = ...always creates the variable in the innermost enclosing scope (unlessglobalornonlocalare in play, but they’re not relevant here). Assigning a new attribute name on an object creates the attribute on that object.So
self.foo = 1assigns an attribute namedfooon the object currently referred to byself. Conventionally, the nameselfis used as the first parameter to a method, which receives the object on which the method was invoked. So “defining a variable with self” isn’t anything special; it’s just the ordinary rules about assigning to attributes on existing object. Any attributes that exist in instance object itself obviously have to be specific to that instance.perimeter = 0inside theperimetermethod of thePolygonclass creates a variable in the innermost enclosing scope. That’s theperimetermethod, so it creates a local variable. A local variable only exists for the duration of the function call, so it’s neither a class variable nor an instance variable. You can’t access it from anywhere except within the scope of that particular method (and it has a new completely independent value on each invocation), so it can’t be common to all the instances. But neither can you access a different value for it on each particular instance, so it’s not an instance variable either.If you had
perimeter = 0outside a method, in the class block itself, then the innermost enclosing scope would be the class block. That would create a “class variable”, which is just an attribute on the class object. If an attribute is on a class, then obviously it can’t be specific to any instance, because there’s only one class but there can be any number of instances. As an aside, this is exactly what the__init__,add_point, andperimetermethods of thePolygonclass are; they were assigned (with adefstatement) in a class block, so they became attributes of the class object.Summary:
self.foo = 1is assigning to an attribute on the object currently referenced byself(this is usually the “current instance”)foo = 1in a class block is creating a class attribute of the class being definedfoo = 1in a def block is creating a local variable of the function being definedBut you shouldn’t really memorise it that way. They’re just special cases of:
foo.bar.baz = 1is writing to an attribute of an objectfoo = 1is writing to a variable in the innermost enclosing scope