__setattr__ взломать код?

Вот код, который у меня есть

class Human(object):
  def __init__(self, name, gender):
    self.name = name
    self.gender = gender
    print 'Hi there, I am '+ self.name

  def ThankHeavens(self):
    return 'Thanks Gods!'

class Soldier(Human):
  def __init__(self, name, gender, rank):
    super(Soldier, self).__init__(name, gender)
    self.rank = rank
    print self.rank + ' reporting!'

class Officer(Soldier):
  def __init__(self, name, gender, rank, num_subordinates):
    super(Officer, self).__init__(name, gender, rank)
    self.num_subordinates = num_subordinates

  def __setattr__(self, rank, value):
    if rank not in ['lieutenant', 'captain', 'major', 'colonel', 'commander', 'admiral']:
      print 'Invalid officer rank'
    else:
      super(Officer, self).__setattr__(rank, value)

Это ломается всякий раз, когда я пытаюсь создать офицера:

helo = Officer(name='Agathon',
               gender='m',
               rank='lieutenant',
               num_subordinates=0)

Traceback (most recent call last):
  File "hw7.py", line 39, in <module>
    num_subordinates=0)
  File "hw7.py", line 20, in __init__
    super(Officer, self).__init__(name, gender, rank)
  File "hw7.py", line 14, in __init__
    super(Soldier, self).__init__(name, gender)
  File "hw7.py", line 7, in __init__
    print 'Hi there, I am '+ self.name
AttributeError: 'Officer' object has no attribute 'name'

Почему он не распознает имя, которое я ввел при определении helo?

2 ответа

То, что вы не опубликовали, это два сообщения, созданные вашим __setattr__:

Invalid officer rank
Invalid officer rank

Это происходит из следующих строк:

self.name = name
self.gender = gender

Так как они терпят неудачу, вы не можете получить имя позже:

 print 'Hi there, I am '+ self.name

Fix:

def __setattr__(self, key, value):
    if key == "rank" and value not in [.....]

Ваш __setattr__ вызывается, когда любой атрибут Officer устанавливается в любое время любым способом, в том числе при инициализации через суперкласс __init__,

когда __setattr__ называется, self будет Officer пример, rank будет именем устанавливаемого атрибута, и value будет значение, требуемое для того, чтобы приписать.

Что вы сделали, это сделать Officer класс такой, что он может иметь .lieutenant и т.д. для значений в вашем списке, но не .rank (или же .name или же .gender) - и вы вообще не ограничивали значение этого атрибута.

Это более глубокая магия, чем вы искали; Вы явно хотели ограничить значения, используемые при настройке .rankприписывать конкретно. Для этого используйте свойство.

Другие вопросы по тегам