Python 继承


以下代码演示了 Pyhton 的基本继承概念,展示了如何在父类中调用子类方法。

import random


class Shape:
    def is_inside(self, x, y):
        raise NotImplementedError("Subclasses should implement this!")

    def monte_carlo_area(self, num_samples):
        inside_count = 0
        x_min, x_max, y_min, y_max = self.get_bounds()
        for _ in range(num_samples):
            x = random.uniform(x_min, x_max)
            y = random.uniform(y_min, y_max)
            if self.is_inside(x, y):
                inside_count += 1
        return (inside_count / num_samples) * (x_max - x_min) * (y_max - y_min)

    def get_bounds(self):
        raise NotImplementedError("Subclasses should implement this!")

    def print_shape(self):
        x_min, x_max, y_min, y_max = self.get_bounds()

        # 计算缩放因子
        char_correct = 2  # 字符比例修正
        width = 20
        height = 10
        scale_x = (
            (width - 1) * char_correct / (x_max - x_min) if (x_max - x_min) != 0 else 1
        )
        scale_y = (height - 1) / (y_max - y_min) if (y_max - y_min) != 0 else 1
        scale = min(scale_x, scale_y)
        print(f"Bounds: x({x_min}, {x_max}), y({y_min}, {y_max})")
        print("Shape representation:")

        for j in range(height):
            y = y_max - j / scale  # 计算实际 y 坐标
            for i in range(width):
                x = x_min + i / scale / char_correct  # 计算实际 x 坐标
                if self.is_inside(x, y):  # 缩放后判断
                    print("*", end="")
                else:
                    print(" ", end="")
            print()  # 换行


class Intersection(Shape):
    def __init__(self, *shapes):
        self.shapes = shapes
        self.bounds = self.calculate_bounds()

    def calculate_bounds(self):
        # 计算所有形状的边界,只调用一次
        x_min_array = []
        x_max_array = []
        y_min_array = []
        y_max_array = []

        for shape in self.shapes:
            x_min, x_max, y_min, y_max = shape.get_bounds()
            x_min_array.append(x_min)
            x_max_array.append(x_max)
            y_min_array.append(y_min)
            y_max_array.append(y_max)

        return (max(x_min_array), min(x_max_array), max(y_min_array), min(y_max_array))

    def is_inside(self, x, y):
        return all(shape.is_inside(x, y) for shape in self.shapes)

    def get_bounds(self):
        return self.bounds


class Union(Shape):
    def __init__(self, *shapes):
        self.shapes = shapes
        self.bounds = self.calculate_bounds()

    def calculate_bounds(self):
        # 计算所有形状的边界,只调用一次
        x_mins = []
        x_maxs = []
        y_mins = []
        y_maxs = []

        for shape in self.shapes:
            x_min, x_max, y_min, y_max = shape.get_bounds()
            x_mins.append(x_min)
            x_maxs.append(x_max)
            y_mins.append(y_min)
            y_maxs.append(y_max)

        return (min(x_mins), max(x_maxs), min(y_mins), max(y_maxs))

    def is_inside(self, x, y):
        return any(shape.is_inside(x, y) for shape in self.shapes)

    def get_bounds(self):
        return self.bounds


class Difference(Shape):
    def __init__(self, shape1: Shape, shape2: Shape):
        self.shape1 = shape1
        self.shape2 = shape2

    def is_inside(self, x, y):
        return self.shape1.is_inside(x, y) and not self.shape2.is_inside(x, y)

    def get_bounds(self):
        return self.shape1.get_bounds()


class XOR(Shape):
    def __init__(self, shape1, shape2):
        self.shape1 = shape1
        self.shape2 = shape2
        self.bounds = self.calculate_bounds()

    def calculate_bounds(self):
        x_min1, x_max1, y_min1, y_max1 = self.shape1.get_bounds()
        x_min2, x_max2, y_min2, y_max2 = self.shape2.get_bounds()
        return (
            min(x_min1, x_min2),
            max(x_max1, x_max2),
            min(y_min1, y_min2),
            max(y_max1, y_max2),
        )

    def is_inside(self, x, y):
        return self.shape1.is_inside(x, y) != self.shape2.is_inside(x, y)

    def get_bounds(self):
        return self.bounds


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

    def is_inside(self, x, y):
        return (x - self.x) ** 2 + (y - self.y) ** 2 <= self.radius**2

    def get_bounds(self):
        return (
            -self.radius + self.x,
            self.radius + self.x,
            -self.radius + self.y,
            self.radius + self.y,
        )


class Square(Shape):
    def __init__(self, side_length, x=0, y=0):
        self.side_length = side_length
        self.x = x
        self.y = y

    def is_inside(self, x, y):
        return (
            -self.side_length / 2 <= x - self.x <= self.side_length / 2
            and -self.side_length / 2 <= y - self.y <= self.side_length / 2
        )

    def get_bounds(self):
        half_side = self.side_length / 2
        return (
            -half_side + self.x,
            half_side + self.x,
            -half_side + self.y,
            half_side + self.y,
        )


class Polygon(Shape):
    def __init__(self, vertices):
        self.vertices = vertices

    def is_inside(self, x, y):
        n = len(self.vertices)
        inside = False
        p1x, p1y = self.vertices[0]

        for i in range(n + 1):
            p2x, p2y = self.vertices[i % n]
            if y > min(p1y, p2y):
                if y <= max(p1y, p2y):
                    if x <= max(p1x, p2x):
                        if p1y != p2y:
                            x_inters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                        if p1x == p2x or x <= x_inters:
                            inside = not inside
            p1x, p1y = p2x, p2y

        return inside

    def get_bounds(self):
        x_coords, y_coords = zip(*self.vertices)
        return (min(x_coords), max(x_coords), min(y_coords), max(y_coords))


# 示例用法
circle = Circle(radius=1, x=1, y=1)
square = Square(side_length=2)
polygon = Polygon([(5, 0), (6, 6), (0, 7)])
intersection = Intersection(circle, square)
union = Union(circle, square)
difference_a = Difference(circle, square)
difference_b = Difference(square, circle)
xor = XOR(circle, square)


def p(shape: Shape):
    shape.print_shape()
    print(
        f"Estimated area of the {type(shape).__name__}: {shape.monte_carlo_area(10000)}"
    )


p(circle)
p(square)
p(intersection)
p(union)
p(difference_a)
p(difference_b)
p(xor)
p(polygon)