Поскольку вы хотите использовать self.format
в качестве аргумента по умолчанию, это подразумевает, что метод должен быть специфичным для экземпляра (то есть, нет способа определить это на уровне класса). Вместо этого вы можете определить конкретный метод, например, в классе __init__
. Здесь у вас есть доступ к специфическим атрибутам экземпляра.
Один из подходов заключается в использовании functools.partial
для получения обновленной (конкретной) версии метода:
from functools import partial
class C:
def __init__(self, format):
self.format = format
self.process = partial(self.process, formatting=self.format)
def process(self, formatting):
print(formatting)
c = C('default')
c.process()
# c.process('custom') # Doesn't work!
c.process(formatting='custom')
Обратите внимание, что при таком подходе вы можете передавать соответствующий аргумент только по ключевому слову, поскольку, если вы предоставите его по позиции, это приведет к конфликту в partial
.
Другой подход заключается в определении и установке метода в __init__
:
from types import MethodType
class C:
def __init__(self, format):
self.format = format
def process(self, formatting=self.format):
print(formatting)
self.process = MethodType(process, self)
c = C('test')
c.process()
c.process('custom')
c.process(formatting='custom')
Это также позволяет передавать аргумент по позиции, однако порядок разрешения метода становится менее очевидным (что может, например, повлиять на проверку IDE, но я полагаю, что для этого есть специальные обходные пути для IDE).
Другой подход заключается в создании пользовательского типа для такого рода «значений по умолчанию атрибута экземпляра» вместе со специальным декоратором, который выполняет соответствующее заполнение аргумента getattr
:
import inspect
class Attribute:
def __init__(self, name):
self.name = name
def decorator(method):
signature = inspect.signature(method)
def wrapper(self, *args, **kwargs):
bound = signature.bind(*((self,) + args), **kwargs)
bound.apply_defaults()
bound.arguments.update({k: getattr(self, v.name) for k, v in bound.arguments.items()
if isinstance(v, Attribute)})
return method(*bound.args, **bound.kwargs)
return wrapper
class C:
def __init__(self, format):
self.format = format
@decorator
def process(self, formatting=Attribute('format')):
print(formatting)
c = C('test')
c.process()
c.process('custom')
c.process(formatting='custom')