Reputation: 20856
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.
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())
Upvotes: 5
Views: 9358
Reputation: 71400
Assigning a new variable with some_name = ...
always creates the variable in the innermost enclosing scope (unless global
or nonlocal
are 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 = 1
assigns an attribute named foo
on the object currently referred to by self
. Conventionally, the name self
is 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 = 0
inside the perimeter
method of the Polygon
class creates a variable in the innermost enclosing scope. That's the perimeter
method, 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 = 0
outside 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
, and perimeter
methods of the Polygon
class are; they were assigned (with a def
statement) in a class block, so they became attributes of the class object.
Summary:
self.foo = 1
is assigning to an attribute on the object currently referenced by self
(this is usually the "current instance")foo = 1
in a class block is creating a class attribute of the class being definedfoo = 1
in 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 = 1
is writing to an attribute of an objectfoo = 1
is writing to a variable in the innermost enclosing scopeUpvotes: 12
Reputation: 798506
No, that means that it's local. Also, you don't want to use self.perimeter
since it will shadow the method with the same name.
Upvotes: 2
Reputation: 251365
In your code, there are two things called perimeter
. One is a method on the Polygon
class. The other is a local variable inside that method. There are no class attributes in your code.
Upvotes: 0