Перепиши данный код на Python 

#include <cstdio>
#include <iostream>
#include <vector>
#include <math.h>

class Drob {
private:
	int chisl;
	int znam;
public:
	Drob() {
		chisl = 0;
		znam = 0;
	}

	Drob(int ch, int zn) {
		chisl = ch;
		znam = zn;
	}

	int get_ch() {
		return chisl;
	}

	int get_zn() {
		return znam;
	}

	void set_ch(int new_ch) {
		chisl = new_ch;
	}

	void set_zn(int new_zn) {
		znam = new_zn;
	}

	// Метод возвращает представление дроби Фарея при помощи цепной дроби
	std::vector<int> chain_drob() {
		std::vector<int> vect;
		int celoe = chisl / znam, ostat = chisl % znam, r_i = chisl, r_j = znam;
		vect.push_back(celoe);
		printf("%d = %d * %d + %d\n", r_i, celoe, r_j, ostat);
		do {
			r_i = r_j;
			r_j = ostat;
			celoe = r_i / ostat;
			ostat = r_i % ostat;
			printf("%d = %d * %d + %d\n", r_i, celoe, r_j, ostat);
			vect.push_back(celoe);
		} while (ostat != 0);
		return vect;
	}

	// Метод для нахождения подходящих дробей
	void get_podhod_drob(std::vector<int> v, std::vector<int> &vP, std::vector<int> &vQ) {
		int P = -1, Q = -1;
		for (int i = 0; i < v.size(); i++) {
			if (i == 0) {
				P = v[0];
				Q = 1;
			}
			else if (i == 1) {
				P = v[0] * v[1] + 1;
				Q = v[1];
			}
			else {
				P = v[i] * vP[i - 1] + vP[i - 2];
				Q = v[i] * vQ[i - 1] + vQ[i - 2];
			}
			vP.push_back(P);
			vQ.push_back(Q);
			std::cout << "P" << i << " = " << vP[i] << " " << "Q" << i << " = " << vQ[i] << "\n";
		}
	}
	
	// Метод для расчета значений на основе расширенного алгоритма Евклида
	void main_calculations(int* start_matr, std::vector<int> a, Drob& res) {
		int iter = 0, bi, ui, vi;
		int bi_2, bi_1; // первая переменная это b(i-2), вторая b(i-1)
		int ui_2, ui_1; // первая переменная это u(i-2), вторая u(i-1)
		int vi_2, vi_1; // первая переменная это v(i-2), вторая v(i-1)
		printf("%2s %5s %3s %5s %5s\n", "i", "bi", "ai", "ui", "vi");
		while (iter < a.size() + 2) {
			if (iter == 0) {
				bi = this->get_ch();
				ui = start_matr[0];
				vi = start_matr[1];
				bi_2 = bi;
				ui_2 = ui;
				vi_2 = vi;
				printf("%2d %5d %3c %5d %5d\n", iter - 2, bi, '-', ui, vi);
			}
			else if (iter == 1) {
				bi = this->get_zn();
				ui = start_matr[2];
				vi = start_matr[3];
				bi_1 = bi;
				ui_1 = ui;
				vi_1 = vi;
				printf("%2d %5d %3c %5d %5d\n", iter - 2, bi, '-', ui, vi);
			}
			else {
				bi = -bi_1 * a[iter - 2] + bi_2;
				ui = ui_1 * a[iter - 2] + ui_2;
				vi = vi_1 * a[iter - 2] + vi_2;
				bi_2 = bi_1; // новое значение b(i-2)
				bi_1 = bi;   // новое значение b(i-1)
				ui_2 = ui_1; // новое значение u(i-2)
				ui_1 = ui;   // новое значение u(i-1)
				vi_2 = vi_1; // новое значение v(i-2)
				vi_1 = vi;   // новое значение v(i-1)
				printf("%2d %5d %3d %5d %5d\n", iter - 2, bi, a[iter - 2], ui, vi);
				res.set_ch(ui);
				res.set_zn(vi);
			}
			iter += 1;
		}
		if (res.get_zn() < 0) {
			res.set_ch(0 - res.get_ch());
			res.set_zn(abs(res.get_zn()));
		}
	}

	// Метод для вычитания дробей
	Drob sub(std::vector<int> a, Drob right_oper) {
		int* start_matr = new int [4] {
			-right_oper.get_ch(), right_oper.get_zn(),
			right_oper.get_zn(), 0
		};
		Drob res;
		this->main_calculations(start_matr, a, res);
		delete[] start_matr;
		return res;
	}

	// Метод для сложения дробей
	Drob add(std::vector<int> a, Drob right_oper) {
		int* start_matr = new int [4] {
			right_oper.get_ch(), right_oper.get_zn(),
			right_oper.get_zn(), 0
		};
		Drob res;
		this->main_calculations(start_matr, a, res);
		delete[] start_matr;
		return res;
	}

	// Метод для перемножения дробей
	Drob mult(std::vector<int> a, Drob right_oper) {
		int* start_matr = new int [4] {
			0, right_oper.get_zn(),
			right_oper.get_ch(), 0
		};
		Drob res;
		this->main_calculations(start_matr, a, res);
		delete[] start_matr;
		return res;
	}

	// Метод для деления дробей
	Drob div(std::vector<int> a, Drob right_oper) {
		int* start_matr = new int [4] {
			0, right_oper.get_ch(),
			right_oper.get_zn(), 0
		};
		Drob res;
		this->main_calculations(start_matr, a, res);
		delete[] start_matr;
		return res;
	}

	// Метод для расчета скалярного произведения новой арифметикой
	Drob scalar_mult_1(Drob* arr_drA, Drob* arr_drB, const int size) {
		Drob res(0, 0);
		for (int i = 0; i < size; i++) {
			Drob cur_res = arr_drA[i].mult(arr_drA[i].chain_drob(), arr_drB[i]);
			printf("------------------------------\n");
			printf("Итерация # %d: %5d / %-5d\n", i, cur_res.get_ch(), cur_res.get_zn());
			if (i == 0) {
				res.set_ch(cur_res.get_ch());
				res.set_zn(cur_res.get_zn());
			}
			else res = res.add(res.chain_drob(), cur_res);
			printf("Промежуточная сумма: %5d / %-5d\n", res.get_ch(), res.get_zn());
			printf("------------------------------\n");
		}
		return res;
	}
};

// Функция для расчета скалярного произведения обычной арифметикой
double scalar_mult_2(double* vect1, double* vect2, const int size) {
	double res = 0;
	for (int i = 0; i < size; i++)
		res += vect1[i] * vect2[i];
	return res;
}

int main() {
	setlocale(LC_ALL, "ru");


	const int n = 3;
	Drob* arr_a = new Drob[n]{
		Drob(1, 2),
		Drob(2, 3),
		Drob(5, 12)
	}, * arr_b = new Drob[n]{
		Drob(6, 4),
		Drob(3, 1),
		Drob(10, 13)
	};
	Drob r = arr_a->scalar_mult_1(arr_a, arr_b, n);
	printf("Результат скалярного произведения: %5d / %-5d\n", r.get_ch(), r.get_zn());
	printf("Результат скалярного произведения 1: %5.16f\n", double(r.get_ch()) / double(r.get_zn()));
	delete[] arr_a, arr_b;


	double* v_a = new double [n] { 1.0 / 2, 2.0 / 3, 5.0 / 12},
		* v_b = new double [n] {6.0 / 4, 3.0 / 1, 10.0 / 13};
	double res = scalar_mult_2(v_a, v_b, n);
	printf("Результат скалярного произведения 2: %5.16f\n", res);
	delete[] v_a, v_b;
}