Descriptor protocol implementation of property()
<p>The Python <a href="https://docs.python.org/3.5/howto/descriptor.html#properties" rel="nofollow">descriptor How-To</a> describes how one could implement the <code>property()</code> in terms of descriptors. I do not understand the reason of the first if-block in the <code>__get__</code> method. Under what circumstances will <code>obj</code> be <code>None</code>? What is supposed to happen then? Why do the <code>__get__</code> and <code>__del__</code> methods not check for that?</p>

<p>Code is a bit lengthy, but it's probably better to give the full code rather than just a snippet. Questionable line is marked.</p>

<pre><code>class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        # =====&gt;&gt;&gt; What's the reason of this if block? &lt;&lt;&lt;=====
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
</code></pre>

<p>You can see what the effect is by making another version that leaves that test out.  I made a class Property that uses the code you posted, and another BadProperty that leaves out that <code>if</code> block.  Then I made this class:</p>

<pre><code>class Foo(object):
    @Property
    def good(self):
        print("In good getter")
        return "good"

    @good.setter
    def good(self, val):
        print("In good setter")

    @BadProperty
    def bad(self):
        print("In bad getter")
        return "bad"

    @bad.setter
    def bad(self, val):
        print("In bad setter")
</code></pre>

<p>The similarities and differences can be seen in this example:</p>

<pre><code>&gt;&gt;&gt; x = Foo()

# same
&gt;&gt;&gt; x.good
In good getter
'good'
&gt;&gt;&gt; x.bad
In bad getter
'bad'
&gt;&gt;&gt; x.good = 2
In good setter
&gt;&gt;&gt; x.bad = 2
In bad setter

# different!
&gt;&gt;&gt; Foo.good
&lt;__main__.Property object at 0x0000000002B71470&gt;
&gt;&gt;&gt; Foo.bad
In bad getter
'bad'
</code></pre>

<p>The effect of the <code>if</code> block is to return the raw property object itself if it is accessed via the class.  Without this check, the getter is called even when accessing the descriptor via the class.</p>

<p>The <code>__set__</code> and <code>__del__</code> methods do not need such a check, since the descriptor protocol is not invoke at all when setting/deleting attributes on a class (only on an instance).  This is not totally obvious from the documentation, but can be seen in the difference between the description of <code>__get__</code> vs. those of <code>__set__</code>/<code>__del__</code> in <a href="https://docs.python.org/3/reference/datamodel.html#object.__get__" rel="nofollow">the docs</a>, where <code>__get__</code> can get the attribute of "the owner class or an instance" but <code>__set__</code>/<code>__del__</code> only set/delete the attribute on an instance.</p>

python