Есть ли способ сделать @property "getter / setter" менее тяжелым в python? - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть простой класс (Node), который имеет идентификатор и 3 координаты (X, Y, Z).Его ID должен быть целым числом, а его координаты плавающими, поэтому я использовал следующее определение класса.

Я новичок в ОО-программировании, но он кажется "тяжелым" для такого простого класса.Есть ли способ сжать это и сделать его менее повторяющимся?Например, если бы у меня было 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 голосов
/ 01 февраля 2019

В 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), не нарушая интерфейс вашего класса.

Возможно, вы также захотите взглянуть на классы данных (введено в Python 3.7):

from dataclasses import dataclass


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

Последнее замечание: атрибуты класса в нижнем регистре по соглашению.Только константы должны быть написаны заглавными буквами.

0 голосов
/ 01 февраля 2019

Вам нужен собственный дескриптор, а не 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__ для инициализациикаждый.)

...