Когда я должен использовать классы и метод self в Python? - PullRequest
2 голосов
/ 11 мая 2019

Я пытался написать программу на Python для расчета местоположения точки на основе расстояния от 4 якорей.Я решил рассчитать это как точки пересечения 4 кругов.

У меня есть вопрос, касающийся не алгоритма, а использования классов в такой программе.У меня нет особого опыта работы с ООП.Действительно ли здесь необходимо использовать классы или это хоть как-то улучшает программу?

Вот мой код:

import math

class Program():
    def __init__(self, anchor_1, anchor_2, anchor_3, anchor_4, data):
        self.anchor_1 = anchor_1
        self.anchor_2 = anchor_2
        self.anchor_3 = anchor_3
        self.anchor_4 = anchor_4



    def intersection(self, P1, P2, dist1, dist2): 
        PX = abs(P1[0]-P2[0])               
        PY = abs(P1[1]-P2[1])
        d = math.sqrt(PX*PX+PY*PY)   

        if d < dist1+ dist2 and d > (abs(dist1-dist2)):

            ex = (P2[0]-P1[0])/d
            ey = (P2[1]-P1[1])/d

            x = (dist1*dist1 - dist2*dist2 + d*d) / (2*d)
            y = math.sqrt(dist1*dist1 - x*x)

            P3 = ((P1[0] + x * ex - y * ey),(P1[1] + x*ey + y*ex))
            P4 = ((P1[0] + x * ex + y * ey),(P1[1] + x*ey - y*ex))  

            return (P3,P4)
        elif d == dist1 + dist2:
            ex = (P2[0]-P1[0])/d
            ey = (P2[1]-P1[1])/d

            x = (dist1*dist1 - dist2*dist2 + d*d) / (2*d)
            y = math.sqrt(dist1*dist1 - x*x)

            P3 = ((P1[0] + x * ex + y * ey),(P1[1] + x*ey + y*ex))

            return(P3, None)
        else:
            return (None, None)





    def calc_point(self, my_list):
        if len(my_list) != 5:
            print("Wrong data")
        else:
            tag_id = my_list[0];
            self.dist_1 = my_list[1];
            self.dist_2 = my_list[2];
            self.dist_3 = my_list[3];
            self.dist_4 = my_list[4];

        (self.X1, self.X2) = self.intersection(self.anchor_1, self.anchor_2, self.dist_1, self.dist_2)
        (self.X3, self.X4) = self.intersection(self.anchor_1, self.anchor_3, self.dist_1, self.dist_3)
        (self.X5, self.X6) = self.intersection(self.anchor_1, self.anchor_4, self.dist_1, self.dist_4)





with open('distances.txt') as f:
    dist_to_anchor = f.readlines()

dist_to_anchor = [x.strip() for x in dist_to_anchor]
dist_to_anchor = [x.split() for x in dist_to_anchor]
for row in dist_to_anchor:
    for k in range(0,5):
        row[k] = float(row[k])
anchor_1= (1,1)
anchor_2 = (-1,1)
anchor_3 = (-1, -1)
anchor_4 = (1, -1)

My_program = Program (anchor_1, anchor_2, anchor_3, anchor_4, dist_to_anchor)
My_program.calc_point(dist_to_anchor[0])

print(My_program.X1)
print(My_program.X2)
print(My_program.X3)
print(My_program.X4)
print(My_program.X5)
print(My_program.X6)

Кроме того, я не совсем понимаю, где я должениспользуйте ключевое слово self и там, где оно не нужно.

Ответы [ 2 ]

4 голосов
/ 11 мая 2019

Классы и ООП являются ИМХО всегда хорошим выбором, используя их, вы сможете лучше организовать и повторно использовать свой код, вы можете создавать новые классы, которые наследуются от существующего класса, чтобы расширять его функциональность (наследование) или изменятьего поведение, если вам нужно (полиморфизм), а также инкапсуляция внутренних частей вашего кода, чтобы он стал более безопасным (хотя в Python нет реальной инкапсуляции).

В вашем конкретном случае, например, высоздание калькулятора, который использует технику для вычисления пересечения, если кто-то другой, использующий ваш класс, хочет изменить это поведение, он может переопределить функцию (это Полиморфизм в действии):

class PointCalculator:
    def intersection(self, P1, P2, dist1, dist2): 
        # Your initial implementation

