Является ли "импорт модуля" лучшим стилем кодирования, чем "из функции импорта модуля"?
пусть from module import function можно назвать стиль кодирования FMIF.
пусть import module называется стилем кодирования IM.
пусть from package import module называется стилем кодирования FPIM.
почему IM + FPIM считается лучшим стилем кодирования, чем FMIF? (См. этот пост для вдохновения для этого вопроса.)
вот некоторые критерии, которые заставляют меня предпочесть FMIF над IM:
- краткость кода: это позволяет мне использовать более короткие имена функций и таким образом помогите придерживаться соглашения 80 столбцов на строку.
- читаемость:
chisquare(...)выглядит более читаемым, чемscipy.stats.stats.chisquare(...). Хотя это субъективный критерий, я думаю, что большинство людей согласятся.
- простота перенаправления: если я использую FMIF и по какой-то причине позже хочу перенаправить python для определения
functionСalt_moduleвместоmoduleмне нужно изменить только одну строку:from alt_module import function. Если бы я использовал IM, мне нужно было бы изменить много строк кода.
Я поймите, что FPIM каким-то образом сводит к нулю первые две проблемы, но как насчет третьего?
меня интересуют все причины, почему IM + FPIM может быть лучше, чем FMIF,
но в частности, я был бы заинтересован в разработке следующих пунктов, упомянутых здесь:
плюсы для IM:
- легкость издеваться / впрыскивать в тестах. (Я не очень хорошо знаком с насмешками, хотя недавно узнал, что означает этот термин. Можете ли вы показать код, который демонстрирует, как им лучше FMIF здесь?)
- возможность гибкого изменения модуля путем переопределения некоторых записей. (Я, должно быть, что-то недопонимаю, потому что это, похоже, преимущество FMIF над IM. См. мою третью причину в пользу FMIF выше.)
- предсказуемое и контролируемое поведение при сериализации и восстановлении ваших данных. (Я действительно не понимаю, как выбор IM или FMIF влияет на эту проблему. Пожалуйста, уточните.)
- я понимаю, что FMIF "загрязняет мой пространство имен", но помимо того, что это отрицательно звучащая фраза, Я не понимаю, как это вредит коду каким-либо конкретным образом.
ПС. При написании этого вопроса я получил предупреждение о том, что вопрос кажется субъективным и, скорее всего, будет закрыт. Пожалуйста, не закрывай его. Я не ищу субъективного мнения, а скорее конкретных ситуаций кодирования, где IM+FPIM явно лучше, чем FMIF.
большое спасибо.
5 ответов:
негативы, которые вы перечисляете для IM / FPIM, часто могут быть улучшены соответствующим использованием
asпредложения.from some.package import mymodulewithalongname as mymodможно бы сократить код и повысить его читаемость, и при переименованииmymodulewithalongnameдоsomethingcompletelydifferentзавтраasпредложение может быть использовано в качестве одного оператора для редактирования.рассмотрим вашу точку pro-FMIF 3 (назовите ее R для перенаправления) против вашей точки pro-FPIM 2 (назовите ее F для гибкости): R означает облегчение потери целостности границ модуля, в то время как F укрепляет его. Множество функций, классов и переменных в модуле часто предназначены для совместной работы: они не должны быть независимо переключены на разные значения. Например, рассмотрим модуль
randomи его функцииseedиuniform: если бы вы переключили импорт только одного из них в другой модуль, то вы бы разорвали нормальное соединение между вызовамиseedи результаты звонков вuniform. Когда модуль был спроектирован с согласия и целостности, R облегчение разрушения границ модуля на самом деле является отрицательным-это облегчает выполнение чего-то, что вам лучше не делаешь.наоборот, F-это то, что позволяет скоординированных переключение связанных функций, классов и переменных (так, как правило, сущностей, которые принадлежат вместе, модульность). Например, чтобы сделать тестирование повторяемым (FPIM pro-point 1), Вы издеваетесь над обоими
seedиrandomнаrandomмодуль, и если ваш код следует за FPIM, вы все настроены, координация гарантирована; но если у вас есть код, который импортировал функции напрямую, вам нужно выследить каждый такой модуль и повторять насмешку снова и снова. Чтобы сделать тесты идеально повторяемыми, как правило, также требуется "скоординированное издевательство" над функциями даты и времени-если вы используетеfrom datetime import datetimeв некоторых модулях, вам нужно найти и издеваться над ними все (а также все те, кто делаетfrom time import timeи так далее), чтобы убедиться, что все время, полученное, когда различные части системы спрашивают: "Так сколько сейчас времени?"совершенно последовательны (Если вы используете FPIM, вы просто издеваетесь над двумя соответствующими модулями).мне нравится FPIM, потому что там действительно не так много добавленной стоимости с помощью умножение квалифицированное имя, а не однократное (в то время как разница между barenames и квалифицированными именами огромный - вы так гораздо больше контроля с определенным именем, будь то поодиночке или умножить, чем вы, возможно, когда-либо сможете с barename!).
Ну, не могу посвятить весь рабочий день, чтобы ответить на каждый из ваших пунктов - ваш вопрос, вероятно, должен быть полдюжины вопросов;-). Я надеюсь, что это по крайней мере решает "почему F лучше, чем R" и некоторые из насмешливых/тестовых вопросов-это сводится к сохранение и повышение хорошо продуманной модульности (через F) вместо того, чтобы подрывать его (через R).
классический текст об этом, как это часто бывает, от Фредрика Лунда, эффбота. Его совет:всегда используйте import - кроме случаев, когда вы не должны.
другими словами, будьте благоразумны. Лично я считаю, что все, что несколько модулей глубоко, как правило, импортируется через
from x.y.z import a- основным примером являются модели Django. Но как и все остальное, это вопрос стиля, и вы должны иметь последовательный - особенно с модулями, такими какdatetime, где и модуль и класс, который он содержит, называется то же самое. Вам нужно написатьdatetime.datetime.now()или простоdatetime.now()? (В моем коде всегда первое.)пункты 1 и 2 в вашем списке вопросов, кажется, та же проблема. Динамическая природа Python означает, что довольно просто заменить элемент в пространстве имен модуля независимо от того, какой из методов вы используете. Трудность возникает, если одна функция в модуле ссылается на другую, которую вы хотите высмеять. В этом случае импортируйте модуль, а не функции означает, что вы можете сделать
module.function_to_replace = myreplacementfuncи все работает прозрачно - но это так же легко сделать через FPIM, как и через IM.Я также не понимаю, как пункт 3 имеет какое-либо отношение к чему-либо. Я думаю, что Ваш пункт 4, однако основан на небольшое недоразумение. Ни один из методов, которые вы даете, не будет "загрязнять ваше пространство имен". Что тут это
from module import *, где вы понятия не имеете, что вы импортируете, и поэтому функции могут появляться в вашем коде без каких-либо подсказка дана читателю откуда они взялись. Это ужасно, и его следует избегать любой ценой.
как Алекс Мартелли, я люблю использовать
asпри импорте функции.одна вещь, которую я сделал, это использовать некоторый префикс для всех функций, которые были импортированы из одного модуля:
from random import seed as r_seed from random import random as r_random
r_seedкороче, чемrandom.seedно несколько сохраняет границы модуля. Кто-то случайно глядя на ваш код может видетьr_seed()иr_random()и есть шанс понять, что они связаны.конечно, вы всегда можете просто делать:
import random as rи затем использовать
r.random()иr.seed(), что может быть идеальным компромиссом для этого случая. Я использую трюк с префиксом только при импорте одной или двух функций из модуля. Когда я хочу использовать много функций из одного модуля, я импортирую модуль, возможно, сasчтобы сократить название.
отличные ответы здесь (я их всех поддержал), и вот мои мысли по этому поводу:
во-первых, обращаясь к каждой из ваших пуль:
(предположительно) плюсы FMIF:
- краткость кода: более короткие имена функций помогают придерживаться 80 столбцов в строке.
возможно, но имена модулей обычно достаточно короткие, поэтому это не актуально. Конечно, есть
datetime, но иos,re,sysи т. д. И Python имеет свободные разрывы строк внутри{ [ (. А для вложенных модулей всегда естьasкак в IM, так и в FPIM
- читаемость: chisquare(...) выглядит более читаемым, чем составляющей.статистика.статистика.chisquare(...).
категорически не согласен. При чтении иностранного кода (или моего собственного кода через несколько месяцев) трудно понять, откуда берется каждая функция. Квалифицированные имена спасают меня от перехода туда и обратно из строки 2345 в заголовок объявления модуля. И это также дает вам контекст:"
chisquare? Что это такое? О, это отscypy? Хорошо, некоторые математические вещи, то". И, еще раз, вы всегда можете сократитьscipy.stats.stats as scypyst.scypyst.chisquare(...)достаточно короткий со всеми преимуществами квалифицированного имени.
import os.path as ospеще один хороший пример, учитывая, что очень часто цепочка 3 или более его функций вместе в одном вызове: join (expanduser (), basename (splitext())) так далее.
- простота перенаправления: однострочное переопределение функции из altmodule вместо модуля.
как часто вы хотите переопределить одну функцию, а не весь модуль? Границы модуля и координация функций должны быть сохранены, и Алекс уже объяснил это очень подробно. Для большинства (всех?) реальные сценарии, если
alt_module.xявляется жизнеспособной заменой дляmodule.x, тогда наверноеalt_moduleсам по себе является каплей Альтернатива дляmodule, так как им и ФПИМ один-вкладыши FMIF как, если вы используетеas.
- я понимаю, что FPIM каким-то образом сводит на нет первые две проблемы...
на самом деле
asэто тот, который смягчает первые 2 проблемы (и 3-й), а не FPIM. Вы можете использовать IM для этого тоже:import some.long.package.path.x as xдля того же результата, что и FPIM.
таким образом, ни один из вышеперечисленных не является настоящим плюсом FMIF. И причины Я предпочитаю IM / FPIM являются:
для простоты и согласованности, когда я импортирую что-то, либо IM, либо FPIM, я всегда импортирую модуль, а не объект из модуля. Помните, что FMIF можно (ab-)использовать для импорта функций, классов, переменных или даже других модулей! Подумайте о беспорядке
from somemodule import sys, somevar, os, SomeClass, datetime, someFunc.кроме того, если вы хотите больше, чем один объект из модуля, FMIF будет загрязнять ваше пространство имен больше, чем IM или FPIM, который будет использовать одно имя независимо от того, сколько объектов вы хотите использовать. И такие объекты будут иметь квалификации имя, которое является pro, а не con: как я уже сказал в выпуске 2, IMHO a it улучшает читабельности.
все сводится к непротиворечивости, простоты организации. "импортировать модули, а не объекты" это хорошая, легкая модель ума, чтобы придерживаться.
Я согласен с MestreLion больше всего здесь (и так upvote).
МОЯ перспектива: я часто просматриваю код, с которым я незнаком, и не знаю, какой модуль функция исходит от простого просмотра функции, довольно неприятно.
код пишется один раз и читается много раз, и поэтому читаемость и ремонтопригодность превосходит простоту ввода.
в аналогичном ключе, как правило, код не пишется в интересах кодер, но в интересах другой сущности.
ваш код должен быть читаем для тех, кто знает python лучше, чем вы, но не знаком с кодом.
импорт полного пути также может лучше помочь IDE указать вам на правильный источник функции или объекта, на который вы смотрите.
по всем этим причинам и причинам, отмеченным MestreLion, я заключаю, что лучше всего импортировать и использовать полный путь.
Comments