英文:
pydantic: BaseSettings with parametrized default values
问题
似乎无法在 pydantic 的 BaseSettings
超类上创建 __init__
函数。
我试图实现这个(注意:为了演示,这段代码在 pydantic 中不受支持):
class MySettings(BaseSettings):
def __init__(self, foo: str):
self.p1 = f"{foo}_param_name1" # <- trying to achieve this
self.p2 = f"{foo}_param_name2" # <- trying to achieve this
redis_host: Optional[str] = "asdf"
settings = MySettings(foo="test")
assert settings.redis_host == "asdf"
assert settings.p1 == "test_param_name1" # 这将引发 p1 不存在的 ValueError
assert settings.p2 == "test_param_name2"
到目前为止,我找到的最接近的方法是使用 create_model
,但在 BaseSettings
的上下文中并没有讨论这一点:https://docs.pydantic.dev/usage/models/#dynamic-model-creation
是否有一种方法可以实现一个基于参数设置某些值的 BaseSettings
超类?
以下方法似乎相当糟糕,而且还会极大地混淆代码编辑器:
def retrofit(class_instance: BaseSettings, foo: str):
setattr(class_instance, "p1", f"{foo}_param_name1")
这也有效,但会导致许多 linting 错误,而且还会混淆编辑器(似乎不知道 p1 是一个参数):
def default_settings(foo: str) -> Type[BaseSettings]:
class DefaultSettings(BaseSettings):
p1 = f"{foo}_param_name1"
redis_host: Optional[str] = "asdf"
return DefaultSettings
MyDefaultSettings: Type[BaseSettings] = default_settings("test")
class SuperSettings(MyDefaultSettings):
""" """
conf = SuperSettings()
assert conf.p1 == "test_param_name1" # 在运行时有效,但会产生 p1 不是属性的 linting 错误
英文:
It appears one cannot create an __init__
function on pydantic BaseSettings superclasses.
I am trying to achieve this (note; for demonstration, this code is not supported in pydantic):
class MySettings(BaseSettings):
def __init__(self, foo: str):
self.p1 = f"{foo}_param_name1" # <- trying to achieve this
self.p2 = f"{foo}_param_name2" # <- trying to achieve this
redis_host: Optional[str] = "asdf"
settings = MySettings(foo="test")
assert settings.redis_host == "asdf"
assert settings.p1 == "test_param_name1" # this will raise a ValueError for p1 not existing
assert settings.p2 == "test_param_name2"
So far, the closest thing I've found is create_model
https://docs.pydantic.dev/usage/models/#dynamic-model-creation
but this is not discussed in the context of BaseSettings
Is there a way to achieve a BaseSettings superclass where some values are set based on a parameter?
The following seems pretty nasty and would also greatly confuse code editors:
def retrofit(class_instance: BaseSettings, foo: str):
setattr(class_instance, "p1", f"{foo}_param_name1")
This also works, but causes many linting errors and also confuses editors (seems not to know p1 is a parameter)
def default_settings(foo: str) -> Type[BaseSettings]:
class DefaultSettings(BaseSettings):
p1 = f"{foo}_param_name1"
redis_host: Optional[str] = "asdf"
return DefaultSettings
MyDefaultSettings: Type[BaseSettings] = default_settings("test")
class SuperSettings(MyDefaultSettings): # linting error that MyDefaultSettings is not a valid type
""" """
conf = SuperSettings()
assert conf.p1 == "test_param_name1" # works at runtime, but linting error that p1 is not an attribute
答案1
得分: 1
BaseSettings
有自己的构造函数 __init__
,如果你想要重写它,你应该实现与原始构造函数相同的行为 +α。
否则,你可以调用基类(super
)的构造函数,它会完成它的工作。正确的继承很重要。
from pydantic import BaseSettings
from typing import Optional
class MySettings(BaseSettings):
p1: Optional[str]
p2: Optional[str]
redis_host: Optional[str] = "asdf"
def __init__(self, *args, foo: str = None, **kwargs):
super().__init__(*args, **kwargs)
if foo is not None:
self.p1 = f"{foo}_param_name1" # <- achieved
self.p2 = f"{foo}_param_name2" # <- achieved
settings = MySettings(foo="test")
assert settings.redis_host == "asdf"
assert settings.p1 == "test_param_name1" # no ValueError
assert settings.p2 == "test_param_name2"
此代码中没有断言。
英文:
BaseSettings
has own constructor __init__
and if you want to override it you should implement same behavior as original constructor +α.
In other case you may call constructor of base (super
) class that will do his job. Correct inheritance is matter.
from pydantic import BaseSettings
from typing import Optional
class MySettings(BaseSettings):
p1: Optional[str]
p2: Optional[str]
redis_host: Optional[str] = "asdf"
def __init__(self, *args, foo: str = None, **kwargs):
super().__init__(*args, **kwargs)
if foo is not None:
self.p1 = f"{foo}_param_name1" # <- achieved
self.p2 = f"{foo}_param_name2" # <- achieved
settings = MySettings(foo="test")
assert settings.redis_host == "asdf"
assert settings.p1 == "test_param_name1" # no ValueError
assert settings.p2 == "test_param_name2"
No assertions in this code
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论