Python中的自变量vs类变量

时间:2012-08-20 02:09:39

标签: python

请您澄清一下下面的班级变量。

我理解self.vertices是针对特定实例的。由于perimeter未定义为self,这是否意味着它是一个类变量?那么所有实例都不常见吗?

这不是将边界编码为self.perimeter的正确方法,因此它适当地声明为每个实例吗?

此代码来自一本书。

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 

新类型

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())

3 个答案:

答案 0 :(得分:4)

使用some_name = ...分配新变量始终会在最里面的封闭范围内创建变量(除非globalnonlocal正在播放,但它们在此处不相关)。在对象上分配新属性名称会在该对象上创建属性。

因此self.foo = 1会在foo当前引用的对象上分配名为self的属性。通常,名称self用作方法的第一个参数,该方法接收调用该方法的对象。所以“用自己定义一个变量”并不是什么特别的东西;它只是关于在现有对象上分配属性的普通规则。实例对象本身中存在的任何属性显然必须特定于该实例。

perimeter = 0类的perimeter方法中的

Polygon在最里面的封闭范围内创建一个变量。这是perimeter方法,因此它创建了一个局部变量。局部变量仅在函数调用期间存在,因此它既不是类变量也不是实例变量。除了在特定方法的范围内之外,您无法从任何地方访问它(并且它在每次调用时都有一个新的完全独立的值),因此它不是所有实例的共同点。但是你也不能在每个特定的实例上为它访问不同的值,因此它也不是实例变量。

如果你在方法之外的perimeter = 0,在类块本身,那么最里面的封闭范围将是类块。 会创建一个“类变量”,它只是类对象的一个​​属性。如果一个属性在一个类上,那么很明显它不能特定于任何实例,因为只有一个类但可以有任意数量的实例。顺便说一句,这正是__init__类的add_pointperimeterPolygon 方法的内容;它们被分配(带有def语句)在类块中,因此它们成为类对象的属性。


要点:

  1. self.foo = 1正在分配self当前引用的对象的属性(这通常是“当前实例”)
  2. foo = 1 在类块中创建正在定义的类的class属性
  3. def块中的
  4. foo = 1 正在创建正在定义的函数的局部变量
  5. 但你不应该那样记住它。他们只是特例:

    1. 指定像foo.bar.baz = 1这样的虚线名称正在写入对象的属性
    2. 分配给foo = 1之类的简单名称是写入最里面的封闭范围内的变量

答案 1 :(得分:2)

不,这意味着它是本地的。此外,您不想使用self.perimeter,因为它会使用相同的名称隐藏方法。

答案 2 :(得分:0)

在您的代码中,有两个名为perimeter的内容。一个是Polygon类的方法。另一个是该方法中的局部变量。您的代码中没有类属性。