java和python构造函数的区别_什么是在Python中拥有多个构造函数的干净,pythonic方式?...

回答(11)

2 years ago

如果你想使用可选参数,所有这些答案都非常好,但另一种Pythonic可能是使用classmethod来生成工厂式伪构造函数:

def __init__(self, num_holes):

# do stuff with the number

@classmethod

def fromRandom(cls):

return cls( # some-random-number )

2 years ago

如果您将只使用 __init__ ,则使用 num_holes=None 作为默认值是正常的 .

如果你想要多个独立的"constructors",你可以将它们作为类方法提供 . 这些通常称为工厂方法 . 在这种情况下,您可以将 num_holes 的默认值设为 0 .

class Cheese(object):

def __init__(self, num_holes=0):

"defaults to a solid cheese"

self.number_of_holes = num_holes

@classmethod

def random(cls):

return cls(randint(0, 100))

@classmethod

def slightly_holey(cls):

return cls(randint((0,33))

@classmethod

def very_holey(cls):

return cls(randint(66, 100))

现在创建这样的对象:

gouda = Cheese()

emmentaler = Cheese.random()

leerdammer = Cheese.slightly_holey()

2 years ago

而是使用 num_holes=None 作为默认值 . 然后检查是否 num_holes is None ,如果是,则随机化 . 无论如何,这就是我通常看到的 .

更完全不同的构造方法可能需要一个返回 cls 实例的类方法 .

2 years ago

这些是您实施的好主意,但如果您要向用户展示奶酪制作界面 . 他们并不关心奶酪有多少孔或者是什么内部制作奶酪 . 您的代码的用户只想要“gouda”或“parmesean”吗?

那么为什么不这样做:

# cheese_user.py

from cheeses import make_gouda, make_parmesean

gouda = make_gouda()

paremesean = make_parmesean()

然后你可以使用上面的任何方法来实际实现这些功能:

# cheeses.py

class Cheese(object):

def __init__(self, *args, **kwargs):

#args -- tuple of anonymous arguments

#kwargs -- dictionary of named arguments

self.num_holes = kwargs.get('num_holes',random_holes())

def make_gouda():

return Cheese()

def make_paremesean():

return Cheese(num_holes=15)

这是一种很好的封装技术,我认为它更像是Pythonic . 对我来说,这种做事方式更适合鸭子打字 . 你只是要求一个gouda对象而你并不关心它是什么类 .

2 years ago

为什么你认为你的解决方案“笨重”?就个人情况而言,我个人更喜欢一个默认值超过多个重载构造函数的构造函数(Python不支持方法重载):

def __init__(self, num_holes=None):

if num_holes is None:

# Construct a gouda

else:

# custom cheese

# common initialization

对于具有许多不同构造函数的非常复杂的情况,使用不同的工厂函数可能更简洁:

@classmethod

def create_gouda(cls):

c = Cheese()

# ...

return c

@classmethod

def create_cheddar(cls):

# ...

在您的奶酪示例中,您可能想要使用奶酪的Gouda子类...

2 years ago

class Cheese:

def __init__(self, *args, **kwargs):

"""A user-friendly initialiser for the general-purpose constructor.

"""

...

def _init_parmesan(self, *args, **kwargs):

"""A special initialiser for Parmesan cheese.

"""

...

def _init_gauda(self, *args, **kwargs):

"""A special initialiser for Gauda cheese.

"""

...

@classmethod

def make_parmesan(cls, *args, **kwargs):

new = cls.__new__(cls)

new._init_parmesan(*args, **kwargs)

return new

@classmethod

def make_gauda(cls, *args, **kwargs):

new = cls.__new__(cls)

new._init_gauda(*args, **kwargs)

return new

2 years ago

实际上 None 对"magic"值更好:

class Cheese():

def __init__(self, num_holes = None):

if num_holes is None:

...

现在,如果您想完全自由地添加更多参数:

class Cheese():

def __init__(self, *args, **kwargs):

#args -- tuple of anonymous arguments

#kwargs -- dictionary of named arguments

self.num_holes = kwargs.get('num_holes',random_holes())

为了更好地解释 *args 和 **kwargs 的概念(您实际上可以更改这些名称):

def f(*args, **kwargs):

print 'args: ', args, ' kwargs: ', kwargs

>>> f('a')

args: ('a',) kwargs: {}

>>> f(ar='a')

args: () kwargs: {'ar': 'a'}

>>> f(1,2,param=3)

args: (1, 2) kwargs: {'param': 3}

2 years ago

最好的答案是关于默认参数的上面的答案,但我很乐意写这个,它确实符合“多个构造函数”的账单 . 使用风险由您自己承担 .

怎么样new方法 .

“典型实现通过使用super(currentclass,cls). new (cls [,...])调用超类的 new ()方法并使用适当的参数创建类的新实例,然后根据需要修改新创建的实例 . 归还它 . “

因此,您可以通过附加适当的构造函数方法让 new 方法修改类定义 .

class Cheese(object):

def __new__(cls, *args, **kwargs):

obj = super(Cheese, cls).__new__(cls)

num_holes = kwargs.get('num_holes', random_holes())

if num_holes == 0:

cls.__init__ = cls.foomethod

else:

cls.__init__ = cls.barmethod

return obj

def foomethod(self, *args, **kwargs):

print "foomethod called as __init__ for Cheese"

def barmethod(self, *args, **kwargs):

print "barmethod called as __init__ for Cheese"

if __name__ == "__main__":

parm = Cheese(num_holes=5)

2 years ago

这就是我为必须创建的 YearQuarter 类解决它的方法 . 我用一个名为 value 的参数创建了 __init__ . __init__ 的代码只决定 value 参数的类型并相应地处理数据 . 如果你想要多个输入参数,你只需将它们打包成一个元组并测试 value 是一个元组 .

你这样使用它:

>>> temp = YearQuarter(datetime.date(2017, 1, 18))

>>> print temp

2017-Q1

>>> temp = YearQuarter((2017, 1))

>>> print temp

2017-Q1

这就是 __init__ 和班上其他人的样子:

import datetime

class YearQuarter:

def __init__(self, value):

if type(value) is datetime.date:

self._year = value.year

self._quarter = (value.month + 2) / 3

elif type(value) is tuple:

self._year = int(value[0])

self._quarter = int(value[1])

def __str__(self):

return '{0}-Q{1}'.format(self._year, self._quarter)

当然,您可以使用多个错误消息展开 __init__ . 我在这个例子中省略了它们 .

2 years ago

人们肯定更喜欢已发布的解决方案,但由于还没有人提到这个解决方案,我认为值得一提的是完整性 .

可以修改 @classmethod 方法以提供不调用默认构造函数( __init__ )的替代构造函数 . 而是使用 __new__ 创建实例 .

如果无法根据构造函数参数的类型选择初始化类型,并且构造函数不共享代码,则可以使用此方法 .

例:

class MyClass(set):

def __init__(self, filename):

self._value = load_from_file(filename)

@classmethod

def from_somewhere(cls, somename):

obj = cls.__new__(cls) # Does not call __init__

obj._value = load_from_somewhere(somename)

return obj

2 years ago

我会使用继承 . 特别是如果存在比孔数更多的差异 . 特别是如果Gouda需要有不同的成员,那么Parmesan .

class Gouda(Cheese):

def __init__(self):

super(Gouda).__init__(num_holes=10)

class Parmesan(Cheese):

def __init__(self):

super(Parmesan).__init__(num_holes=15)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值