Python property deleter

Learn how Python property deleter works with @property, @name.setter, and @name.deleter, including how del obj.attr calls the deleter method and common mistakes.

Published

Updated

Read time 5 min read

Reviewed byDeepak Prasad

Python property deleter

A Python property deleter is the method that runs when you delete a managed attribute with del obj.attr (or the equivalent delattr). Below I walk through @property, @name.setter, and @name.deleter, show the small Student pattern end-to-end, then the older property(fget, fset, fdel) spelling and a short mistake list. For classes in general, see the Python class example page first if decorators feel new.

I keep generic decorator theory short and stick to what runs when you delete the public attribute.

Tested on: Python 3.13.3; kernel 6.14.0-37-generic.


What is a deleter in Python?

For a property, the deleter is the optional third leg: when you execute del instance.attr, Python does not simply wipe an instance dict entry for you; it calls the function you wired as fdel / @attr.deleter. That method typically deletes the private backing attribute (for example del self._name). The property object on the class remains; only the per-instance storage you chose to manage goes away—until you assign through the setter again.

Here is the smallest useful shape: del box.label runs the method under @label.deleter, which clears _label.

python
class Box:
    def __init__(self, label):
        self._label = label

    @property
    def label(self):
        return self._label

    @label.deleter
    def label(self):
        print("deleter ran")
        del self._label


box = Box("inbox")
del box.label
Output

You should see deleter ran once. After that, reading box.label would fail until you add storage again (for example with a setter).


Python property getter, setter, and deleter

Together they give you one public name with three behaviors:

  • Getter (@property): read obj.name.
  • Setter (@name.setter): assign obj.name = value.
  • Deleter (@name.deleter): run custom logic when someone writes del obj.name.

Under the hood this is still the built-in property type; the decorators are syntactic sugar on top of ordinary Python classes.


Create a property using @property

Start with read-only access to a backing attribute you control (by convention _name, one leading underscore). The backing field is usually set in __init__ before the property manages reads and writes.

python
class Student:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name


s = Student("Alice")
print(s.name)
Output

You should see Alice. There is no setter yet, so s.name = "Bob" would raise AttributeError: can't set attribute until you add one.


Add a setter using @name.setter

The setter must follow the getter and reuse the same method name.

python
class Student:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value


s = Student("Alice")
s.name = "Bob"
print(s.name)
Output

You should see Bob.


Add a deleter using @name.deleter

Attach the deleter to the same property name. Inside, delete the backing field you actually store—not a bare del self.name (that would recurse into the deleter again).

python
class Student:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @name.deleter
    def name(self):
        del self._name


student = Student("Alice")
del student.name
try:
    print(student.name)
except AttributeError:
    print("name is gone until you assign again")
Output

You should see name is gone until you assign again. After del student.name, the getter no longer finds _name; assigning student.name = "Carol" would go through the setter and recreate _name.


How del obj.attr calls the deleter

When Python handles del student.name, it resolves name on the class, finds a property with an fdel, and calls that deleter function with self bound to student. The same hook runs when you use delattr(student, "name") or student.__delattr__("name") on the usual deletion paths described in the data model.

All three spellings below end up invoking the same deleter on three fresh instances:

python
class Tag:
    def __init__(self):
        self._code = "x"

    @property
    def code(self):
        return self._code

    @code.deleter
    def code(self):
        del self._code


def read_code(obj, label):
    try:
        obj.code
    except AttributeError:
        return f"{label}: backing gone"
    return f"{label}: still there"


a, b, c = Tag(), Tag(), Tag()
del a.code
delattr(b, "code")
c.__delattr__("code")
print(read_code(a, "del obj.attr"))
print(read_code(b, "delattr"))
print(read_code(c, "__delattr__"))
Output

You should see three lines ending with backing gone, one for each of del obj.attr, delattr, and __delattr__. That is the same fdel path in all three cases.


property() function with fget, fset, and fdel

Before decorator syntax, people passed callables into property(). It is the same object you get from @property; use whichever style your team agrees on.

python
class Student:
    def __init__(self, name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self, value):
        self._name = value

    def delete_name(self):
        del self._name

    name = property(get_name, set_name, delete_name)


s = Student("Dan")
print(s.name)
del s.name
try:
    print(s.name)
except AttributeError:
    print("deleted via property() form")
Output

You should see Dan then deleted via property() form. The official property signature documents fget, fset, fdel, and doc.


Common mistakes with property deleter

  • Deleting the wrong storage inside the deleter—for example del self.name instead of del self._name, which recurses or targets the wrong object.
  • Adding @name.deleter before you define @property for name—the deleter decorator hangs off the property object created by the getter.
  • Calling person.name() like a method—access is person.name without parentheses.
  • Thinking del removes the property from the class—it clears the managed slot you implement, not the descriptor on Student.__dict__.
  • Reading the property immediately after delete without catching AttributeError or reassigning first.
  • Defaulting to double-underscore mangling (__name) for “privacy” when a single _name is clearer for deleters and subclasses.
  • Wrapping every public field in property when a plain attribute would stay simpler.

Python property deleter quick reference table

Need What you write
Managed read @property + def name(self): ...
Managed write @name.setter + def name(self, value): ...
Managed delete @name.deleter + def name(self): del self._name
User deletes value del obj.name
Delete by dynamic string delattr(obj, "name")
Backing field convention self._name (one underscore)
Read after delete Expect AttributeError until you assign again
Older style name = property(get, set, delete)

Summary

A property deleter is the fdel you attach with @name.deleter (or the third argument to property). When someone runs del obj.name, Python calls that deleter so you can drop your backing storage—typically del self._name—while the property descriptor itself stays on the class. Pair getter, setter, and deleter on the same public name, keep one consistent storage attribute, and reserve this pattern for when you truly need validation or deletion side effects; otherwise a normal attribute stays easier to read.


References


Frequently Asked Questions

1. What runs when I write del obj.name on a property?

Python calls the function you registered with @name.deleter (or the fdel argument to property()); that method usually removes the backing storage such as del self._name, while the property object on the class stays defined.

2. Do I need a getter before I can add @name.setter or @name.deleter?

Yes—the @property getter must exist first because setter and deleter decorators attach to that property name on the class.

3. Is property() with fget, fset, fdel the same as @property?

It is the same machinery: decorator syntax builds a property object from your methods; the explicit property(getter, setter, deleter) form is the older spelling you still see in some codebases.

4. Why use a single leading underscore for _name instead of double underscore?

A single underscore is the usual “internal but not mangled” convention; double leading underscores trigger name mangling and make deleter and subclass stories harder to reason about unless you really want that behavior.
Bashir Alam

Data Analyst and Machine Learning Engineer

Computer Science graduate from the University of Central Asia, currently employed as a full-time Machine Learning Engineer at uExel. His expertise lies in OCR, text extraction, data preprocessing, and …