gpt4 book ai didi

python - 在继承的数据类中使用 __new__

转载 作者:行者123 更新时间:2023-12-04 11:22:08 28 4
gpt4 key购买 nike

假设我有以下代码用于处理个人和国家/地区之间的链接:

from dataclasses import dataclass

@dataclass
class Country:
iso2 : str
iso3 : str
name : str

countries = [ Country('AW','ABW','Aruba'),
Country('AF','AFG','Afghanistan'),
Country('AO','AGO','Angola')]
countries_by_iso2 = {c.iso2 : c for c in countries}
countries_by_iso3 = {c.iso3 : c for c in countries}

@dataclass
class CountryLink:
person_id : int
country : Country

country_links = [ CountryLink(123, countries_by_iso2['AW']),
CountryLink(456, countries_by_iso3['AFG']),
CountryLink(789, countries_by_iso2['AO'])]

print(country_links[0].country.name)
这一切都很好,但我决定让它不那么笨拙,以便能够处理不同形式的输入。我还想使用 __new__ 来确保我们每次都获得有效的 ISO 代码,并且我想反对在这种情况下无法创建。因此,我添加了几个继承自此的新类:
@dataclass
class CountryLinkFromISO2(CountryLink):
def __new__(cls, person_id : int, iso2 : str):
if iso2 not in countries_by_iso2:
return None
new_obj = super().__new__(cls)
new_obj.country = countries_by_iso2[iso2]
return new_obj

@dataclass
class CountryLinkFromISO3(CountryLink):
def __new__(cls, person_id : int, iso3 : str):
if iso3 not in countries_by_iso3:
return None
new_obj = super().__new__(cls)
new_obj.country = countries_by_iso3[iso3]
return new_obj

country_links = [ CountryLinkFromISO2(123, 'AW'),
CountryLinkFromISO3(456, 'AFG'),
CountryLinkFromISO2(789, 'AO')]
乍一看这似乎有效,但后来我遇到了一个问题:
a = CountryLinkFromISO2(123, 'AW')
print(type(a))
print(a.country)
print(type(a.country))
返回:
<class '__main__.CountryLinkFromISO2'>
AW
<class 'str'>
继承的对象具有正确的类型,但它的属性 country 只是一个字符串,而不是我期望的 Country 类型。我在 __new__ 中放入了打印语句来检查 new_obj.country 的类型,并且在 return 行之前是正确的。
我想要实现的是让 a 成为 CountryLinkFromISO2 类型的对象,它将继承我对 CountryLink 所做的更改,并使其具有从字典 country 中获取的属性 countries_by_iso2 。我怎样才能做到这一点?

最佳答案

仅仅因为数据类在幕后做,并不意味着你的类没有 __init__() .他们这样做,看起来像:

def __init__(self, person_id: int, country: Country):
self.person_id = person_id
self.country = country
当您使用以下命令创建类时:
CountryLinkFromISO2(123, 'AW')
那个 "AW"字符串被传递给 __init__()并将值设置为字符串。
使用 __new__()以这种方式是脆弱的,并且从构造函数返回 None 是相当不pythonic的(imo)。也许你最好制作一个返回 None 的实际工厂函数。或者你想要的类(class)。那你就不用惹 __new__()根本。
@dataclass
class CountryLinkFromISO2(CountryLink):
@classmethod
def from_country_code(cls, person_id : int, iso2 : str):
if iso2 not in countries_by_iso2:
return None
return cls(person_id, countries_by_iso2[iso2])

a = CountryLinkFromISO2.from_country_code(123, 'AW')
如果由于某种原因它需要使用 __new__() , 您可以返回 None没有匹配项时从新开始,并在 __post_init__() 中设置国家/地区:
@dataclass
class CountryLinkFromISO2(CountryLink):
def __new__(cls, person_id : int, iso2 : str):
if iso2 not in countries_by_iso2:
return None
return super().__new__(cls)

def __post_init__(self):
self.country = countries_by_iso2[self.country]

关于python - 在继承的数据类中使用 __new__,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68703741/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com