有没有办法让@property“ getter / setter”在python中不那么繁重?

时间:2019-02-01 19:26:51

标签: python properties setter getter

我有一个简单的类(Node),它具有一个ID和3个坐标(X,Y,Z)。它的ID必须是整数,并且其坐标是浮动的,因此我使用了以下类定义。

我是OO编程的新手,但是对于这样一个简单的类来说似乎“繁重”。有没有什么办法来压缩这一点,使它少重复?例如,如果我有10个坐标,这将是比较重。

无论如何,我只是想知道是否有更好的方法可以做到这一点。

class Node():

    def __init__(self):
        self.ID = 0
        self.X = 0
        self.Y = 0
        self.Z = 0


    @property
    def ID(self):
        return self._ID

    @ID.setter
    def ID(self,value):
        self._ID = int(value)

    @property
    def X(self):
        return self._X


    @X.setter
    def X(self,value):
        self._X = float(value)

    @property
    def Y(self):
        return self._Y


    @Y.setter
    def Y(self,value):
        self._Y = float(value)

    @property
    def Z(self):
        return self._Z

    @Z.setter
    def Z(self,value):
        self._Z = float(value)

2 个答案:

答案 0 :(得分:0)

你想要的是一个自定义的描述符,而不是property本身。

class Force(object):
    def __init__(self, type_, var):
        self.type = type_
        self.var = "_" + var

    def __get__(self, obj, type):
        # obj is None when the descriptor is accessed via
        # the class, rather than an instance.
        # type is the class through which the descriptor is accessed;
        # not used here.
        if obj is None:
            return self
        return getattr(obj, self.var)

    def __set__(self, obj, value):
        setattr(obj, self.var, self.type(value))

class Node:
    ID = Force(int, 'ID')
    X = Force(float, 'X')
    Y = Force(float, 'Y')
    Z = Force(float, 'Z')

    def __init__(self):
        self.ID = 0
        self.X = 0
        self.Y = 0
        self.Z = 0

Python 3.6添加了对__set_name__方法的支持,该方法在实例化描述符时会自动调用,并接收将描述符分配给其的名称作为参数。

class Force:
    def __init__(self, type_):
        self.type = type_

    def __set_name__(self, owner, name):
        # Owner is the class which contains the descriptor;
        # not used here
        self.var = "_" + name

    def __get__(self, obj, type):
        if obj is None:
            return self
        return getattr(obj, self.var)

    def __set__(self, obj, value):
        setattr(obj, self.var, self.type(value))

class Node:
    ID = Force(int)
    X = Force(float)
    Y = Force(float)
    Z = Force(float)

    def __init__(self):
        self.ID = 0
        self.X = 0
        self.Y = 0
        self.Z = 0

(我敢肯定这可以改善。Force.__init__可以为描述符的每个实例取一个初始值,而不是要求Node.__init__对其进行初始化。)

答案 1 :(得分:0)

在Python中,如果要提供对属性的读写访问,只需将它们设为“公共”即可。

像这样:

class Node():

    def __init__(self):
        self.ID = 0  # No underscores
        self.X = 0   # means
        self.Y = 0   # public
        self.Z = 0   # (by convention)

现在你可以使用你的类是这样的:

n = Node()
n.Z = 9

这很好,因为您仍然可以稍后决定调整读取和写入操作的行为(使用@property装饰器),而无需制动类的接口。

您可能还想研究dataclasses(在Python 3.7中引入):

from dataclasses import dataclass


@dataclass
class Node:
    ID = 0
    X = 0
    Y = 0
    Z: float = 0  # type hints are optional

最后一点:类属性按惯例是小写的。只有常量应该使用完整的大写字母写。