class FasterPointCalculator(PointCalculator):
    def __init__(self):
        super().__init__()

    def intersection(self, P1, P2, dist1, dist2):
        # New implementation

Или вы можетерасширять класс в будущем:

class BetterPointCalculator(PointCalculator):
        def __init__(self):
            super().__init__()

        def distance(self, P1, P2):
            # New function

Вам может потребоваться инициализировать ваш класс некоторыми необходимыми данными, и вы можете не захотеть, чтобы пользователи могли изменять его, вы можете указать инкапсуляцию, назвав свои переменные с помощьюподчеркивание:

class PointCalculator:
    def __init__(self, p1, p2):
        self._p1 = p1
        self._p2 = p2

    def do_something(self): 
        # Do something with your data
        self._p1 + self._p2

Как вы, наверное, заметили, self - это pоценивается автоматически при вызове функции, она содержит ссылку на текущий объект (экземпляр класса), поэтому вы можете получить доступ ко всему объявленному в нем, например к переменным _p1 и _p2 в приведенном выше примере.

Вы также можетесоздайте методы класса (статические методы), и тогда у вас не будет доступа к self, вы должны сделать это для методов, которые выполняют общие вычисления, или для любой операции, которая не нуждается в конкретном экземпляре, ваш метод пересечения может быть хорошим кандидатом, например

class PointCalculator:

    @staticmethod
    def intersection(P1, P2, dist1, dist2): 
        # Return the result

Теперь вам не нужен экземпляр PointCalculator, вы можете просто вызвать PointCalculator.intersection(1, 2, 3, 4)

Еще одним преимуществом использования классов может быть оптимизация памяти, Python будет удалять объекты из памяти, когда онивыйдите из области видимости, поэтому, если у вас длинный сценарий с большим количеством данных, они не будут освобождены из памяти, пока сценарий не завершится.

Сказав это, для небольших служебных сценариев, которые выполняют очень специфические задачи,например, установить приложение, настроить какой-либо сервис,без какой-либо задачи администрирования ОС и т. д. простой сценарий полностью подходит, и это одна из причин популярности Python.

2 голосов
/ 11 мая 2019

Нет, то, как вы пишете свои классы кода, не нужно и делает код заметно хуже.

Давайте посмотрим, как бы вы выполнили некоторую геометрию в процедурном стиле против объектно-ориентированного стиля.

Процедурное программирование - это написание функций (процедур), которые принимают некоторые данные, обрабатывают их и возвращают некоторые данные.

def area_circle(radius):
    return math.pi * radius * radius

print(area_circle(5))

У вас есть радиус круга, и вы получите площадь.

Объектно-ориентированное программирование - это запрос данных для выполнения каких-либо задач.

class Circle():
    def __init__(self, radius=0):
        self.radius = radius

    def area(self):
        return math.pi * self.radius * self.radius

circle = Circle(radius=5)
print(circle.area())

У вас есть круг, и вы спрашиваете его о его площади.

Кажется, много лишнего кода для очень тонкого различия.

Что теперь произойдет, если вам понадобится рассчитать другие фигуры? Вот квадрат в ОО.

class Square():
    def __init__(self, side=0):
        self.side = side

    def area(self):
        return self.side * self.side

square = Square(side=5)
print(square.area())

А теперь процедурный.

def area_square(side):
    return side * side
print(area_square(5));

И что? Что происходит, когда вы хотите вычислить площадь формы ? Процедурно вам придется передавать данные для различных типов фигур и сообщать вашей функции области, что это за форма, и функция области должна знать, как интерпретировать данные формы для различных форм.

def area(type, shape_data):
    if type == 'circle':
        return area_circle(shape_data)
    elif type == 'square':
        return area_square(shape_data)

print(area('circle', 5))
print(area('square', 5))

В ОО это так.

print(shape.area())

Будет ли shape Circle или Square, shape.area() работать. Вам, человеку, использующему форму, не нужно ничего знать о том, как она работает.

По мере добавления новых фигур процедурный код становится все более сложным везде, где ему необходимо использовать формы. Код OO остается точно таким же, вместо этого вы пишете больше классов.

И в этом смысл ОО: скрывать детали того, как работа выполняется за интерфейсом. Для вашего кода не имеет значения, как он работает, если результат одинаков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...