Python: использует "..%(var)s.."% местные жители() хорошая практика?



я обнаружил этот шаблон (или анти-шаблон), и я очень доволен им.



Я чувствую, что это очень подвижный:



def example():
age = ...
name = ...
print "hello %(name)s you are %(age)s years old" % locals()


иногда я использую его двоюродный брат:



def example2(obj):
print "The file at %(path)s has %(length)s bytes" % obj.__dict__


мне не нужно создавать искусственный кортеж и подсчитывать параметры и сохранять соответствующие позиции %s внутри кортежа.



нравится ли вам это? Вы бы его использовали? Да / Нет, пожалуйста, объясните.

625   7  

7 ответов:

это нормально для небольших приложений и якобы "одноразовых" скриптов, особенно с vars повышение упомянутое @kaizer.se а то .format версия, упомянутая @RedGlyph.

в "серьезном" приложении у вас не будет жестко закодированной строки формата - или, если бы вы это сделали, это было бы в какой-то форме, такой как _('Hello {name}.'), где _ происходит от gettext или аналогичным названием i18n / команде l10n рамки. Дело в том, что такое приложение (или многоразовые модули, которые могут быть использованы в таких приложениях) должно поддерживать интернационализацию (АКА i18n) и локализация (AKA L10n): вы хотите, чтобы ваше приложение могло излучать "Hello Paul" в некоторых странах и культурах, "Hola Paul" в некоторых других, "Ciao Paul" в других еще и так далее. Таким образом, строка формата более или менее автоматически заменяется другой во время выполнения, в зависимости от текущих настроек локализации; вместо того, чтобы быть жестко закодированной, она живет в какой-то базе данных. Во всех смыслах и целях представьте, что строка формата всегда является переменной, а не строкой буквальный.

так, что у вас есть по существу

formatstring.format(**locals())

и вы не можете тривиально проверить точно что локальные имена форматирование будет использовать. Вам нужно будет открыть и просмотреть базу данных L10N, определить строки формата, которые будут использоваться здесь в разных настройках, проверить все из них.

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

если у вас есть превосходное тестирование интеграции / регрессии, поломка будет поймана до бета-релиза-но QA будет кричать на вас, и релиз будет отложен... и, давайте будем честными, стремясь к 100% покрытия unit тесты разумно, то действительно не с интеграция тесты, как только вы рассмотрите комбинаторный взрыв настроек [[для L10N и по многим другим причинам]] и поддерживаемые версии всех зависимостей. Таким образом, вы просто не беспечно рискуете поломками, потому что "они будут пойманы в QA" (если вы это сделаете, вы не сможете долго работать в среде, которая разрабатывает большие приложения или многоразовые компоненты;-).

таким образом, на практике вы никогда не будете удалять локальную переменную "name", даже если пользовательский интерфейс люди уже давно переключили это приветствие на более подходящее "Добро пожаловать, ужасный Повелитель!"его (и соответственно команде l10n объед версии). Все потому, что вы пошли на locals()...

таким образом, вы накапливаете cruft из-за того, как вы обжали свою способность поддерживать и редактировать свой код-и, возможно, эта локальная переменная "имя" существует только потому, что она была извлечена из БД или тому подобное, поэтому сохранение ее (или какой-либо другой локальный) вокруг не просто cruft, это также снижает производительность. Это поверхностное удобство locals() стоимостью это?- )

но подождите, это еще хуже! Среди множества полезных услуг lint - как программа (например,pylint) может сделать для вас, чтобы предупредить вас о неиспользуемых локальных переменных (жаль, что он может сделать это для неиспользуемых глобалов, а также, но, для многоразовых компонентов, это просто слишком сложно;-). Таким образом, вы будете ловить большинство случайных ошибок, таких как if ...: nmae = ... очень быстро и дешево, а не видеть блок-тест перерыв и делать сыщика работу, чтобы узнать почему он сломался (вы do есть навязчивые, всепроникающие модульные тесты, которые б поймать это в конце концов, не так ли?- ) -- lint расскажет вам о неиспользуемой локальной переменной nmae и вы сразу же это исправите.

но если у вас есть в коде a blah.format(**locals()), или в blah % locals()... ты же Сол, приятель!- ) Как бедный Линт узнает, будет ли nmae фактически является неиспользуемой переменной, или на самом деле он используется любой внешней функцией или методом, который вы передаете locals() в? Он не может-либо он все равно предупредит (вызывая эффект "крик волка", который в конечном итоге заставляет вас игнорировать или отключать такие предупреждения), либо он никогда не предупредит (с тем же конечным эффектом: нет предупреждений;-).

