在类中有很多构造函数是pythonic吗?

时间:2014-06-08 18:04:18

标签: python oop constructor ooad

Point class in Geopy中,我们可以看到很多不同的方法来调用它的构造函数:

>>> p1 = Point(41.5, -81, 0)
>>> p2 = Point(latitude=41.5, longitude=-81)
>>> p3 = Point([41.5, -81, 0])
>>> p4 = Point((41.5, -81))
>>> p5 = Point(p4)
>>> p6 = Point('41.5,-81.0')
>>> p7 = Point('41.5 N -81.0 W')
>>> p8 = Point('-41.5 S, 81.0 E, 2.5km')
>>> p9 = Point('23 26m 22s N 23 27m 30s E 21.0mi')
>>> p10 = Point('''3 26' 22" N 23 27' 30" E''')

我想知道这是好的还是坏的做法,代码味道,如果它违反了一些pythonic成语。实际上这个问题适用于任何OO语言,但我特别询问python

1 个答案:

答案 0 :(得分:4)

可能

def __init__(self, *args, **kwargs):
    # "args" holds a list of positional arguments,
    # "kwargs" holds a dictionary of keyword arguments

    if len(args) == 1 and not kwargs:
        if isinstance(args[0], str):
            if re.match(args[0], some_regex):
                ... # etc

是代码味道

这使初始化代码变得非常糟糕,并且很难将数据安全地传递给构造函数,并使构造函数意外地处理格式错误的数据。

在我看来,它违反了Python的Zen(import this)上的子弹1,2,3,5,7,10,12和17。所以我会说它违反了Pythonic的习语。

<子> •美丽胜过丑陋。 •明确比隐含更好。 •简单比复杂更好。 •Flat优于嵌套。 •可读性计数。 •错误不应该默默地传递。 •面对模棱两可,拒绝猜测的诱惑。 •如果实施难以解释,那么这是一个坏主意。

查看链接代码,我看到了

POINT_PATTERN = re.compile(r"""
    .*?
    (?P<latitude>
      (?P<latitude_direction_front>[NS])?[ ]*
        (?P<latitude_degrees>-?%(FLOAT)s)(?:[%(DEGREE)sD\*\u00B0\s][ ]*
        (?:(?P<latitude_arcminutes>%(FLOAT)s)[%(PRIME)s'm][ ]*)?
        (?:(?P<latitude_arcseconds>%(FLOAT)s)[%(DOUBLE_PRIME)s"s][ ]*)?
        )?(?P<latitude_direction_back>[NS])?)
    %(SEP)s
    (?P<longitude>
      (?P<longitude_direction_front>[EW])?[ ]*
      (?P<longitude_degrees>-?%(FLOAT)s)(?:[%(DEGREE)sD\*\u00B0\s][ ]*
      (?:(?P<longitude_arcminutes>%(FLOAT)s)[%(PRIME)s'm][ ]*)?
      (?:(?P<longitude_arcseconds>%(FLOAT)s)[%(DOUBLE_PRIME)s"s][ ]*)?
      )?(?P<longitude_direction_back>[EW])?)(?:
    %(SEP)s
      (?P<altitude>
        (?P<altitude_distance>-?%(FLOAT)s)[ ]*
        (?P<altitude_units>km|m|mi|ft|nm|nmi)))?
    .*?$
""" % {
    "FLOAT": r'\d+(?:\.\d+)?',
    "DEGREE": format.DEGREE,
    "PRIME": format.PRIME,
    "DOUBLE_PRIME": format.DOUBLE_PRIME,
    "SEP": r'\s*[,;/\s]\s*',
}, re.X)

就个人而言,我印象深刻。要让那个大小的正则表达式如此可读并不容易。但这很难解释或简单


有很好的选择

您可以使用staticmethodclassmethod构造函数。

class Rectangle:
    def __init__(self, a=0, b=0):
        self.a = a # measured in meters
        self.b = b # measured in meters

    @classmethod
    def as_square(cls, a):
        return cls(a, a)

    @classmethod
    def from_inches(cls, a_inches, b_inches):
        inch = 0.0254 # in meters
        return cls(a_inches * inch, b_inches * inch)

    def __repr__(self):
        templ = "<Rectangle: {self.a:.3f} x {self.b:.3f}>"
        return templ.format(self=self)

这允许您从数据中实例化,同时仍然保持不同的方法。

>>> Rectangle(10, 20)
<Rectangle: 10.000 x 20.000>
>>> Rectangle.as_square(100)
<Rectangle: 100.000 x 100.000>
>>> Rectangle.from_inches(2, 4)
<Rectangle: 0.051 x 0.102>

另一方面

您是否看到了int可以解析的内容?

from decimal import Decimal
int(2546)
#>>> 134
int(17657.342)
#>>> 17657
int(Decimal("134"))
#>>> 2546
int("5443")
#>>> 5443
int("543", 34)
#>>> 5919
int("໖᭗")
#>>> 67

说出我喜欢的内容,我不会说服很多人没有这方面的先例。