将类更改为数据类

-2 python python-3.x python-dataclasses

我想将一个类重构为数据类,这是我所拥有的:

class Tenant:
   def __init__(self, tenant: dict, api_client: str) -> None:
      self.name = tenant["name"]
      self.tenant_id= tenant["id"]
      self.subdomain = tenant["subdomain"]
      self.api_client= api_client
Run Code Online (Sandbox Code Playgroud)

与数据类相同的类是什么?我尝试过类似的方法,但我不知道如何将此字典分为名称、租户 ID 和子域:

@dataclass
class Tenant:
   tenant: dict
   api_client: str
Run Code Online (Sandbox Code Playgroud)

che*_*ner 7

我将向数据类添加一个类方法,以从dict.

@dataclass
class Tenant:
    name: str
    tenant_id: int
    subdomain: str
    api_client: str

    @classmethod
    def from_dict(cls, tenant: dict, api_client: str):
        return cls(tenant["name"],
                   tenant["id"],
                   tenant["subdomain"],
                   api_client)


t1 = Tenant("alice", 5, "bar", "client")
t2 = Tenant.from_dict({"name": "bob", "id": 6, "subdomain": "foo"},
                      "client")
Run Code Online (Sandbox Code Playgroud)

Tenant即使不是数据类,也会采取相同的方法。的实例Tenant只对分配给其属性的值感兴趣,而不关心在创建实例之前如何打包这些值。


如果您必须保留 的现有 API Tenant,则需要使用InitVarand__post_init__方法。

from dataclasses import dataclass, InitVar, field


@dataclass
class Tenant:
    tenant: InitVar[dict]
    name: str = field(init=False)
    tenant_id: int = field(init=False)
    subdomain: str = field(init=False)
    api_client: str

    # Approximate __init__ method generated
    # def __init__(self, tenant, api_client):
    #     self.api_client = api_client
    #     self.__post_init__(tenant)

    def __post_init__(self, tenant):
        self.name = tenant["name"]
        self.tenant_id = tenant["id"]
        self.subdomain = tenant["subdomain"]

t = Tenant({"name": "bob", "id": 6, "subdomain": "foo"},
           "client")
Run Code Online (Sandbox Code Playgroud)

tenant,作为InitVar, 传递给__init____post_init__,但不会用作其他自动生成方法的属性。nametenant_id、 和subdomain不会被接受作为 的参数__init__,但会被其他自动生成的方法使用。但是,您有责任确保它们在 中正确设置__post_init__


一种可能的混合方法来定义“私有”类,并使名称Tenant引用类方法。

def _from_dict(cls, tenant, api_client):
    return cls(tenant["name"],
               tenant["id"],
               tenant["subdomain"],
               api_client)

# Using make_dataclass just to make the class name
# 'Tenant' instead of '_Tenant'. You can use an
# ordinary class statement and patch _Teant.__name__
# instead.
_Tenant = dataclasses.make_dataclass(
      'Tenant',
      [('name', str),
       ('tenant_id', int),
       ('subdomain', str),
       ('api_client', str)],
      namespace={'from_dict': classmethod(_from_dict)}
     )

Tenant = _Tenant.from_dict
Run Code Online (Sandbox Code Playgroud)