Объекты Python - избегая создания атрибута с неизвестным именем - PullRequest
13 голосов
/ 10 марта 2012

Желая избежать ситуации, подобной этой:

>>> 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.")

Хотя это, кажется, работает, питон *В документации 1007 * говорится о dir():

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

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

Ответы [ 3 ]

16 голосов
/ 10 марта 2012

Гораздо лучшие способы.

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

Но если вы действительно хотите это сделать, в 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 голосов
/ 10 марта 2012

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

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)
2 голосов
/ 10 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...