4

我是 Python 和一般 OOP 的新手。我有一个错误"...instance has no attribute '__getitem__'",我知道我创建的对象不是列表。我怎样才能成为一个列表对象。这是类文件:

#!/usr/bin/python -tt

import math, sys, matrix, os

class Point:
    'Class for points'
    pointCount = 0

    def __init__(self, x, y, z):
        'initialise the Point from three coordinates'
        self.x = x
        self.y = y
        self.z = z
        Point.pointCount += 1

    def __str__(self):
        'print the Point'
        return 'Point (%f, %f, %f)' %(self.x, self.y, self.z)

    def copyPoint(self, distance):
        'create another Point at distance from the self Point'
        return Point(self.x + distance[0], self.y + distance[1], self.z + distance[2])

    def __del__(self):
        'delete the Point'
        Point.pointCount -= 1
        #print Point.pointCount
        return '%s deleted' %self

我需要将它作为一个在(x,y,z)内部具有三个坐标的点,并且这些坐标必须是“可调用的”,就像在带有 [] 的列表实例中一样。

我读过类似的主题,但不太了解。请用简单的语言和例子来描述它。

4

3 回答 3

5

写一个__getitem__方法:

def __getitem__(self, item):
    return (self.x, self.y, self.z)[item]

这构造了tuplex、y 和 z 的 a,并使用 Python 自己的索引工具来访问它。

或者,您可以将自己的内部存储切换为元组,并为 x、y 和 z 创建属性:

def __init__(self, x, y, z):
    self.coords = (x, y, z)

@property
def x(self):  # sim. for y, z
    return self.coords[0]

def __getitem__(self, item):
    return self.coords[item]
于 2012-07-19T14:49:55.810 回答
0

我建议您考虑使用collections.namedtuple工厂函数创建您的 Point 类,这将使其成为内置类的子tuple类。这将为您节省一些样板工作。namedtuple类具有可以按名称访问的属性,例如p.x和索引,例如p[0].

它们也像tuples 一样非常节省内存,如果您要拥有很多类实例,这可能很重要。

您可以通过子类化来进一步专门化返回的内容,或者使用该verbose选项来捕获源代码并根据需要进行修改。

上面链接的文档中有一个示例显示它用于创建 2DPoint类,这似乎对您的特定用例非常有帮助。

这是一个示例,展示了如何通过子类化定义自定义 3D Point 类:

from collections import namedtuple

class Point(namedtuple('Point', 'x y z')):
    __slots__ = ()  # prevent creation of instance dictionaries to save memory
    point_count = 0  # instance counter

    def __init__(self, *args):
        super(Point, self).__init__(*args)
        Point.point_count += 1

    def distance(self, other):
        return sum((self[i]-other[i])**2 for i in xrange(len(self))) ** 0.5

    def copy_point(self, distance):
        'create another Point at distance from the self Point'
        return Point(*[dimension+distance for dimension in self])

p1 = Point(0, 0, 0)
print 'p1:', p1
p2 = p1.copy_point(20)
print 'p2: Point(%s)' % ', '.join(str(p2[i]) for i in xrange(len(p2)))
print 'distance p1 <-> p2: %.3f' % p1.distance(p2)

输出:

p1: Point(x=1, y=2, z=3)
p2: Point(21, 22, 23)
distance p1 <-> p2: 34.641

请注意,通过使用namedtuple您不必__getitem__()自己实现,也不必编写__str__()方法。需要an 的唯一原因__init__()是需要增加已添加的类实例计数器——这是namedtuple默认情况下没有或没有的。

于 2012-07-19T16:17:15.433 回答
0

是的,您需要定义__getitem__,但我可能会按如下方式设计类,它允许属性和索引访问坐标。

from collections import namedtuple

class Point(object):
    def __init__(self, x, y, z):
        self._coords = namedtuple('Coords', 'x y z')._make( (x, y, z) )

    @property
    def coords(self):
        return self._coords

    def __getitem__(self, item):
        return self.coords[item]

    def copy_point(self, distance):
        return Point(*(el + distance for el in self.coords))

    def __repr__(self):
        return 'Point: {}'.format(self.coords)

p = Point(1, 2, 3)
p.copy_point(20), p.coords[0], p.coords.x
# (Point: Coords(x=21, y=22, z=23), 1, 1)
于 2012-07-19T15:14:56.807 回答