在 OOP 中处理属性的 Pythonic 方式
Pythonic Way of Handling Attributes in OOP
我的任务是使用 OOP 创建一个程序,阅读他们给我的有关此任务的文档,我注意到许多使用此命名约定的代码示例:
class User:
def __init__(self, x, y, z):
self.__x = x
self.__y = y
self.__z = z
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
@property
def z(self):
return self.__z
这是pythonic方式吗?我会使用简单的属性,像这样:
class User:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
我对 OOP 没有太多经验,所以也许我遗漏了一些东西,在第一个例子中,你有命名重整来保护属性,但我不知道为什么它是必要的,至于我已经看到对 class 属性的所有修改仅在每个 class 内进行,而不是从外部进行。关于为什么第一个例子更有意义的任何想法?
如果它是内部 class 用法的私有 属性,它实际上是 python 编写自己的 classes 的方式,它被称为私有名称修改:
有关详细信息,请参阅 The Python Language Reference:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used. If the transformed name is extremely long (longer than 255 characters), implementation defined truncation may happen. If the class name consists only of underscores, no transformation is done.
这个模式:
class User:
def __init__(self, x, y, z):
self.__x = x
@property
def x(self):
return self.__x
如果您想公开 x
以供阅读,但不希望人们不小心设置它,则更有意义。
你当然可以加一个setter:
@x.setter
def x(self, value):
self.__x_was_set = True
self.__x = value
如果您需要设置 属性 的一些副作用(我用 __x_was_set
添加了一个微不足道的副作用,但它可以是任何东西,而且非常复杂)。
如果您都不需要,那么这样做更有意义:
class User:
def __init__(self, x):
self.x = x
或者您甚至可以使用数据类:
@dataclass
class User:
x: str
(或者当然是 x
需要的任何类型)
我发现来自 Java 或 C# 等语言的开发人员倾向于过度使用 getter/setter 模式,因为这是他们更习惯的。我想说,从 Python 的角度来看,越简单、越易读越好。更重要的是因为读取和设置user.__x
仍然是可能的,所以实际上没有添加保护,它只是添加代码。
我的任务是使用 OOP 创建一个程序,阅读他们给我的有关此任务的文档,我注意到许多使用此命名约定的代码示例:
class User:
def __init__(self, x, y, z):
self.__x = x
self.__y = y
self.__z = z
@property
def x(self):
return self.__x
@property
def y(self):
return self.__y
@property
def z(self):
return self.__z
这是pythonic方式吗?我会使用简单的属性,像这样:
class User:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
我对 OOP 没有太多经验,所以也许我遗漏了一些东西,在第一个例子中,你有命名重整来保护属性,但我不知道为什么它是必要的,至于我已经看到对 class 属性的所有修改仅在每个 class 内进行,而不是从外部进行。关于为什么第一个例子更有意义的任何想法?
如果它是内部 class 用法的私有 属性,它实际上是 python 编写自己的 classes 的方式,它被称为私有名称修改:
有关详细信息,请参阅 The Python Language Reference:
Private name mangling: When an identifier that textually occurs in a class definition begins with two or more underscore characters and does not end in two or more underscores, it is considered a private name of that class. Private names are transformed to a longer form before code is generated for them. The transformation inserts the class name, with leading underscores removed and a single underscore inserted, in front of the name. For example, the identifier __spam occurring in a class named Ham will be transformed to _Ham__spam. This transformation is independent of the syntactical context in which the identifier is used. If the transformed name is extremely long (longer than 255 characters), implementation defined truncation may happen. If the class name consists only of underscores, no transformation is done.
这个模式:
class User:
def __init__(self, x, y, z):
self.__x = x
@property
def x(self):
return self.__x
如果您想公开 x
以供阅读,但不希望人们不小心设置它,则更有意义。
你当然可以加一个setter:
@x.setter
def x(self, value):
self.__x_was_set = True
self.__x = value
如果您需要设置 属性 的一些副作用(我用 __x_was_set
添加了一个微不足道的副作用,但它可以是任何东西,而且非常复杂)。
如果您都不需要,那么这样做更有意义:
class User:
def __init__(self, x):
self.x = x
或者您甚至可以使用数据类:
@dataclass
class User:
x: str
(或者当然是 x
需要的任何类型)
我发现来自 Java 或 C# 等语言的开发人员倾向于过度使用 getter/setter 模式,因为这是他们更习惯的。我想说,从 Python 的角度来看,越简单、越易读越好。更重要的是因为读取和设置user.__x
仍然是可能的,所以实际上没有添加保护,它只是添加代码。