подключиться к встроенному оборудованию формата Python F-String - PullRequest
6 голосов
/ 27 апреля 2019

Резюме

Я действительно ЛЮБЛЮ f-струны .Они чертовски удивительный синтаксис.

Я написал небольшую библиотеку - описанную ниже - для собственного использования, чтобы использовать их дальше (и выложил ее для использования другими , вдело было бы полезно для них).Краткий пример того, что он делает:

>>> import simpleformatter as sf
>>> def format_camel_case(string):
...     """camel cases a sentence"""
...     return ''.join(s.capitalize() for s in string.split())
...
>>> @sf.formattable(camcase=format_camel_case)
... class MyStr(str): ...
...
>>> f'{MyStr("lime cordial delicious"):camcase}'
'LimeCordialDelicious'

Было бы очень полезно - для целей упрощенного API и расширения использования встроенных экземпляров классов - найти способ подключиться квстроенный механизм форматирования Python, который позволял бы задавать пользовательские спецификации формата встроенных модулей:

>>> f'{"lime cordial delicious":camcase}'
'LimeCordialDelicious'

Другими словами, я хотел бы переопределить встроенную функцию format (котораяиспользуется синтаксисом f-строки) или, альтернативно, расширить встроенные __format__ методы существующих стандартных библиотечных классов - так, чтобы я мог написать что-то вроде этого:

for x, y, z in complicated_generator:
    eat_string(f"x: {x:custom_spec1}, y: {x:custom_spec2}, z: {x:custom_spec3}")

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

Я мог бы приблизиться к нему, используя string.Formatter api:

my_formatter=MyFormatter()  # custom string.Formatter instance

format_str = "x: {x:custom_spec1}, y: {x:custom_spec2}, z: {x:custom_spec3}"

for x, y, z in complicated_generator:
    eat_string(my_formatter.format(format_str, **locals()))

Я считаю, что это немного неуклюже и определенно не читаемо по сравнению с API-интерфейсом струнных.

Еще одна вещь, которую можно сделать, это переопределить builtins.format:

>>> import builtins
>>> builtins.format = lambda *args, **kwargs: 'womp womp'
>>> format(1,"foo")
'womp womp'

... но это дo не работает для f-строк:

>>> f"{1:foo}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Invalid format specifier

Подробности

В настоящее время мой API выглядит примерно так (несколько упрощенно):

import simpleformatter as sf
@sf.formatter("this_specification")
def this_formatting_function(some_obj):
    return "this formatted someobj!"

@sf.formatter("that_specification")
def that_formatting_function(some_obj):
    return "that formatted someobj!"

@sf.formattable
class SomeClass: ...

После чего вы можете написать код, подобный этому:

some_obj = SomeClass()
f"{some_obj:this_specification}"
f"{some_obj:that_specification}"

Я бы хотел, чтобы API был больше похож на ниже:

@sf.formatter("this_specification")
def this_formatting_function(some_obj):
    return "this formatted someobj!"

@sf.formatter("that_specification")
def that_formatting_function(some_obj):
    return "that formatted someobj!"

class SomeClass: ...  # no class decorator needed

...и разрешить использование спецификаций нестандартного формата для встроенных классов:

x=1  # built-in type instance
f"{x:this_specification}"
f"{x:that_specification}"

Но для того, чтобы сделать это, мы должны проникнуть во встроенную функцию format().Как я могу ухватиться за это сочное совершенство f-string?

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