Как создать псевдоним всех методов объекта? - PullRequest
5 голосов
/ 28 марта 2019

Я создаю сценарий, который на самом деле является средой, в которой другие пользователи могут писать код.

Я объявил несколько методов в классе и создал экземпляр объекта, чтобы пользователи могли использовать эти методы как простые функции интерпретатора, например:

from code import interact

class framework:
    def method1(self, arg1):
    # code for method1
    def method2(self, arg2):
    # code for method2

def main():
    fw = framework()

    # Aliases
    method1 = fw.method1
    method2 = fw.method2

    interact(local=locals())

Поскольку я не хочу, чтобы пользователь вызывал методы с fw.method1(arg), я настроил псевдонимы. Проблема в том, что, поскольку класс инфраструктуры находится в стадии разработки, я должен постоянно обновлять основной скрипт новыми псевдонимами для методов, которые я создаю.

Есть ли простой способ избавиться от части "fw." в вызовах, и все методы в рамках класса автоматически отображаются в main?

Ответы [ 4 ]

4 голосов
/ 28 марта 2019

Вы управляете словарем, переданным в interact, поэтому поместите в него то, что вам нужно, не беспокоясь о локальных переменных в main:

d={}
for n in vars(framework):
  if n.startswith('_'): continue  # probably
  x=getattr(fw,n)
  if callable(x): d[n]=x
interact(local=d)

Это работает для обычных, статических и классовых методов.Он не видит атрибуты экземпляра (если они не скрывают атрибут класса) или унаследованные методы.

Первый имеет значение только в том случае, если экземпляр хранит функции как атрибуты (в этом случае вы можете или не хотите, чтобы они были доступны).Последнее удобно тем, что оно пропускает object;если есть другие базовые классы, их можно легко включить, выполнив поиск framework.__mro__ (и при этом пропустив object).

1 голос
/ 28 марта 2019

Я не знаю, что вы планируете делать с функциями, но если они не static, это вряд ли будет работать за пределами класса:

fs = [func for func in dir(c) if callable(getattr(c, func)) and not func.startswith("__")]
for func in fs:
    globals()[func] = getattr(c, func)

Это поместит все пользовательские функциив пределах класса c в глобальную область.

0 голосов
/ 28 марта 2019

Вот что-то похожее на ответ @Davis Herring, переработанный и переупакованный:

#from code import interact

def interact(local):
    local['method1'](42)
    local['method2']('foobar')


class Framework:
    def method1(self, arg1):
        print('Framework.method1({!r}) called'.format(arg1))
    def method2(self, arg2):
        print('Framework.method2({!r}) called'.format(arg2))


def get_callables(obj):
    return {name: getattr(obj, name) for name in vars(obj.__class__)
                if callable(getattr(obj, name))}

def main():
    fw = Framework()

#    # Aliases
#    method1 = fw.method1
#    method2 = fw.method2

    interact(local=get_callables(fw))


if __name__ == '__main__':
    main()

Вывод:

Framework.method1(42) called
Framework.method2('foobar') called
0 голосов
/ 28 марта 2019

Вы в основном хотите сделать две вещи:

  1. получить список методов экземпляра класса
  2. динамически добавлять функции в локальную область

Первое можно получить с помощью модуля inspect из стандартной библиотеки, второе - с помощью vars.

Попробуйте следующее:

import inspect

from code import interact

class framework:
    def method1(self, arg1):
    # code for method1
    def method2(self, arg2):
    # code for method2

def main():
    fw = framework()

    # get the methods of fw and update vars().
    # getmembers returns a list of two-tuples with (<Name>, <function>)
    methods = inspect.getmembers(fw, predicate=inspect.ismethod)
    vars().update({method[0]: method[1] for method in methods})

    interact(local=locals())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...