Проверьте, есть ли метод уже в экземпляре в объекте?

#python #class #oop #attributes #instance

#python #класс #ооп #атрибуты #экземпляр

Вопрос:

Я пытаюсь выяснить, существует ли уже экземпляр атрибута для моего объекта. Как вы можете видеть ниже, я хочу что-то сделать, если мой Dog объект имеет определенный атрибут, с помощью do_something_if_has_aged метода. Как я могу проверить, был ли уже объявлен определенный атрибут? Обычно вы проверяете наличие чего-то подобного, что возвращает False :

 obj = None
if obj:
    print(True)
else:
    print(False)
 

Вот мой минимальный воспроизводимый пример:

 >>> class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def add_years(self, years):
        self.age  = years
        self.has_aged = True
    def do_something_if_has_aged(self):
        if self.has_aged:
            print("The dog has aged and is %d years closer to death" % self.years)
        else:
            print("The dog hasn't aged, apparently.")


>>> dog = Dog('Spot', 3)
>>> dog.age
3
>>> dog.do_something_if_has_aged()
Traceback (most recent call last):
  File "<pyshell#193>", line 1, in <module>
    dog.do_something_if_has_aged()
  File "<pyshell#190>", line 9, in do_something_if_has_aged
    if not self.has_aged:
AttributeError: 'Dog' object has no attribute 'has_aged'
>>> dog.add_years(1)
>>> dog.age
4
>>> dog.do_something_if_has_aged()
The dog hasn't aged, apparently.
 

Очевидно, что собака постарела.

Я прошу прощения, если заголовок не отражает то, что я пытаюсь передать ниже; Я новичок в ООП.

Комментарии:

1. Ваше условие неправильное: вы должны сделать if self.has_aged .

Ответ №1:

Похоже, вы ищете hasattr встроенную функцию:

 >>> class Dog(object):
...     pass
...
>>> a = Dog()
>>> hasattr(a, 'age')
False
>>> a.age = 7
>>> hasattr(a, 'age')
True
 

В вашем случае вы можете изменить следующим образом:

 def do_something_if_has_aged(self):
    if hasattr(self, 'has_aged'):
        pass # do your logic
 

Ответ №2:

Вместо проверки атрибута установите значение по умолчанию для класса; если атрибут экземпляра отсутствует, Python вместо этого ищет атрибут класса:

 class Dog:
    has_aged = False  # default for all instances
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def add_years(self, years):
        self.age  = years
        self.has_aged = True  # sets an instance attribute
    def do_something_if_has_aged(self):
        if self.has_aged:
            print("The dog has aged and is %d years closer to death" % self.years)
        else:
            print("The dog hasn't aged, apparently.")
 

(обратите внимание, что мне пришлось инвертировать ваш тест, если self.has_aged верно, что вы хотите перейти в первую ветвь, а не наоборот).

Или вы можете установить значение по умолчанию для атрибута в __init__ :

 class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.has_aged = False
    def add_years(self, years):
        self.age  = years
        self.has_aged = True
    def do_something_if_has_aged(self):
        if self.has_aged:
            print("The dog has aged and is %d years closer to death" % self.years)
        else:
            print("The dog hasn't aged, apparently.")
 

Вы также можете проверить, присутствует ли атрибут в hasattr() функции:

 def do_something_if_has_aged(self):
    if hasattr(self 'has_aged') and self.has_aged:
        print("The dog has aged and is %d years closer to death" % self.years)
    else:
        print("The dog hasn't aged, apparently.")
 

или с помощью getattr() функции со значением по умолчанию:

 def do_something_if_has_aged(self):
    if not getattr(self 'has_aged', False):
        print("The dog has aged and is %d years closer to death" % self.years)
    else:
        print("The dog hasn't aged, apparently.")
 

Однако динамическое тестирование атрибутов не должно быть первым выбранным вами вариантом; наличие класса по умолчанию намного чище.

Комментарии:

1. В чем преимущество has_aged того, чтобы быть переменной класса, а не переменной экземпляра (определенной в __init__ )?

2. @JosieThompson: существует только одна копия переменной (что дает преимущество в памяти); зачем присваивать всем экземплярам атрибут, когда значение по умолчанию может быть просто сохранено в классе?

Ответ №3:

Я бы переписал __init__ метод для включения self.has_aged = False , чтобы избежать необходимости проверки:

 class Dog(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.has_aged = False # Starting value so it is guaranteed to be defined (unless explicitly deleted).
 

Теперь остальная часть вашего класса должна работать так, как написано. Однако, если вы хотите узнать, был ли определен атрибут для объекта, вы можете написать это:

 class Foo(object):
    def set_bar(self):
        self.bar = True # Define the attribute bar if it is not yet defined.

    def is_bar_set(self):
        return hasattr(self, 'bar')
 

Ответ №4:

Чтобы проверить hasattr , подходит ли using, но на случай, если вы ищете быстрое исправление для своего кода, вы можете инициализировать переменную как false перед рукой:

 class Dog:
  has_aged = False
 

а также исправить ваше состояние, поскольку я думаю, что оно должно быть обращено вспять:

 def do_something_if_has_aged(self):
  if self.has_aged:    # instead of not self.has_aged
    print("The dog has aged and is %d years closer to death" % self.years)
  else:
    print("The dog hasn't aged, apparently.")