Подтвердить что ты не робот

Объекты Python - исключение создания атрибута с неизвестным именем

Желая избежать такой ситуации:

>>> class Point:
x = 0
y = 0
>>> a = Point()
>>> a.X = 4 #whoops, typo creates new attribute capital x

Я создал следующий объект, который будет использоваться в качестве суперкласса:

class StrictObject(object):
    def __setattr__(self, item, value):
        if item in dir(self):
            object.__setattr__(self, item, value)
        else:
            raise AttributeError("Attribute " + item + " does not exist.")

Пока это работает, документация python описывает dir():

Примечание: Поскольку dir() предоставляется в основном как удобство для использования в интерактивном приглашении, он пытается чтобы предоставить интересный набор имен больше, чем он пытается предоставить строго или последовательно определенный набор имен, а его подробное поведение может измениться в разных версиях. Например, атрибуты metaclass не входят в список результатов, когда аргумент является классом.

Есть ли лучший способ проверить, есть ли у объекта атрибут?

4b9b3361

Ответ 1

Значительно лучшие способы.

Самый распространенный способ - "мы все соглашаемся с взрослыми". Это означает, что вы не делаете никаких проверок, и вы оставляете его пользователю. Любая проверка, сделанная вами, делает код менее гибким в использовании.

Но если вы действительно этого хотите, в Python 3.x по умолчанию используется __slots__, а для классов нового стиля в Python 2.x:

По умолчанию экземпляры как старых, так и новых классов имеют словарь для хранения атрибутов. Это освобождает пространство для объектов, имеющих очень мало переменных экземпляра. Расход пространства может стать острой при создании большого количества экземпляров.

Значение по умолчанию можно переопределить, определяя __slots__ в определении класса нового стиля. Объявление __slots__ принимает последовательность переменных экземпляра и резервирует достаточно места в каждом экземпляре для хранения значения для каждой переменной. Пробел сохраняется, потому что для каждого экземпляра не создается __dict__.

Без переменной __dict__ экземпляры не могут назначаться новые переменные, не перечисленные в определении __slots__. Попытки назначить имя переменной без имени повышают AttributeError. Если требуется динамическое назначение новых переменных, добавьте '__dict__' в последовательность строк в объявлении __slots__.

Например:

class Point(object):
    __slots__ = ("x", "y")

point = Point()
point.x = 5 # OK
point.y = 1 # OK
point.X = 4 # AttributeError is raised

И, наконец, правильный способ проверить, имеет ли объект определенный атрибут, не использовать dir, а использовать встроенную функцию hasattr(object, name).

Ответ 2

Я не думаю, что это хорошая идея написать код, чтобы предотвратить такие ошибки. Эти "статические" проверки должны быть заданием вашей среды IDE. Pylint предупредит вас о назначении атрибутов за пределами __init__, тем самым предотвращая ошибки typo. Он также показывает много других проблем и потенциальных проблем, и его можно легко использовать из PyDev.

Ответ 3

В такой ситуации вы должны посмотреть, что может предложить вам стандартная библиотека python. Вы считали namedtuple?

from collections import namedtuple

Point = namedtuple("Point", "x, y")

a = Point(1,3)

print a.x, a.y

Поскольку точка теперь неизменна, ваша проблема просто не может произойти, но обратная связь, естественно, вы не можете, например. просто добавьте +1 к a, но вам нужно создать полный новый экземпляр.

x,y = a
b = Point(x+1,y)