我不知道正确的用语,所以在网上找不到关于此的任何信息。
使用以下示例代码:
public void convert2JSON(URL inputJson, File outputPojoDirectory, String packageName, String className) throws IOException
{
JCodeModel codeModel = new JCodeModel();
URL source = inputJson;
GenerationConfig config = new DefaultGenerationConfig()
{
@Override
public boolean isGenerateBuilders()
{ // set config option by overriding method
return true;
}
public SourceType getSourceType()
{
return SourceType.JSON;
}
};
SchemaMapper mapper = new SchemaMapper(new RuleFactory(config, new Jackson2Annotator(config), new SchemaStore()), new SchemaGenerator());
mapper.generate(codeModel, className, packageName, source);
codeModel.build(outputPojoDirectory);
}
现在,说我想检查一下水果是否为红色:
def Fruit(object):
def __init__(self, color):
self._color = color
def color(self):
return self._color
可以很好地工作。但是
def isRed(self):
if self._color == "red":
return True
return False
具有 def isRed(self):
if self.color() == "red":
return True
return False
函数是一种好习惯吗? (我假设这是因为我正在攻读的是MIT教授的课程,他在课堂上这样做,并希望学生在功课上也做同样的事情。)
这两个示例中的任何一个都不同吗?为什么习惯用getProperty
来简单地引用该属性呢?
编辑:添加了下划线以使self.property
成为惯例。
答案 0 :(得分:1)
TL; DR:并非所有常规编程最佳实践都不是Python最佳实践。 Getter和setter方法是常规(OOP)最佳实践,但不是Python最佳实践。相反,请尽可能使用普通的Python属性,并根据需要切换到Python @property
。
它有许多面向对象的编程语言(例如Java和C ++),它被认为是一种很好的做法:
为什么?
让我们详细了解这些:
面向对象的核心思想之一是,将小数据块的定义与与该数据相关的功能捆绑在一起,使命令式/“结构化” /程序化程序更易于管理和发展。
这些捆绑包称为“对象”。每个“类”都是具有相同数据结构(虽然可能具有不同的数据)和相同相关功能的组对象的模板。
数据定义是类(对象的“属性”)的(非静态)数据成员。相关功能被编码为功能成员(“方法”)。
这也可以被视为构建新的用户定义类型的方法。 (每个类都是一个类型,每个对象有点像一个值。)
通常,与已经提供的数据成员的类型相比,方法需要更多有关属性值的保证才能正常工作。假设您有
class Color() {
float red;
float green;
float blue;
float hue() {
return // ... some formula
}
float brightness {
return // ... some formula
}
}
如果red
,green
和blue
的范围是[0,1],则这些方法的实现可能取决于该事实。同样,如果它们在[0,256)范围内。不管类内部的约定如何,维护该类的方法都是它的任务,并且仅将值分配给可接受的数据成员。
尽管通常,对于有意义的面向对象程序,不同类的对象必须进行交互。但是您不希望仅仅因为您正在访问其他类而考虑其他类的内部约定,因为这将需要大量查找才能找出那些约定。因此,您不应从该类之外的代码中为该类的对象分配数据成员。
为避免这种错误或过失,在这些语言中广为接受的最佳实践是将所有数据成员声明为私有。但这意味着它们也不能从外面读取!如果外部不关心该值,则可以通过提供一种非私有的getter方法来解决此问题,该方法除了提供属性值外什么也不做。
说外面的东西(例如另一个类)必须能够设置类的某些属性的值。并且说,除了该属性的类型已经施加的限制之外,没有任何其他限制。 您应该将该属性设为公开吗?(仍然假设在Python中不是 !)否!,相反,提供了一个setter方法除了将值作为参数并将其分配给属性外什么也没做!
似乎有点沉闷,那为什么呢?这样我们以后可以改变主意!
假设您每次颜色对象的红色分量发生更改时都要登录到控制台/终端(标准输出)。 (出于任何原因。)
在(setter)方法中,添加一行代码,然后执行此操作,而无需调用方进行任何更改。
但是,如果您需要首先从分配给公共属性切换到调用setter方法,那么所有为这些属性分配的代码段(到那时可能很多)也必须更改! (不要忘记将属性设为私有,这样就不会遗忘任何属性。)
因此,最好从一开始就只具有私有属性,并在类外的代码必须能够设置值时添加setter方法。
假设您刚刚注意到,对于您的应用程序,颜色实际上应该在内部以色相,值和饱和度表示,而不是红色,绿色和蓝色分量。
如果您有setter和getter方法,则由于必要的转换计算,红色,绿色和蓝色的方法将变得更加复杂。 (但是,亮度和色调方法将变得更加简单。)不过,与必须更改使用该类的类之外的所有代码相比,更改它们的工作量要少得多。由于界面保持不变,呼叫者根本不需要更改,也不会发现任何差异。
但是,如果您需要首先从分配给公共属性转换为调用setter方法,那么……我们去过那里,不是吗?
因此,访问器方法方法(我们称为getter和setters)可帮助您将类的公共接口与其内部实现分离,从而将其对象与用户分离。这样,您就可以在不破坏公共接口的情况下更改内部实现,从而不必在使用类时更改使用类的代码。
需要一个只能从外部读取而不能从外部写入的属性吗?简便:仅提供 getter 方法,但不提供setter方法(并且属性本身是私有的)。
不常见,但比您想像的更常见:
需要一个只能从外部只能写但不能从外部读取的属性吗?简便:仅提供 setter方法,但不提供getter方法(并且属性本身是私有的)。
不确定是否应该从班级外部访问(和访问)您的属性? 将其设为私有,并且不要暂时提供任何获取和设置方法。您以后可以随时添加它们。 (然后然后考虑他们应该具有的可见度级别。)
如您所见,没有理由在可变对象中拥有非私有属性。 (假设运行时开销对您的应用程序不重要(实际上可能不重要),或者由编译器进行了优化(可能至少部分地)。)
请注意,属性和方法的“可见性”级别并不意味着提供应用程序安全性或隐私性(不是)。它们是帮助程序员犯错误的工具(通过避免犯错误,避免他们偶然访问不应被他们访问的东西),但它们不会阻止对抗性程序员访问这些东西。或者,就此而言,诚实的程序员认为自己知道自己在做什么(无论他们是否知道),并且愿意冒险。
尽管Python也是强制性的,“结构化的”,过程性的且非常面向对象的,但它采用了更为宽松的可见性方法。 Python中没有真正的“私有”可见性级别,也没有“受保护”或“包”(Java中的默认)级别。
本质上, Python类中的所有内容都是公开的。
当将Python用作快速,肮脏的即席解决方案的脚本语言时,这很有意义,您可能会编写一次代码,然后扔掉(或者不做进一步开发就保持这种状态)。
如果您使用Python开发了更多涉及的应用程序(并且使用Python肯定是可行的,并且也做了很多事情),则可能需要区分类的公共接口及其内部实现细节。 Python提供了两个级别的“隐藏”内部成员(函数,数据属性):
_
前缀__
前缀以_
开头的名称向命名空间之外的所有人(无论是类,模块还是程序包)发出信号:
除非您知道自己在做什么,否则不应该访问它。我(该名称空间中东西的实现者)可能会随意更改它,因此您可能不知道通过访问它将要做什么。 东西可能会破裂。如果是的话,那将是您的(访问它的那个)错误,而不是我的(实现它的那个)。该成员不属于此命名空间的公共接口。
是的,您可以访问它。 这并不意味着您应该。我们都是成年人。负责。
即使您还不是成年人,也应该坚持这一点。
以__
开头的名称向命名空间之外的所有人(无论是类,模块还是程序包)发出信号:
仅与
_
相同,甚至更强!
此外,并且仅当名称空间 是一个类(且属性名称以不超过一个下划线结尾)时:>
为确保您不会意外地从外部访问这些内容,请使用Python "mangles" the names of these attributes从类外部进行访问。结果名称是完全可预测的(_
+(简单的类名称+原始属性名称),因此您仍然仍然可以访问这些内容,但是您肯定不会简单地误认为
此外,此可以有助于避免基类成员及其子类成员之间的名称冲突。 (但是,如果类共享相同的类名(如使用“简单类名”,不包括模块和包),则将无法正常工作。)
在任何一种情况下,您可能都有充分的理由无论如何都要访问这些值(例如,用于调试),并且Python不想在这样做时妨碍您的工作(或使用名称修改功能,最多只能稍微改变一下)。< / p>
因此,由于Python中没有真正的私有工具,因此我们无法应用Java和C ++中的模式/样式。但是我们可能仍然需要稳定的接口来进行认真的编程。
在Python中,您可以 用方法替换data属性,而不必更改其用户。 Pils19's answer提供了一个示例:
class Fruit(object):
def __init__(self, color):
self._color = color
@property
def color(self):
return self._color
(此装饰器here的文档。)
如果我们还提供了一个属性设定器方法和一个属性设定器方法...
class Fruit(object):
def __init__(self, color):
self._color = color
@property
def color(self):
return self._color
@color.setter
def color(self, c):
self._color = c
@color.deleter
def color(self):
del self._color
这将相当于一个简单的data属性:
class Fruit(object):
def __init__(self, c):
self.color = c
但是现在我们拥有方法的所有自由。我们可以忽略其中的任何一个(最常见的是只具有getter,因此您具有只读属性),我们可以赋予它们其他或不同的行为,等等。
这是Python中推荐的方法:
_
的前缀以获取实施细节我假设[有一种在Python中定义非属性获取器和设置器的良好做法],因为我正在学习的MIT教授的课程与他的课程相同,并希望学生也能做到这一点在他们的作业上。
您确定这是您的教授所做的,还是他使用了Python的属性机制?
如果他这样做了,这是关于Python的一类,还是恰好发生在示例中使用Python(而您的教授也使用它来演示实际上仅适用于其他语言的东西)?
我们不要忘记:即使是麻省理工学院的教授,也可能被迫教授并非该学科各个方面的专家的课程。
答案 1 :(得分:0)
通常,@Property
装饰器对您来说是一个好习惯。并具有带有单个下划线的内部属性。对于您来说,它看起来像:
class Fruit(object):
def __init__(self, color):
self._color = color
@property
def color(self):
return self._color