Нужна ли в Python функция nonlocals() наряду с globals(), locals()?

Иногда удобно использовать функцию globals(). В примере ниже я создаю словарь функций, используя некоторые соглашения, а именно - первый символ имени функции должен совпадать с ключом:

def a_fun(c):
    print(c, 'from a_fun')


def b_fun(c):
    print(c, 'from b_fun')

def fun():
    fun_dict = dict.fromkeys({'a', 'b'})
    return {key: globals()[key + '_fun'] for key in fun_dict}

fun()['a'](33), fun()['b'](44)

код прекрасно себе работает и выдает:

33 from a_fun  
44 from b_fun

Но вот при описании класса так не получается. Мне удалось только так:

class fabric():

    def __a_fun(self, c):
        print(c, 'from __a_fun')


    def __b_fun(self, c):
        print(c, 'from __b_fun')

    def fun(self):
        # print(locals())
        # print(globals())
        return {'a': self.__a_fun, 'b': self.__b_fun}

z = fabric()

z.fun()['a'](33)

что дает

33 from __a_fun

Проблема в том, что __a_fun и __b_fun отсутствуюьт в словарях locals() и globals().
Подскажите, можно ли это реализовать по аналогии с первым примером? Идея в том, чтобы не менять код при добавлении очередного варианта обработки данных. Ну если что-то поменялось - я просто добавлю еще одну функцию в файл и не нужно менять в другом месте.
То есть вопрос об автоматическом заполнении словаря с функциями внутри класса.


Ответы (1 шт):

Автор решения: CrazyElf

Все названия методов класса можно достать из self.__class__.__dict__ и начинаться они там будут с self.__class__.__name__:

class fabric():

    def __a_fun(c):
        print(c, 'from __a_fun')

    def __b_fun(c):
        print(c, 'from __b_fun')

    def fun(self):
        fun_dict = dict.fromkeys({'a', 'b'})
        return {key: self.__class__.__dict__['_' + self.__class__.__name__ + '__' + key + '_fun'] for key in fun_dict}


z = fabric()

z.fun()['a'](33), z.fun()['b'](44)

Вывод:

33 from __a_fun
44 from __b_fun

Вариант, чтобы не прописывать словарь, а всё брать из класса:

    def fun(self):
        postfix = '_fun'
        cut = -len(postfix)
        return {k[cut-1:cut]: v for k,v in self.__class__.__dict__.items() if callable(v) and k.endswith(postfix)}
→ Ссылка