Как сделать список объектов? Экземпляр не имеет атрибута __getitem__

Я новичок в Python и в ООП в целом. У меня ошибка "...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), и эти координаты должны быть "вызываемыми", как в экземпляре списка с [].

Я читал похожие темы, но не очень много понял. Пожалуйста, опишите это простыми словами и примерами.

3 ответа

Решение

Я предлагаю вам рассмотреть возможность создания вашего класса Point с использованием фабричной функции collection.namedtuple, которая сделает его подклассом встроенного tuple учебный класс. Это спасет вас от работы с котлом. namedtuple У класса есть атрибуты, к которым можно обращаться как по имени, такому как p.x и индексируется, как p[0],

Они также очень эффективны, как память tuples, что может быть важно, если у вас будет много экземпляров классов.

Вы можете дополнительно специализировать то, что возвращается, подклассифицируя это, или использовать verbose возможность захватить исходный код и изменить его при необходимости.

В документации, приведенной выше, есть пример, показывающий, что он используется для создания 2D Point класс, который, кажется, может быть очень полезным в вашем конкретном случае использования.

Вот пример, показывающий, как можно определить пользовательский класс 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__() метод. Единственная причина __init__() было необходимо из-за необходимости увеличить счетчик экземпляров класса, который был добавлен - то, что namedtupleне имеют или не делают по умолчанию.

Напиши __getitem__ метод:

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

Это создает tuple x, y и z, и использует собственные средства индексации 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]

Да, нужно определить __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)
Другие вопросы по тегам