Как сделать список объектов? Экземпляр не имеет атрибута __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]
,
Они также очень эффективны, как память tuple
s, что может быть важно, если у вас будет много экземпляров классов.
Вы можете дополнительно специализировать то, что возвращается, подклассифицируя это, или использовать 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)