当前位置: 首页 > 知识库问答 >
问题:

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

缪升
2023-03-14

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

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

Pythonsnamedtuple是这方面的首选,但问题是参数的数量是固定的。因此,如果只需要有带年份的tuple类对象,我要么就必须安装

mytupleobj = TupObj(2012, None)

或者创建一个只携带年份的名称元组的新定义。两种解决方案看起来都不怎么样。

有没有一种方法——使用< code>namedtuple或其他技术——当我实例化

mytupleobj = TupObj(2012)

我得到一个类似元组的对象实例化,它只有属性年份,当我使用时

mytupleobj = TupObj(2012,2)

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

共有3个答案

林龙野
2023-03-14

您可以在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
令狐跃
2023-03-14

如果您的目标是从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

另一种更干净的实现/维护方法是将默认值保存为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
东郭阳德
2023-03-14

您不希望有不同的类定义。如果没有传入一个< code>month值,您只需要用属性的默认值使这些参数成为可选的。< code>namedtuple()工厂函数不支持该用例。

但这并不是创建命名元组的唯一方法。您还可以将类型划分为子类。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具有新的dataclass模块,或者您可以安装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)
 类似资料:
  • 在问我的问题之前,我想把一些事情说清楚。首先,我是Java和编程的新手。第二,这是我的第一个帖子,所以如果我做错了什么,请宽容对待我。最后,我不想要任何具体的解决办法,我的任务在任何回应这篇文章。这些问题要我来解决。我想要的是一个解释,为什么我的测试代码不能编译/运行。为了更好地理解这个问题,我将粘贴赋值信息,然后是给定的驱动程序类,然后是驱动程序类访问的我的类代码。我的编译器错误显示在标题中,但

  • 我有一个抽象的超类,它有一个形式的构造函数 并希望创建该抽象类的一个子类,该子类不是以字符串作为其第一个参数,而是采用一个表示给定字符串名称的整数值,例如,0代表某个字符串,1代表另一个字符串,依此类推。 当我尝试编写窗体子类(int number,int amount)的构造函数时,我得到一个格式为“Implicit super constructor is undefined.必须显式调用另一

  • 问题内容: 如何使AB的构造函数使用适当的参数调用A和B的构造函数? 我试过了 但这给我一个错误。 问题答案: 你没有通过。 请注意,如果这种继承层次结构变得更加复杂,则会遇到构造函数无法执行或无法重新执行的问题。外观到(和问题与),并从不要忘记继承如果你在2.x和你的类不从别的继承。

  • 我想问一下java编程语言,具体到构造函数。假设我们有一个类测试,在那里我们测试整个程序,和类点,在那里定义构造函数(集和获取方法btw)。类行: 类点: 现在,如果我在构造函数中输入类点的名称,那将是一个错误:

  • 我得到了下面的代码,使用数组来查找一些prim数。然而,当试图编译我的用户类PalindromeArrayUser时,它说——“类中的构造函数不能应用于给定的类型” 要求:int。找到:没有论点。原因:实际参数和正式参数列表的长度不同。 但是,我已经向构造器传递了一个int值(与我的蓝图中设计的方式相同)。我不太明白问题来自哪里。谢谢。 这是我的两节课 而这就是我的用户类问题的来源。上面的类编译良

  • 在Dart中,工厂构造函数需要编码器提供更多逻辑,但与常量构造函数没有太大区别,只是它们允许“非最终”实例变量。 与const Constructor相比,它们有哪些优点? 谢谢大家。 编辑 下面是关于Seth Ladd博客“Dart-试图理解“工厂”构造函数的价值”中工厂构造函数的用法。 恕我直言,使用通用构造函数,可以通过细微的差异实现相同的效果,但相当简单。 如上所示,尽管这两个实例 所以,