def import_file(full_path_to_module):
try:
import os
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
save_cwd = os.getcwd()
os.chdir(module_dir)
module_obj = __import__(module_name)
module_obj.__file__ = full_path_to_module
globals()[module_name] = module_obj
os.chdir(save_cwd)
except:
raise ImportError
import_file('/home/somebody/somemodule.py')
Создавать файлы заголовков, которые содержат ТОЛЬКО то, что необходимо для использования модуля. В соответствующих файлах .c сделайте все, что не должно быть видимым снаружи (например, вспомогательные функции), статическим. Используйте префиксы в именах всего видимого извне, чтобы избежать конфликтов пространства имен. (Если модуль охватывает несколько файлов, все становится сложнее, так как вам может понадобиться раскрыть внутренние вещи и не удастся скрыть их с помощью "static")
(Если бы я попытался улучшить C, я бы сделал одну вещь это сделать "статическим" область видимости функций по умолчанию. Если вы хотите, чтобы что-то было видимым снаружи, вам нужно было бы пометить это как "экспорт", "глобальный" или что-то подобное.)
Статья Высокий и низкий уровень C содержит много хороших советов. В частности, обратите внимание на раздел « Классы и объекты ».
Стандарты и стиль для кодирования в ANSI C также содержат полезные советы, из которых вы можете выбирать.
Техники объектно-ориентированного программирования могут применяться к коду C. Они просто требуют большей дисциплины.
stdio
- все организовано вокруг непрозрачного дескриптора FILE *
. Многие успешные библиотеки организованы вокруг этого принципа (например, zlib , apr ) struct
s неявно общедоступны
в C вам потребуется соглашение + дисциплина программиста, чтобы применить полезную технику сокрытия информации . Выберите простое, автоматически проверяемое соглашение, такое как «закрытые члены заканчиваются на '_'». Подход, который использует Pidgin (ранее Gaim), заключается в том, что они создал структуру плагина
. Каждый плагин заполняет структуру функциями обратного вызова для инициализации и удаления, а также кучей другой описательной информации. Практически все, кроме структуры, объявлено как статическое, поэтому для связывания доступна только структура подключаемого модуля.
Затем, чтобы обработать слабую связь подключаемого модуля, взаимодействующего с остальной частью приложения (поскольку было бы неплохо, если бы это было что-то среднее между настройкой и разборкой) у них есть сигнализация. Плагины могут регистрировать обратные вызовы, которые будут вызываться при определенных сигналах (не стандартных сигналов C, а настраиваемых расширяемых типов [идентифицируемых строкой, вместо кодов набора]) выдаются любой частью приложения (включая другой плагин). Они также могут сами подавать сигналы.
Похоже, что это хорошо работает на практике - разные плагины могут опираться друг на друга, но связь довольно слабая - нет прямого вызова функций, все происходит через сигнальную систему.
Есть каталоги и файлы, но нет пространств имен или инкапсуляции. Вы можете скомпилировать каждый модуль в отдельный файл obj и связать их вместе (как библиотеки).
Разбивка кода на библиотеки связанных функций - один из способов сохранить порядок. Чтобы избежать конфликтов имен, вы также можете использовать префиксы, позволяющие повторно использовать имена функций, хотя с хорошими именами я никогда не считал это большой проблемой. Например, если вы хотите разработать свои собственные математические подпрограммы, но все еще используете некоторые из стандартной математической библиотеки, вы можете префикс своей некоторой строкой: xyz_sin (), xyz_cos ().
Обычно я предпочитаю одну функцию (или установить тесно связанных функций) на файл и один файл заголовка на соглашение об исходном файле. Разбивка файлов на каталоги, где каждый каталог представляет отдельную библиотеку, также является хорошей идеей. Вы'
Функция должна делать одно, а одно - хорошо.
Множество мелких функций, используемых более крупными функциями-оболочками, помогают структурировать код из небольших, простых для понимания (и тестирования!) Строительных блоков.
Создавайте небольшие модули с парой функций в каждом. Открывайте только то, что вы должны, оставьте все остальное статичным внутри модуля. Связывайте небольшие модули вместе с их интерфейсными файлами .h.
Предоставьте функции получения и установки для доступа к переменным статической области видимости файла в вашем модуле. Таким образом, переменные фактически записываются только в одном месте. Это также помогает отслеживать доступ к этим статическим переменным с помощью точки останова в функции и стеке вызовов.
Одно важное правило при разработке модульного кода: не пытайтесь оптимизировать, если вам не нужно. Множество мелких функций обычно приводят к более чистому, хорошо структурированный код и дополнительные накладные расходы на вызов функций могут того стоить.
Я всегда стараюсь сохранять переменные в самом узком диапазоне, в том числе внутри функций. Например, индексы циклов for обычно могут храниться в области видимости блока, и их не нужно предоставлять на уровне всей функции. C не так гибок, как C ++ с «определением его там, где вы его используете», но он работоспособен.