如何保持python项目模块化?

时间:2019-06-11 09:12:20

标签: python

上下文

我最近一直在研究python项目,发现模块化非常重要。例如,您创建了一个具有一些属性和使用这些属性的代码行的类,例如

a = A()
print("hi"+a.imA)

如果要将类imA的{​​{1}}修改为另一种类型,则必须修改print语句。就我而言,我必须做很多次。这很烦人而且很费时间。 get / set方法可以解决这个问题,但是我听说get / set不是'good python'。那么如何在不使用get和set方法的情况下解决此问题呢?

2 个答案:

答案 0 :(得分:1)

第一点:通过使用字符串格式而不是字符串连接,您可以节省很多麻烦,即:

print("hi {}".format(a.imA))

当然,根据a.imA类型实现__str__()__repr__()的方式,最终结果可能不是您所期望的,但是至少不会破坏 代码。

wrt / getters和setters,它们确实被认为是非Python的,因为python对computed attributes有很强的支持,而简单的通用实现可以作为the builtin property type使用。

NB:实际上,当普通的公共属性足够用时,系统地使用实现属性和getter / setter(显式或隐式)是系统的实现属性,这被认为是非Python的因为您总是可以在不破坏客户端代码的情况下将一个简单的属性转换为一个经过计算的属性(当然,假设您不更改属性的类型或语义)-早期的OOPL(如Smalltalk,C ++或Java,这是不可能的)( Smalltalk实际上有点特殊情况,但这是另一个主题。

在您的情况下,如果重点是在不破坏API的情况下更改存储的值的类型,则最简单的规范解决方案是使用property委托给实现属性:< / p>

之前:

class Foo(object):
    def __init__(self, bar):
        # `bar`  is expected to be the string representation of an int.
        self.bar = bar

    def frobnicate(self, val):
        return (int(self.bar) + val) / 2

之后:

class Foo(object):
    def __init__(self, bar):
        # `bar`  is expected to be the string representation of an int.
        self.bar = bar

    # but we want to store it as an int
    @property
    def bar(self):
        return str(self._bar)

    @bar.setter
    def bar(self, value):
        self._bar = int(value)

    def frobnicate(self, val):
        # internally we use the implementation attribute `_bar`
        return (self._bar + val) / 2

现在您将值内部存储为一个int,但公共接口(几乎)完全相同-唯一的区别是,将无法传递的内容传递给int()将在预期的位置上升(设置时),而不是打破最意外的设置(调用.frobnicate()时)

现在请注意,更改公共属性的类型就像更改getter的返回类型(或setter参数的类型)一样,在两种情况下都是 违约-因此,如果您真正想要真正更改A.imA的类型,则getter和属性都无法解决您的问题-getter和setter(或Python计算属性)只能保护您免受实现更改。

编辑:哦,是的:这与模块化无关(这是关于编写解耦的,自包含的代码,它更易于阅读,测试,维护和最终重用),但与封装(旨在使可以适应实施更改的公共接口。

答案 1 :(得分:0)

首先,使用

print(f"hi {a.imA}")  # Python 3.6+

print("hi {}".format(a.imA)) # all Python 3

代替

print("hi"+a.imA)

这样,str将在每个参数上自动调用。

然后在所有类中定义一个__str__函数,以便对任何类进行print总是有效。

class A:
    def __init__(self):
        self._member_1 = "spam"

    def __str__(self):
        return f"A(member 1: {self._member_1})"