Using nested helper functions while building a class

77 views Asked by At

I want to build a class which is merely a wrapper for some data. This is the basic idea:

class Fruits:
    fruits = [ 'apple', 'orange', 'cherry' ]

My fruits aren’t strings, though, but classes defined earlier:

class Apple: pass
class Orange: pass
class Cherry: pass

class Fruits:
    fruits = [ Apple(), Orange(), Cherry() ]

My fruit classes are a bit more complex, though:

from dataclasses import dataclass

@dataclass
class Apple:
    color: str
    size: float
    price: float

Because my fruit-classes are quite complex, I need some helper functions to avoid massive code-doubling while calling the constructors:

class Fruits:

    @staticmethod
    def green_apple(size, price_factor=2.5):
        return Apple(color='green', size=size, price=size * price_factor)

    fruits = [ green_apple(3), green_apple(3, price_factor=1.2) ]

This far this works with static methods.

Now I would like to have one more layer of abstraction:

class Fruits:

    @staticmethod
    def green_apple(size, price_factor=2.5):
        return Apple(color='green', size=size, price=size * price_factor)

    @staticmethod
    def cheap_green_apple(size):
        return green_apple(size, price_factor=1.2)
        # alternative spelling:
        # return Fruits.green_apple(size, price_factor=1.2)

    fruits = [ green_apple(3), cheap_green_apple(3) ]

I did not find any way to achieve this yet. I understand why this is a problem: The second static method cannot call the first one before the class exists, and the class cannot exist before the fruits field hasn’t been built. There is no logical reason why one static method cannot call another one before the class exists, though. The methods are just scoped inside the class, they don’t use anything of the class; hence the building of the field fruits still works in the example one above.

The methods shall be wrapped in the wrapper class Fruits as users of this class are supposed to also use them. Putting them before the class (and repeating them within) would be an ugly solution, but it would clutter the outer scope, therefore I would like to avoid that.

So my question is not why this happens. I am asking for clever solutions to achieve what I want: Several fruit-classes (Apple, etc.) and a single wrapper class (Fruits) for providing all fruits in my scenario without cluttering the outer scope, while using a nested set of helper functions within the wrapper class.

Is there an option to achieve this? I tried several variants with static and class methods, but nothing worked yet.

1

There are 1 answers

3
Itération 122442 On

This looks like a case for a factory pattern.

An easy solution is to remove your object creation from the Fruits data holder and put it into a dedicated class, a factory.

A possible (quickly written) solution could be:

from dataclasses import dataclass

@dataclass
class Apple:
    color: str
    size: float
    price: float


class FruitFactory:
    @staticmethod
    def green_apple(size, price_factor=2.5):
        return Apple(color="green", size=size, price=price_factor)

class Fruits:
    def __init__(self):
        self.fruits = [FruitFactory.green_apple(1)]
    

fruits = Fruits()
print(fruits.fruits)