以下代码演示了 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)