RkMpNY5Y
RkMpNY5Y

Reputation: 21

Most pythonic way to store all readonly properties of a class in a list

I have a lot of properties, and

class ClassA:
    @property
    def func1(self):
        self.__string1 = "a"
        return self.__string1

    @property
    def func2(self):
        self.__string2 = "b"
        return self.__string2

    def func3(self):
        self.__list = [self.func1, self.func2]

seems redundant, especially when there are a lot of properties of a class. Is there a more compact way of doing this without having to list every single property?

Upvotes: 2

Views: 152

Answers (2)

LNiederha
LNiederha

Reputation: 948

For the use case you propose you might want to take a look at data classes which allow you to avoid a lot of boiler plate. It also allows you to make it read-only with a simple frozen argument. You could store all of your properties in a data class inside your class.

from dataclasses import dataclass

@dataclass(frozen = True)
class MyPropertyContainer():
    property1: str
    property2: float
    # ...

Such a class would allow you to store all your read only properties in a single object which is easily accessible. The only down side is that you would need to access those properties through an additional dot from outside the class: my_object.my_properties.property1 or you could write properties assessors for each properties if you want to avoid that (which I do not recommend).

Afterwards, you can get all your arguments as a dict. If you need to you can extract a list from that. Provided you defined the data class above, it would look as follow:

my_properties = MyPropertyContainer('aString', 12, ...)  # Instantiate what you want
properties_dict = my_properties.asDict()          # Get the dictionnary
properties_list = list(properties_dict.values())  # Dict to list

Based on the example you provided, a solution would be to rewrite your class as follow:


# Make a data class for private properties
@dataclass(frozen = True)
class PropertyContainer():
    func1: str
    func2: str

class A():
    
    # Since we're readonly we set the values on instanciation
    def __init__(self, func1_val, func2_val):
        self.properties = PropertyContainer(func1_val, func2_val)

    # Here we get the values from all readonly
    def func3(self):
         return list(self.properties.asDict().values())

    # You could also have sth like this for retro compatibility
    @property
    def func2(self):
        return self.properties.func1

Upvotes: 0

NoBlockhit
NoBlockhit

Reputation: 409

Use the __dict__ attribute and combine it with the isinstance method to filter out non property attributes:

> python
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec  6 2021, 19:10:37) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
...     not_a_property = None
...     @property
...     def func1():
...         return "string1"
...     @property
...     def func2():
...         return "string2"
...
>>> [p for p,v in A.__dict__.items() if isinstance(v, property)] 
['func1', 'func2']
>>>

Upvotes: 1

Related Questions