Резюме
Я действительно ЛЮБЛЮ 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?