В чем разница между атрибутами класса и экземпляра?
есть ли какое-либо значимое различие между:
class A(object):
foo = 5 # some default value
и
class B(object):
def __init__(self, foo=5):
self.foo = foo
Если вы создаете много экземпляров, есть ли разница в производительности или требования к пространству для двух стилей? Когда вы читаете код, считаете ли вы, что значение двух стилей значительно отличается?
6 ответов:
помимо соображений производительности, есть значительный семантический разницы. В случае атрибута class есть только один объект, на который ссылаются. В instance-attribute-set-at-instantiation может быть несколько объектов, на которые ссылаются. Например,
>>> class A: foo = [] >>> a, b = A(), A() >>> a.foo.append(5) >>> b.foo [5] >>> class A: ... def __init__(self): self.foo = [] >>> a, b = A(), A() >>> a.foo.append(5) >>> b.foo []
разница в том, что атрибут класса является общим для всех экземпляров. Атрибут экземпляра является уникальным для этого экземпляра.
Если исходить из C++, атрибуты в классе больше похожи на статические переменные-члены.
вот это очень хорошо post, и резюме его, как показано ниже.
class Bar(object): ## No need for dot syntax class_var = 1 def __init__(self, i_var): self.i_var = i_var ## Need dot syntax as we've left scope of class namespace Bar.class_var ## 1 foo = MyClass(2) ## Finds i_var in foo's instance namespace foo.i_var ## 2 ## Doesn't find class_var in instance namespace… ## So look's in class namespace (Bar.__dict__) foo.class_var ## 1и в наглядной форме
присвоение атрибутов класса
если атрибут класса установлен путем доступа к классу, он переопределит значение для все экземпляры
foo = Bar(2) foo.class_var ## 1 Bar.class_var = 2 foo.class_var ## 2если переменная класса задана путем доступа к экземпляру, она будет переопределена значение только для этого экземпляра. Это по существу переопределяет переменную класса и превращает ее в переменную экземпляра, доступную интуитивно,только для этого экземпляра.
foo = Bar(2) foo.class_var ## 1 foo.class_var = 2 foo.class_var ## 2 Bar.class_var ## 1когда бы вы использовали атрибут класса?
хранение констант. Как атрибуты класса могут быть доступны как атрибуты класса, его часто используют их для хранения Общеклассовые, специфичные для класса константы
class Circle(object): pi = 3.14159 def __init__(self, radius): self.radius = radius def area(self): return Circle.pi * self.radius * self.radius Circle.pi ## 3.14159 c = Circle(10) c.pi ## 3.14159 c.area() ## 314.159определение значений по умолчанию. Банальный пример, мы можем создать ограниченный список (т. е. список, который может содержать только определенное количество элементов или меньше) и выбрать шапку по умолчанию 10 товаров
class MyClass(object): limit = 10 def __init__(self): self.data = [] def item(self, i): return self.data[i] def add(self, e): if len(self.data) >= self.limit: raise Exception("Too many elements") self.data.append(e) MyClass.limit ## 10
поскольку люди в комментариях здесь и в двух других вопросах, отмеченных как dups, все, похоже, путаются в этом одинаково, Я думаю, что стоит добавить дополнительный ответ поверх Алекс Ковентри!--22-->.
тот факт, что Алекс присваивает значение изменяемого типа, как список, не имеет ничего общего с тем, являются ли вещи общими или нет. Мы можем видеть это с помощью
просто уточнение того, что сказал Алекс Ковентри, другой Алекс (Мартелли) обратился к аналогичному вопросу на
comp.lang.pythonгруппа Новостей лет назад. Он исследует семантическое различие того, что человек намеревался против того, что он получил (используя переменные экземпляра).http://groups.google.com/group/comp.lang.python/msg/5914d297aff35fae?hl=en
есть еще одна ситуация.
атрибуты класса и экземпляра - это дескриптор.
# -*- encoding: utf-8 -*- class RevealAccess(object): def __init__(self, initval=None, name='var'): self.val = initval self.name = name def __get__(self, obj, objtype): return self.val class Base(object): attr_1 = RevealAccess(10, 'var "x"') def __init__(self): self.attr_2 = RevealAccess(10, 'var "x"') def main(): b = Base() print("Access to class attribute, return: ", Base.attr_1) print("Access to instance attribute, return: ", b.attr_2) if __name__ == '__main__': main()выше будет выход:
('Access to class attribute, return: ', 10) ('Access to instance attribute, return: ', <__main__.RevealAccess object at 0x10184eb50>)один и тот же тип доступа к экземпляру через класс или экземпляр возвращает другой результат!
и я нашел в Си.Определение PyObject_GenericGetAttr,и многие post.
объяснить
если атрибут находится в словарь классов, которые составляют. объекты MRO, затем проверьте, указывает ли искомый атрибут на дескриптор данных (что не более чем класс, реализующий оба
__get__и__set__методов). Если это так, разрешите поиск атрибута, вызвав__get__метод дескриптора данных (строки 28-33).

Comments