繁体   English   中英

根据构造函数签名使用不同的类定义

[英]Using a different class definition depending on the constructor signature

这是我的用例:我想定义一个类似元组的对象,但我可以通过属性名访问其元素,例如

mytupleobj = TupObj(2012,3)
mytupleobj.year = 2012 
mytupleobj.month = 3

Pythons namedtuple是这个的主要候选者,但问题是参数的数量是固定的。 因此,如果只需要具有年份的元组类对象,我要么必须实现

mytupleobj = TupObj(2012, None)

或者创建一个仅包含年份的名称元组的新定义。 两种解决方案看起来都很丑

有没有办法 - 使用namedtuple或其他一些技术 - 以便在我实例化时

mytupleobj = TupObj(2012)

我得到一个类似于元组的对象,它只有属性year和我使用时

mytupleobj = TupObj(2012,2)

我得到一个具有yearmonth属性的类似元组的对象?

您可以在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

您不需要不同的类定义。 如果没有传入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模块 ,或者你可以安装attrs项目 数据类可以具有可选属性(默认为您在定义时声明的值):

from dataclasses import dataclass
from typing import Optional

@dataclass
class VagueTimePeriod:
    year: int
    month: Optional[int] = None

vtp1 = VagueTimePeriod(2012)
vtp2 = VagueTimePeriod(2012, 3)

数据类为您提供了极大简化的语法来定义一个小类,它带有表示,相等测试和可选的排序支持,散列和不变性。

数据类也完全支持继承,而元组则没有。

数据类不能自动迭代或不可变,但可以这样做,请参阅我之前的答案 ,其中我定义了一个简单的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)

如果你的目标是从OOP角度看一个易于理解的实现,你只需要处理条件并传递值的默认参数,在init期间检查它们的条件值。 它可能看起来像这样:

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

实现/维护方法的另一个清理方法是将默认值保存为None,这样您就不必担心每个对象中实际存在哪些属性。

class mydatetimeclass():
    def __init__(self, year, month=None, day=None):
        self.year = year
        self.month = month #sets to None by default
        self.day = day

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM