#python
Вопрос:
Я только начал работать с ООП в Python, и меня попросили создать класс с именем Square с определенным атрибутом position, который имеет тип tuple. Таким образом, для каждого квадратного объекта существует определенный метод его печати с учетом атрибута размера (печатает » # » размера*размер) и атрибута позиции (начинается с координат (x, y)), но когда у меня есть ошибка атрибута в методе инициализации, которая сообщает мне:
Ошибка атрибута: объект «Квадрат» не имеет атрибута «_Квадрат__позиция»
Вот код:
class Square:
''' create Square instance with public attributes
size and position '''
def __init__(self, size=0, position=(0, 0)):
self.size = size
self.position = position
''' retrieve size and make it private'''
@property
def size(self):
return self.__size
''' set private size attribute '''
@size.setter
def size(self, value):
if type(value) is not int:
raise TypeError("size must be an integer")
if value < 0:
raise ValueError("size must be >= 0")
self.__size = value
''' retrieve position and make it private '''
@property
def position(self):
return self.__position
''' set private position attribute '''
@position.setter
def position(self, value):
if value[0] < 0 or value[1] < 0:
raise TypeError("position must be a tuple of 2 positive integers")
self.__position[0] = value[0]
self.__position[1] = value[1]
''' calculates area of square '''
def area(self):
return self.__size ** 2
''' print a square of # the size of self.__size'''
def my_print(self):
if self.__size == 0:
print()
else:
for line in range(self.__position[1]):
print()
for i in range(self.__size):
for space in range(self.__position[0]):
print(" ", end="")
for j in range(self.__size):
print('#', end="")
print()
Любая помощь приветствуется, спасибо!
Комментарии:
1. Пожалуйста, опубликуйте всю обратную связь, чтобы мы видели поток.
2. У вас есть вторая проблема, связанная с первой. Кортежи неизменны. Ты хочешь
__position
быть кортежем? Если это так, то вы не можете этого сделатьself.__position[0] = value[0]
. Скорее всего, вы хотите простоself.__position = value
заняться сеттером. Но тогда почему это вообще должно быть собственностью?3. свойства стоят дороже, чем переменные экземпляра. Они полезны, если вы хотите запустить дополнительный код при получении или настройке (возможно, вы хотите проверить, что позиция является кортежем, прежде чем принимать ее). В противном случае они вам не понадобятся. «Частные» переменные могут быть проблематичными. При использовании 2 символов подчеркивания имя переменной искажается вместе с именем класса. Это затрудняет наследование.
4. Искажение имени (двойной префикс подчеркивания) не делает атрибут «частным». Нет способа сделать атрибут личным. Вместо этого используйте один префикс подчеркивания, чтобы указать, что атрибут не является общедоступным API.
Ответ №1:
Ваш __init__()
метод должен быть таким:
def __init__(self, size=0, position=(0, 0)):
self.__size = size #<-- dunder
self.__position = position #<-- dunder
Редактировать
Спасибо @tdelaney, который указал, что position
это кортеж, который не позволяет присваивать элементы. Итак, вы @position.setter
должны быть такими:
@position.setter
def position(self, value):
if type(value) != tuple or value[0] < 0 or value[1] < 0:
raise TypeError("position must be a tuple of 2 positive integers")
self.__position = value
Комментарии:
1. Я не могу поверить, что это было просто так. Поскольку я сделал атрибут закрытым с помощью установщика свойств, я подумал, что он может быть общедоступным в функции инициализации. Это сработало, спасибо!
2. @Anwarvic -Это, скорее всего, не ответ. Вы увидите сбой, если попытаетесь позже снова установить позицию — возможно, вы захотите переместить квадрат и сделать
square.position = (3,4)
это позже. Это не удастся. Как только вы это исправите, ваш оригинал__init__
также снова начнет работать.3. @tdelaney ты прав… давайте исправим это для него/нее.
4. Мне не нравится это решение, потому что вы все еще предлагаете использовать искажение имен без веской причины.
5. @wim — Я согласен, что это, скорее всего, не нужно, но я думаю, что это дизайнерское решение вне строгого ответа на вопрос. Ответы не обязательно должны касаться того, о чем не спрашивают.