Можно ли импортировать модуль и выполнить все в контексте импортирующего модуля? - PullRequest
0 голосов
/ 06 июля 2018

Предположим, у меня есть пакет, содержащий два модуля moduleA и moduleB. Оба должны предоставлять две функции манипуляции со строками в виде интерфейса manipulate и undo_manipulation, однако они должны различаться в деталях манипуляции.

Допустим, я хочу, чтобы manipulate из moduleA заменил все экземпляры "i" на "u", переместил первую букву в конец, а затем заглавную первую букву:

>>>moduleA.manipulate("string")
'Trungs'

В moduleB, с другой стороны, он должен заменить "r" на "w", переместить первую букву в конец, затем поменять местами первые и вторые буквы и затем использовать заглавные буквы:

>>>moduleB.manipulate("string")
'Wtings'

Например, я бы реализовал moduleA как:

to_replace = {"i": "u"}

def manipulate(string):
    for key, value in to_replace.items():
        string = string.replace(key, value)
    string = move_letter(string)
    return capitalise(string)

def move_letter(string):
    return string[1:]+string[0]

def capitalise(string):
    return string[0].upper()+string[1:]

(для простоты я предполагаю, что ввод всегда не менее 3 символов)

Теперь, что я хотел бы сделать для moduleB, это позволить ему просто «наследовать» все moduleA и затем переопределить детали (то есть определить новые to_replaced и move_letter). Тогда пользователь должен иметь возможность вызвать moduleB.manipulate, и он вызовет импортированную функцию, только тогда он будет использовать обновленный контекст. Итак, в основном:

from moduleA import manipulate, move_letter, capitalise
# second import necessary if I want to access the original version of move_letter
from . import moduleA

to_replace{"r": "w"}

def move_letter(string):
    newstring = moduleA.move_letter(string)
    return newstring[1]+newstring[0]+newstring[2:]

(Очевидно, что манипуляции, которые я на самом деле хочу сделать, являются немного более сложными; но они также могут быть разбиты на более атомарные части, из которых только некоторые должны быть переопределены «дочерними» модулями)

К сожалению, это не работает. Если пользователь вызывает moduleB.manipulate, он использует moduleA версии to_replace и move_letter, а не обновленные версии moduleB.

Есть ли способ обойти это? Или, другими словами, есть ли способ эмулировать наследование объектов только с помощью модулей, без использования классов?

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

  • задачи (manipulate и undo_manipulation, которые я упустил из вышеприведенного кода для простоты), кажутся гораздо более «глаголами-у», чем «существительными-у».
  • нет никакого изменяющегося состояния вообще, так что в действительности нет никакого смысла в создании экземпляра.
  • использование объекта добавляет еще один слой точечной нотации, который на самом деле не добавляет никакой новой информации. Таким образом, извне пакета пользователь должен будет использовать по крайней мере имя из трех частей: package.module.Class (по крайней мере, если они не делают from package import..., что также становится громоздким, если у него есть более двух или трех отдельных модулей для импорта).

По этим причинам я действительно хотел бы избежать использования классов, если это вообще возможно. Или, если нет, я бы, по крайней мере, нашел бы способ скрыть слой класса от интерфейса, чтобы сэкономить пользователю набор текста.

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