сравните это с альтернативой" явное лучше, чем неявное"...:

blah.format(name=name)

есть -- никто из техническое обслуживание, производительность, и я-я-тормоз-нибудь вкусненькое волнуется, применяет больше; блаженство! Вы сразу же сделаете это ясно всем заинтересованным (включая Линт; -) точно что локальные переменные используются, а именно для каких целей.

я мог бы продолжать, но я думаю, что этот пост уже довольно долго;-).

Итак, резюмируя: "γνῶθι σεαυτόν!"Хм, я имею в виду," Познай себя!". И под "самим собой "я на самом деле имею в виду"цель и объем вашего кода". Если это 1-офф-или-около того вещь, никогда не хотел быть i18n и l10n бы, вряд ли нуждаются в дальнейшем обслуживании, никогда не будет снова использован в более широком контексте и т. д., и т. д., а затем пойти дальше и использовать locals() для его небольшого, но аккуратного удобства; если вы знаете иначе или даже если вы не совсем уверены, ошибитесь на стороне осторожности и сделаете вещи более явными-страдайте от небольшого неудобства, точно указывая, что вы собираетесь, и наслаждайтесь всеми вытекающими преимуществами.

кстати, это только один из примеров, когда Python стремится поддерживать как" небольшое, одноразовое, исследовательское, возможно, интерактивное " Программирование (позволяя и поддерживая рискованные удобства, которые выходят далеко за рамки locals() -- думаю, что от import *,eval,exec, и несколько других способов, которыми вы можете размазать пространства имен и влияние на обслуживание рисков для удобства), а также "большие, многоразовые, корпоративные" приложения и компоненты. Он может сделать довольно хорошую работу в обоих, но только если вы "знаете себя" и избегаете использования " удобства" части, за исключением тех случаев, когда вы абсолютно уверены, что можете себе это позволить. Чаще всего ключевым соображением является: "что это делает с моими пространствами имен и осознанием их формирования и использования компилятором, lint &c, читателями и сопровождающими людьми и т. д.?".

вы определить границы того, что это подразумевает, как следствие вашей среды разработки, целей и практики. Используйте эту силу ответственно!- )

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

Я никогда не пишу код, мне не нужно писать меньше кода лучше, чем больше кода и это практика использования позволяет мне писать меньше кода, а также очень легко читать и понимать.

ни разу за миллион лет. Неясно, что такое контекст для форматирования:locals может включать практически любой переменной. self.__dict__ не так расплывчато. Совершенно ужасно оставлять будущих разработчиков почесывать голову над тем, что локально, а что не локально.

это намеренная тайна. Зачем обременять свою организацию такими головными болями в будущем?

относительно "кузена", а не obj.__dict__, это выглядит намного лучше с новым форматированием строки:

def example2(obj):
    print "The file at {o.path} has {o.length} bytes".format(o=obj)

Я использую это много для repr методы, например,

def __repr__(self):
    return "{s.time}/{s.place}/{s.warning}".format(s=self)

The "%(name)s" % <dictionary> или еще лучше "{name}".format(<parameters>) есть заслуга

  • будучи более читаемым, чем "%0s"
  • не зависит от порядка аргументов
  • Не обязательно использовать все аргументы в строке

Я бы предпочел str.format (), так как это должен быть способ сделать это в Python 3 (согласно PEP 3101), и уже доступен с 2.6. С locals() хотя, вы должны были бы сделать это:

print("hello {name} you are {age} years old".format(**locals()))

С помощью встроенного vars([object]) (документация) может сделать второй выглядеть лучше для вас:

def example2(obj):
    print "The file at %(path)s has %(length)s bytes" % vars(obj)

эффект конечно же.

теперь есть официальный способ сделать это, начиная с Python 3.6.0:форматированные строковые литералы.

это работает так:

f'normal string text {local_variable_name}'

например, вместо этих:

"hello %(name)s you are %(age)s years old" % locals()
"hello {name} you are {age} years old".format(**locals())
"hello {} you are {} years old".format(name, age)

просто сделать это:

f"hello {name} you are {age} years old"

вот официальный пример:

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal("12.34567")
>>> f"result: {value:{width}.{precision}}"  # nested fields
'result:      12.35'

ссылки:

Comments

    Ничего не найдено.