上下文
我最近一直在研究python项目,发现模块化非常重要。例如,您创建了一个具有一些属性和使用这些属性的代码行的类,例如
a = A()
print("hi"+a.imA)
如果要将类imA
的{{1}}修改为另一种类型,则必须修改print语句。就我而言,我必须做很多次。这很烦人而且很费时间。 get / set方法可以解决这个问题,但是我听说get / set不是'good python'。那么如何在不使用get和set方法的情况下解决此问题呢?
答案 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})"