Question: I have a python class which has several properties. I want to implement a method which will return some properties as a dict. I want to mark the properties with a decorator. Here's an example: class Foo: @export_to_dict # I want to add this property to dict @property def bar1(self): return 1 @property # I don't want to add this propetry to dict def bar2(self): return {"smth": 2} @export_to_dict # I want to add this property to dict @property def bar3(self): return "a" @property def bar4(self): return [2, 3, 4] def to_dict(self): return ... # expected result: {"bar1": 1, "bar3": "a"}  One way to implement it is to set an additional attribute to the properties with the export_to_dict decorator, like this: def export_to_dict(func): setattr(func, '_export_to_dict', True) return func  and to search for properties with the _export_to_dict attribute when to_dict is called. Is there another way to accomplish the task?

Answer: Marking each property forces to_dict to scan all methods/attributes on each invocation, which is slow and inelegant. Here's a self-contained alternative that keeps your example usage identical. Keep a list of exported properties in a class attribute By making export_to_dict a class, we can use __set_name__ (Python 3.6+) to get a reference of the Foo class and add a new attribute to it. Now to_dict knows exactly which properties to extract, and because the list is per-class, you can annotate different classes without conflict. And while we're at it, we can make export_to_dict automatically generate the to_dict function to any class that has exported properties. The decorator also restores the original property after the class is created, so the properties work as normal without any performance impact. class export_to_dict: def __init__(self, property): self.property = property def __set_name__(self, owner, name): if not hasattr(owner, '_exported_properties'): owner._exported_properties = [] assert not hasattr(owner, 'to_dict'), 'Class already has a to_dict method' owner.to_dict = lambda self: {prop.__name__: prop(self) for prop in owner._exported_properties} owner._exported_properties.append(self.property.fget) # We don't need the decorator object anymore, restore the property. setattr(owner, name, self.property) class Foo: @export_to_dict # I want to add this property to dict @property def bar1(self): return 1 @property # I don't want to add this propetry to dict def bar2(self): return {"smth": 2} @export_to_dict # I want to add this property to dict @property def bar3(self): return "a" @property def bar4(self): return [2, 3, 4] # to_dict is not needed anymore here! print(Foo().to_dict()) {'bar1': 1, 'bar3': 'a'}  If you don't want to your Foo class to have an extra attribute, you can store the mapping in a static dict export_to_dict.properties_by_class = {class: [properties]}.  Properties with setters If you need to support property setters, the situation is a bit more complicated but still doable. Passing property.setter through is not sufficient, because the setter replaces the getter and __set_name__ is not called (they have the same name, after all). This can be fixed by splitting the annotation process and creating a wrapper class for property.setter. class export_to_dict: # Used to create setter for properties. class setter_helper: def __init__(self, setter, export): self.setter = setter self.export = export def __set_name__(self, owner, name): self.export.annotate_class(owner) setattr(owner, name, self.setter) def __init__(self, property): self.property = property @property def setter(self): return lambda fn: export_to_dict.setter_helper(self.property.setter(fn), self) def annotate_class(self, owner): if not hasattr(owner, '_exported_properties'): owner._exported_properties = [] assert not hasattr(owner, 'to_dict'), 'Class already has a to_dict method' owner.to_dict = lambda self: {prop.__name__: prop(self) for prop in owner._exported_properties} owner._exported_properties.append(self.property.fget) def __set_name__(self, owner, name): self.annotate_class(owner) # We don't need the decorator object anymore, restore the property. setattr(owner, name, self.property) class Foo: @export_to_dict # I want to add this property to dict @property def writeable_property(self): return self._writeable_property @writeable_property.setter def writeable_property(self, value): self._writeable_property = value foo = Foo() foo.writeable_property = 5 print(foo.to_dict()) {'writeable_property': 5}