这是我的用例:我想定义一个像元组的对象,但是我可以通过属性名称访问其元素,例如
mytupleobj = TupObj(2012,3)
mytupleobj.year = 2012
mytupleobj.month = 3
Python namedtuple
是最主要的选择,但是问题是参数的数量是固定的。因此,如果只需要带有元组的对象来承载年份,那么我要么必须实例化
mytupleobj = TupObj(2012, None)
或创建仅包含年份的名称元组的新定义。两种解决方案都很难看。
有没有一种方法-使用namedtuple
或其他某种技术-以便在我实例化时
mytupleobj = TupObj(2012)
我得到一个类似元组的可实例化对象,该对象仅在使用时具有属性year
mytupleobj = TupObj(2012,2)
我得到一个具有year
和month
属性的类似元组的对象吗?
答案 0 :(得分:1)
您可以在namedtuple
Python 2.7解决方案:
from collections import namedtuple
tupobj = namedtuple('tupobj', 'year month')
tupobj.__new__.__defaults__ = (None,) * len(tupobj._fields)
t1 = tupobj(2012)
print(t1)
# >> tupobj(year=2012, month=None)
print(t1.year)
# >> 2012
t2 = tupobj(year=2012)
print(t2)
# >> tupobj(year=2012, month=None)
print(t2.year)
# >> 2012
t3 = tupobj(month=1)
print(t3)
# >> tupobj(year=None, month=1)
print(t3.month)
# >> 1
t4 = tupobj(2012, 1)
print(t4)
# >> tupobj(year=2012, month=1)
print(t4.year)
# >> 2012
print(t4.month)
# >> 1
Python 3.7解决方案:
from collections import namedtuple
tupobj = namedtuple('tupobj', 'year month', defaults=(None,None))
t1 = tupobj(2012)
print(t1)
# >> tupobj(year=2012, month=None)
print(t1.year)
# >> 2012
t2 = tupobj(year=2012)
print(t2)
# >> tupobj(year=2012, month=None)
print(t2.year)
# >> 2012
t3 = tupobj(month=1)
print(t3)
# >> tupobj(year=None, month=1)
print(t3.month)
# >> 1
t4 = tupobj(2012, 1)
print(t4)
# >> tupobj(year=2012, month=1)
print(t4.year)
# >> 2012
print(t4.month)
# >> 1
答案 1 :(得分:1)
您不需要其他的类定义。如果您未传递month
值,则只想使用属性的默认值使这些参数可选即可。 namedtuple()
工厂功能不支持该用例。
但这不是创建命名元组的唯一方法。您还可以继承typing.NamedTuple
的子类:
from typing import NamedTuple, Optional
class VagueTimePeriod(NamedTuple):
year: int
month: Optional[int] = None
这是命名元组的类定义,其中month
是可选的,如果您不指定月份,则将其保留为默认值:
>>> VagueTimePeriod(2012)
VagueTimePeriod(year=2012, month=None)
>>> VagueTimePeriod(2012, 3)
VagueTimePeriod(year=2012, month=3)
但是,我怀疑您真正想要的是数据类。一个简单的类,大部分只保存一些数据。
Python 3.7具有新的dataclasses
module,或者您可以安装attrs
project。数据类可以具有可选属性(默认为您在定义时指定的值):
from dataclasses import dataclass
from typing import Optional
@dataclass
class VagueTimePeriod:
year: int
month: Optional[int] = None
vtp1 = VagueTimePeriod(2012)
vtp2 = VagueTimePeriod(2012, 3)
数据类为您提供了一种简化的语法,用于定义一个小类,该小类具有表示法,相等性测试以及可选的排序支持,哈希和不变性。
数据类也完全支持继承,而元组则不支持。
数据类不是自动可迭代或不可变的,但可以做到这一点,请参见this previous answer of mine,其中我定义了一个简单的DataclassSequence
基类,该基类增加了序列行为。
快速演示:
>>> @dataclass(frozen=True)
... class VagueTimePeriod:
... year: int
... month: Optional[int] = None
...
>>> VagueTimePeriod(2012)
VagueTimePeriod(year=2012, month=None)
VagueTimePeriod(2012, 3)
VagueTimePeriod(year=2012, month=3)
答案 2 :(得分:1)
如果您的目标是要有一个易于理解的实现,以实现从OOP角度来看的外观,则只需使用条件并为值传递默认参数,并在初始化期间检查其条件值。它可能看起来像这样:
class mydatetimeclass():
def __init__(self, year, month=None, day=None):
self.year = year
if month is not None:
self.month = month
if day is not None:
self.day = day
obj1 = mydatetimeclass(2016)
obj1.year #2016
obj2 = mydatetimeclass(2017, 5)
obj2.year #2017
obj2.month #5
另一种更易于实施/维护的方法是将默认值保存为“无”,这样您就不必担心每个对象中实际存在哪些属性。
class mydatetimeclass():
def __init__(self, year, month=None, day=None):
self.year = year
self.month = month #sets to None by default
self.day = day