Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are properties class attributes in Python?

Tags:

python

I'm reading Fluent Python chapter 19 > A Proper Look at Properties, and I'm confused about the following words:

Properties are always class attributes, but they actually manage attribute access in the instances of the class.

The example code is:

class LineItem:

    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight  # <1>
        self.price = price

    def subtotal(self):
        return self.weight * self.price

    @property  # <2>
    def weight(self):  # <3>
        return self.__weight  # <4>

    @weight.setter  # <5>
    def weight(self, value):
        if value > 0:
            self.__weight = value  # <6>
        else:
            raise ValueError('value must be > 0')  # <7>

From my previous experiences, class attributes are belong to the class itself and shared by all the instances. But here, weight, the property, is an instance method and the value returned by it is different between instances. How is it eligible to be a class attribute? Doesn't it that all the class attributes should be the same for any instances?

I think I misunderstand something, so I hope to get a correct explanation. Thanks!

like image 390
Bicheng Avatar asked Sep 04 '18 09:09

Bicheng


1 Answers

A distinction is made because when you define a @property on a class, that property object becomes an attribute on the class. Whereas when you define attributes against an instance of your class (in your __init__ method), that attribute only exists against that object. This might be confusing if you do:

>>> dir(LineItem)
['__class__', ..., '__weakref__', 'subtotal', 'weight']

>>> item = LineItem("an item", 3, 1.12)
>>> dir(item)
['__class__', ..., '__weakref__', 'description', 'price', 'subtotal', 'weight']

Notice how both subtotal and weight exist as attributes on your class.

I think it's also worth noting that when you define a class, code under that class is executed. This includes defining variables (which then become class attributes), defining functions, and anything else.

>>> import requests

>>> class KindOfJustANamespace:
...     text = requests.get("https://example.com").text
...     while True:
...         break
...     for x in range(2):
...         print(x)
...
0
1
>>> KindOfJustANamespace.text
'<!doctype html>\n<html>\n<head>\n    <title>Example Domain...'

A @decorator is just "syntactic sugar". Meaning @property over a function if the same as function = property(function). This applies to functions defined inside a class as well, but now the function is part of the class's namespace.

class TestClass:
    @property
    def foo(self):
        return "foo"
    # ^ is the same as:
    def bar(self):
         return "bar"
    bar = property(bar)

A good explanation of property in Python can be found here: https://stackoverflow.com/a/17330273/7220776

like image 116
alxwrd Avatar answered Oct 04 '22 08:10

alxwrd