面向对象练习题
随机数生成类
要求:
- 可指定生成数字的个数、生成的数值范围;
- 运行时还可以调整每批生成数字的个数。
方法1
import random
class NumberGenerator:
def __init__(self, num_count=1, range_min=0, range_max=100):
self.num_count = num_count
self.range_min = range_min
self.range_max = range_max
def generate_numbers(self):
return [random.randint(self.range_min, self.range_max) for _ in range(self.num_count)]
def set_num_count(self, num_count):
self.num_count = num_count
def set_range(self, range_min, range_max):
self.range_min = range_min
self.range_max = range_max
## 示例用法
## 创建一个生成器对象
generator = NumberGenerator()
## 生成默认数量的数字
print("Generated numbers:", generator.generate_numbers())
## 设置新的数字个数
generator.set_num_count(3)
## 生成新的数字
print("Generated numbers:", generator.generate_numbers())
## 设置新的数字范围
generator.set_range(10, 50)
## 生成新的数字
print("Generated numbers:", generator.generate_numbers())这个类名为 NumberGenerator,你可以根据需要初始化时指定生成的数字个数和范围,也可以随时调整生成的数字个数。使用 generate_numbers 方法可以生成指定数量的随机整数列表,使用 set_num_count 和 set_range 方法可以在运行时修改生成的数字个数和范围。
方法2(推荐)
普通类实现,这种实现适合用每一个实例来保存各自的数值范围,互不干扰。
import random
class RandomGen:
def __init__(self, start=1, end=100, count=10):
self.start = start
self.end = end
self.count = count
def generate(self):
return [random.randint(self.start, self.end) for _ in range(self.count)]
rg1 = RandomGen()
print(rg1.generate())
rg2 = RandomGen(1, 10000, 3)
print(rg2.generate())方法3(推荐)
作为工具类来实现,提供类方法。不需要记录用过的值,只需要调用一次给结果就好。
import random
class RandomGen:
@classmethod
def generate(cls, start=1, end=10, count=10):
return [random.randint(start, end) for _ in range(count)]
print(RandomGen.generate())
print(RandomGen.generate(1, 10000, 3))用类的实例调用(则无需在类方法前使用classmethod装饰器):
import random
class RandomGen:
def generate(cls, start=1, end=10, count=10):
return [random.randint(start, end) for _ in range(count)]
print(RandomGen().generate())
print(RandomGen().generate(1, 10000, 3))方法4
使用生成器表达式
不立刻返回结果,而是返回生成器对象。
import random
class RandomGen:
def __init__(self, start=1, end=100, count=10):
self.start = start
self.end = end
self.count = count
def generate(self):
# 生成器表达式,返回一个生成器对象,该生成器对象可以逐个生成指定数量的随机整数。
return (random.randint(self.start, self.end) for _ in range(self.count))
r = RandomGen()
print(r.generate()) # <generator object RandomGen.generate.<locals>.<genexpr> at 0x000002A15DBBFA00>,生成器对象的内存地址
print(*r.generate()) # 46 46 37 93 81 90 92 72 70 13,通过解构运算符* 迭代打印生成器中的每个值
print(list(r.generate())) # [13, 37, 15, 66, 77, 33, 56, 5, 97, 96],将生成器转换为列表并打印方法5
使用 yield 将普通函数转换为生成器函数
import random
class RandomGen:
def __init__(self, start=1, end=100, count=10):
self.start = start
self.end = end
self.count = count
def _generate(self): # 生成器函数
while True: # 一次生成一个数据
yield random.randint(self.start, self.end)
def generate(self):
return [next(self._generate()) for _ in range(self.count)]
r = RandomGen()
print(r.generate()) # [51, 97, 90, 68, 41, 64, 78, 37, 73, 72]改进版
import random
class RandomGen:
def __init__(self, start=1, end=100, count=10):
self.start = start
self.end = end
self.count = count
self._gen = self._generate()
def _generate(self): # 生成器函数
while True: # 一次生成一个数据
yield random.randint(self.start, self.end)
def generate(self):
return [next(self._gen) for _ in range(self.count)]
r = RandomGen()
print(r.generate()) # [92, 71, 8, 23, 37, 3, 98, 88, 19, 17]PS
这两个版本的主要区别在于如何生成随机数序列。
- 在第一个版本中,每次调用
generate()方法时都会创建一个新的生成器对象; - 而在第二个版本中,生成器对象
_gen在初始化时就被创建,并在后续调用generate()方法时重复使用。
推荐使用第二种方式,因为它更加高效。在第二个版本中,生成器对象 _gen 只创建了一次,然后被重复利用,避免了每次调用 generate() 方法时都重新创建生成器对象的开销。这样可以节省内存和计算资源,并且提高代码的性能。
方法6
较为复杂的实现方式
import random
class RandomGen:
def __init__(self, start=1, stop=100, count=10):
self.start = start
self.stop = stop
self._count = count
self._gen = self._generate()
def _generate(self):
while True:
yield [random.randint(self.start, self.stop) for _ in range(self._count)]
def generate(self):
return next(self._gen)
@property
def count(self):
return self._count
@count.setter
def count(self, value):
self._count = value
r = RandomGen()
print(r.generate())
print(r.generate())
print(r.count)
r.count = 30
print(r.generate())**while True:**的意义
在这段代码中,while True: 的意义在于创建了一个无限循环,这是为了确保生成器 (_generate 方法) 能够持续地产生随机数列表。生成器的主要目的是生成随机数列表,而无限循环保证了生成器可以在需要时一直生成列表,而不会停止。
这里的 while True: 是必要的,如果没有 while True:,生成器将只生成一个随机数列表,然后在 generate 方法被调用后停止。而通过使用 while True:,生成器可以持续生成随机数列表,直到调用方明确要求停止,而不会在生成一个列表后就停止。
import random
class RandomGen:
def __init__(self, start=1, stop=100, count=10):
self.start = start
self.stop = stop
self._count = count
self._gen = self._generate()
def _generate(self):
#while True:
yield [random.randint(self.start, self.stop) for _ in range(self._count)]
def generate(self):
return next(self._gen)
r = RandomGen()
print(r.generate())
print(r.generate()) # StopIteration,不加 while True 将停止迭代。打印二维坐标
使用上题中的类,随机生成20个数字,两两配对形成二维坐标系的坐标,把这些坐标组织起来,并打印输出。
方法1
import random
class RandomGen:
def __init__(self, start=1, stop=100, count=10):
self.start = start
self.stop = stop
self._count = count
self._gen = self._generate()
def _generate(self):
while True:
yield [random.randint(self.start, self.stop) for _ in range(self._count)]
def generate(self):
return next(self._gen)
@property
def count(self):
return self._count
@count.setter
def count(self, value):
self._count = value
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
r = RandomGen()
points = [Point(x, y) for x, y in zip(r.generate(), r.generate())]
for p in points:
print("{:2} {:2}".format(p.x, p.y))points = [Point(x, y) for x, y in zip(r.generate(), r.generate())] 含义:
这段代码创建了一个名为 points 的列表,其中包含了由 RandomGen 类生成的随机坐标点。让我逐步解释:
-
RandomGen类定义了一个名为generate的方法,用于生成指定范围内的随机整数列表。这个方法有三个参数:start(起始值,默认为1),end(结束值,默认为10),以及count(生成的随机数的数量,默认为10)。它返回一个包含随机整数的列表。 -
Point类定义了一个点的对象,它有两个属性x和y分别代表横纵坐标。 -
在实例化
RandomGen类之后,使用其generate方法两次来生成两个长度相同的随机整数列表,分别用来表示 x 和 y 坐标。 -
zip(r.generate(), r.generate())这一步将两个随机数列表按顺序一一配对,形成一个包含元组的迭代器。每个元组中的第一个元素来自第一个随机数列表,第二个元素来自第二个随机数列表。 -
列表推导式
[Point(x, y) for x, y in zip(r.generate(), r.generate())]遍历了这个元组迭代器,对于每个元组中的 x 和 y 坐标,创建一个Point对象,并将其添加到points列表中。
所以,points 列表中的每个元素都是一个 Point 对象,表示一个随机生成的坐标点,其 x 和 y 坐标是随机生成的。
最后使用 for 循环遍历了 points 列表中的每个元素,即 Point 对象。对于每个 Point 对象,它打印出其 x 和 y 属性的值,即打印出该点的横纵坐标。
所以,这段代码的执行结果会逐行打印出每个点的横纵坐标。
方法2
使用 repr 魔术方法
import random
class RandomGen:
def generate(cls, start=1, end=10, count=10):
return [random.randint(start, end) for _ in range(count)]
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"({self.x}, {self.y})"
r = RandomGen()
points = [Point(x, y) for x, y in zip(r.generate(), r.generate())]
print(points)方法3
使用 namedtuple
想要简单可以使用这种方式
import random
from collections import namedtuple
class RandomGen:
def generate(cls, start=1, end=10, count=10):
return [random.randint(start, end) for _ in range(count)]
r = RandomGen()
Point = namedtuple('Point', ['x', 'y'])
points = [Point(x, y) for x, y in zip(r.generate(), r.generate())]
print(points)方法4
使用 lambda 表达式
import random
from collections import namedtuple
class RandomGen:
def generate(cls, start=1, end=10, count=10):
return [random.randint(start, end) for _ in range(count)]
r = RandomGen()
Point = namedtuple('Point', ['x', 'y'])
points = map(lambda x, y: Point(x, y), r.generate(), r.generate())
print(*points)车辆信息
记录车的品牌brand、颜色color、价格price、速度speed等特征,并实现车辆管理,能增加车辆、显示车辆的全部信息
方法1
class Car:
def __init__(self, brand, color, price, speed):
self.brand = brand
self.color = color
self.price = price
self.speed = speed
class CarManager:
def __init__(self):
self.cars = []
def add_car(self, car):
self.cars.append(car)
def display_all_cars(self):
for idx, car in enumerate(self.cars, start=1):
print(f"Car {idx}:")
print(f"Brand: {car.brand}")
print(f"Color: {car.color}")
print(f"Price: {car.price}")
print(f"Speed: {car.speed}")
print()
## 示例用法
car_manager = CarManager()
## 添加车辆
car1 = Car("Toyota", "Red", 25000, 180)
car_manager.add_car(car1)
car2 = Car("Honda", "Blue", 30000, 200)
car_manager.add_car(car2)
## 显示所有车辆信息
car_manager.display_all_cars(){car.brand}是怎么拿到的?
在这段代码中,car是Car类的一个实例对象,而不是列表。当你调用add_car方法将Car对象添加到CarManager的cars列表中时,实际上你是将Car对象的引用添加到了列表中,而不是直接将对象本身放入列表。
所以,当你在display_all_cars方法中遍历self.cars列表时,每次迭代得到的car都是Car类的一个实例对象。因此,{car.brand}就是访问该实例对象的brand属性,以显示该汽车的品牌信息。
方法2
class Car:
def __init__(self, brand, color, price, speed):
self.brand = brand
self.color = color
self.price = price
self.speed = speed
def __repr__(self): # 不加这个返回的将是默认的、难以理解的实例对象信息
# return str(sorted(self.__dict__.items()))
# return "<Car brand={}, color={}, price={}, speed={}>".format(
# self.brand, self.color, self.price, self.speed
# )
return str(self.__dict__)
class CarInfoMgr:
def __init__(self):
self.__car_list = []
def add_car(self, car):
self.__car_list.append(car) # 添加的是Car类的一个实例对象
def get_all(self):
return self.__car_list
mgr = CarInfoMgr() # 实例化后将会生成一个列表(self.__car_list = []),可以容纳其它车辆
car1 = Car("Audi", "red", 20, 200)
car2 = Car("BMW", "blue", 30, 300)
mgr.add_car(car1)
mgr.add_car(car2)
print(*mgr.get_all(), sep='\n')温度单位转换
摄氏度、华氏度、开氏度之间互相转换。
方法1
通过工具类实现(工具类不需要实例化)
class TemperatureConvert:
@classmethod
def c2f(cls, c):
return c * 9 / 5 + 32
@classmethod
def f2c(cls, f):
return (f - 32) * 5 / 9
@classmethod
def c2k(cls, c):
return c + 273.15
@classmethod
def k2c(cls, k):
return k - 273.15
@classmethod
def f2k(cls, f):
return cls.c2k(cls.f2c(f))
@classmethod
def k2f(cls, k):
return cls.c2f(cls.k2c(k))
print(TemperatureConvert.c2f(30)) # 86.0
print(TemperatureConvert.f2c(86)) # 30.0
print(TemperatureConvert.c2k(30)) # 303.15
print(TemperatureConvert.k2c(303.15)) # 30.0
print(TemperatureConvert.f2k(86)) # 303.15
print(TemperatureConvert.k2f(303.15)) # 86.0新需求
一个温度和单位,先存着,以后不一定什么时候需要将该温度转换成其它单位的温度。
方案1
下面的实现方式,既可以当工具类,又可以当实例类~
class TemperatureConvert:
def __init__(self, t, unit='c'):
if unit == 'c':
self._c = t
self._f = self.c2f(t)
self._k = self.c2k(t)
elif unit == 'f':
self._f = t
self._c = self.f2c(t)
self._k = self.f2k(t)
elif unit == 'k':
self._k = t
self._c = self.k2c(t)
self._f = self.k2f(t)
@property
def c(self):
return self._c
@property
def f(self):
return self._f
@property
def k(self):
return self._k
@classmethod
def c2f(cls, c):
return c * 9 / 5 + 32
@classmethod
def f2c(cls, f):
return (f - 32) * 5 / 9
@classmethod
def c2k(cls, c):
return c + 273.15
@classmethod
def k2c(cls, k):
return k - 273.15
@classmethod
def f2k(cls, f):
return cls.c2k(cls.f2c(f)) # 核心,最常用的温度体系是摄氏度
@classmethod
def k2f(cls, k):
return cls.c2f(cls.k2c(k))
t = TemperatureConvert(30, 'c')
print(t.c)
print(t.f)
print(t.k)
print('-' * 30)
t = TemperatureConvert(86, 'f')
print(t.c)
print(t.f)
print(t.k)
print('-' * 30)
t = TemperatureConvert(303.15, 'k')
print(t.c)
print(t.f)
print(t.k)方案2
class TemperatureConvert:
def __init__(self, t, unit='c'):
self._c = None
self._t = None
self._k = None
if unit == 'c':
self._c = t
elif unit == 'f':
self._f = t
self._c = self.f2c(t)
elif unit == 'k':
self._k = t
self._c = self.k2c(t)
@property
def c(self):
return self._c
@property
def f(self):
if self._f is None:
self._f = self.c2f(self._c)
return self._f
@property
def k(self):
if self._k is None:
self._k = self.c2k(self._c)
return self._k
@classmethod
def c2f(cls, c):
return c * 9 / 5 + 32
@classmethod
def f2c(cls, f):
return (f - 32) * 5 / 9
@classmethod
def c2k(cls, c):
return c + 273.15
@classmethod
def k2c(cls, k):
return k - 273.15
@classmethod
def f2k(cls, f):
return cls.c2k(cls.f2c(f))
@classmethod
def k2f(cls, k):
return cls.c2f(cls.k2c(k))两个方案对比
两种方案都能实现温度单位之间的转换,但它们的实现方式略有不同。
方案1:
- 使用了属性(property)来延迟计算,只有在需要时才计算对应的温度值。
- 使用了单个属性来表示每种温度单位的值,当一个单位的值被设置时,其他单位的值会被自动计算。
- 在初始化时,只需要提供一个温度值和其对应的单位即可,其他单位的值会在需要时自动计算。
方案2:
- 在初始化时,根据提供的单位,直接计算并设置所有单位的值。
- 不使用属性延迟计算,直接计算并存储所有单位的值。
哪种方案更好取决于具体的使用场景和偏好:
- 如果需要频繁地访问不同单位的温度值,且性能要求不高,可以选择方案1,因为它会在需要时计算,并且能够节省内存空间。
- 如果性能要求较高,或者温度转换是在初始化后不再改变的情况下,可以选择方案2,因为它会在初始化时一次性计算并存储所有单位的值,避免了在访问时的计算开销。
总的来说,方案1更灵活和节省内存,适用于需要频繁访问不同单位温度值的场景;而方案2更简洁直接,适用于性能要求较高或者温度转换不频繁的场景。
模拟购物车购物
商品有很多种类,商品的属性多种多样,怎么解决?
购物车可以加入很多不同的商品,如何实现?
方法1
class Color:
RED = 0
BLUE = 1
BLACK = 2
class Item: # 不应该设计所有的商品类,应该像这样统一设计。
def __init__(self, name, price, **kwargs):
self.name = name
self.price = price
self.__spec = kwargs
def __repr__(self):
return f'{self.name} - {self.price} - {self.__spec}'
class Cart:
def __init__(self):
self.items = []
def add(self, item: Item):
self.items.append(item)
def getall(self):
return self.items
my_cart = Cart()
my_item = Item('p30', 3000, color=Color.RED, memory='8g')
my_cart.add(my_item)
print(my_cart.getall())方法2
要解决商品种类繁多、属性多样的问题,可以采用面向对象的方法,定义商品类(Product class),每个商品对象有各自的属性(如名称、价格、库存等),然后将不同种类的商品实例化为不同的对象。
至于购物车的实现,可以创建一个购物车类(ShoppingCart class),该类可以包含一些方法来添加商品、移除商品、计算总价等。
以下是一个简单的 Python 实现:
class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self.price = price
self.quantity = quantity
class ShoppingCart:
def __init__(self):
self.items = []
def add_item(self, product):
self.items.append(product)
def remove_item(self, product):
self.items.remove(product)
def calculate_total(self):
total = 0
for item in self.items:
total += item.price * item.quantity
return total
## 测试代码
## 创建一些商品
product1 = Product("手机", 2000)
product2 = Product("电视", 3000)
product3 = Product("电脑", 4000)
## 创建购物车
cart = ShoppingCart()
## 添加商品到购物车
cart.add_item(product1)
cart.add_item(product2)
cart.add_item(product3)
## 计算购物车总价
total_price = cart.calculate_total()
print("总价:", total_price)这个例子中,我们首先定义了一个 Product 类来表示商品,每个商品有名称、价格等属性。然后定义了 ShoppingCart 类来表示购物车,它包含一个列表用来存储购物车中的商品对象。购物车类中有添加商品、移除商品和计算总价等方法。
你可以根据自己的需求对这个实现进行扩展和修改,比如加入库存管理、优惠券功能等。
如果商品还有其它属性怎么办?
可以在 Product 类的 __init__() 方法中使用 **kwargs 参数来接收任意数量的关键字参数,并将它们存储在一个字典中。以下是一个示例:
class Product:
def __init__(self, name, price, quantity=1, **kwargs):
self.name = name
self.price = price
self.quantity = quantity
self.attributes = kwargs # 存储附加属性的字典
## 测试代码
product1 = Product("T恤", 20, color="红色", size="M")
product2 = Product("牛仔裤", 50, color="蓝色", size="L")
product3 = Product("运动鞋", 100, color="黑色", size="42")
## 打印商品的属性
print(product1.name, product1.price, product1.attributes)
print(product2.name, product2.price, product2.attributes)
print(product3.name, product3.price, product3.attributes)在这个示例中,Product 类的 __init__() 方法使用 **kwargs 参数来接收任意数量的关键字参数,并将它们存储在 attributes 字典中。这样,你就可以给每个商品传递不同数量和类型的附加属性,而不需要事先定义它们。
计算图形面积
要求:Shape基类,要求所有子类都必须提供面积的计算,子类有三角形、矩形、圆。
方法1
-
使用
@property装饰器后,调用类方法时,就像掉类属性一样,更加方便; -
此方式仅适用于中途不修改属性值
import math
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
raise NotImplementedError('基类未实现')
class Triangle(Shape):
def __init__(self, a, b, c):
super().__init__() # 继承父类的 self._area
self.a = a
self.b = b
self.c = c
@property
def area(self):
# 不立刻生成面积的计算结果,以减少开销
if self._area is None:
p = (self.a + self.b + self.c) / 2
self._area = math.sqrt(p * (p - self.a) * (p - self.b) * (p - self.c))
print('*' * 30) # 测试是否二次计算
return self._area
class Rectangle(Shape):
def __init__(self, width, height):
super().__init__()
self.width = width
self.height = height
@property
def area(self):
if self._area is None:
self._area = self.width * self.height
return self._area
class Circle(Shape):
def __init__(self, radius):
super().__init__()
self.r = radius
@property
def area(self):
if self._area is None:
self._area = 3.14 * self.r * self.r
return self._area
shapes = [Triangle(3,4, 5),Rectangle(4,5),Circle(4)]
for shape in shapes:
print(shape.area)
print(shape.area)
t = Triangle(3, 4, 5)
print('-' * 100)
print(t.area)
print(t.area)方法2
- 此方式适用于中途修改属性值(修改属性值后,将
__area设置为None,以重新计算) - 下面仅使用 Triangle 类演示:
import math
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
raise NotImplementedError('基类未实现')
class Triangle(Shape):
def __init__(self, a, b, c):
super().__init__() # 继承父类的 self._area
self.a = a
self.b = b
self.c = c
# 私有属性只读
@property
def a(self):
return self.__a
@a.setter
def a(self, value):
self.__a = value
self.__area = None
@property
def b(self):
return self.__b
@b.setter
def b(self, value):
self.__b = value
self.__area = None
@property
def c(self):
return self.__c
@c.setter
def c(self, value):
self.__c = value
self.__area = None
@property
def area(self):
# 不立刻生成面积的计算结果,以减少开销
if self._area is None:
p = (self.a + self.b + self.c) / 2
self._area = math.sqrt(p * (p - self.a) * (p - self.b) * (p - self.c))
print('*' * 30) # 测试是否二次计算
return self._area
class Rectangle(Shape):
def __init__(self, width, height):
super().__init__()
self.width = width
self.height = height
@property
def area(self):
if self._area is None:
self._area = self.width * self.height
return self._area
class Circle(Shape):
def __init__(self, radius):
super().__init__()
self.r = radius
@property
def area(self):
if self._area is None:
self._area = 3.14 * self.r * self.r
return self._area
shapes = [Triangle(3,4, 5),Rectangle(4,5),Circle(4)]
for shape in shapes:
print(shape.area)
print(shape.area)
print('-' * 100)
t = Triangle(3, 4, 5)
print(t.area)
print(t.area)
print('=' * 30)
t.a = 2
print(t.area)
print(t.area)实现圆类的数据可序列化
import math
import json
import msgpack
class Shape:
def __init__(self):
self._area = None
@property
def area(self):
raise NotImplementedError('基类未实现')
class Circle(Shape):
def __init__(self, radius):
super().__init__()
self.r = radius
@property
def area(self):
if self._area is None:
self._area = 3.14 * self.r * self.r
return self._area
class SerializableMixin:
def dumps(self, typ='json'):
if typ == 'json':
return json.dumps(self.__dict__)
elif typ == 'msgpack':
return msgpack.dumps(self.__dict__)
else:
raise TypeError
class SerializableCircleMixin(SerializableMixin, Circle): pass
sc = SerializableCircleMixin(3)
print(sc.dumps())
print(sc.dumps('msgpack'))
print()
print(sc.area)
print(sc.dumps())这段代码展示了 Python 中 Mixin 的用法,Mixin 是一种将类的功能“混入”到其他类中的方式,以增加功能或重用代码而不引入继承链的复杂性。下面是对代码的详细解释:
-
Shape类是一个基类,定义了一个抽象的属性area,但没有实现具体的计算方法。这意味着任何继承自Shape的子类都需要实现自己的area方法。 -
Circle类继承自Shape类。它具体实现了area方法,用于计算圆的面积。此外,它使用了一个property装饰器,将area方法转换为属性,使得可以通过sc.area的形式访问面积,而不需要加上括号。 -
SerializableMixin类是一个 Mixin 类,用于提供序列化的功能。它定义了一个dumps方法,根据指定的类型(‘json’ 或 ‘msgpack’),将对象转换为对应格式的字符串。 -
SerializableCircleMixin类继承自SerializableMixin和Circle。这意味着它继承了SerializableMixin提供的序列化功能,同时也继承了Circle类的计算面积的功能。 -
当创建
SerializableCircleMixin的实例sc时,需要传入一个半径。然后可以使用sc.dumps()方法将对象序列化为 JSON 格式的字符串,或者使用sc.dumps('msgpack')方法将对象序列化为 MessagePack 格式的字符串。 -
在
Circle类中,计算出的面积会被缓存到_area属性中,避免重复计算。因此,当调用sc.area时,如果_area已经有值,就直接返回缓存的结果。 -
在最后一行代码中,再次调用了
sc.dumps()方法,由于对象的属性并没有发生改变,所以序列化的结果与之前是一样的。
总的来说,Mixin 提供了一种方便的方式,可以将不同类中的功能组合在一起,而不需要使用传统的多重继承,从而避免了继承链过长和复杂性增加的问题。
实现单双向链表
要求
用面向对象的方式实现链表 LinkedList
- 单向链表实现
append、iternodes方法 - 双向链表实现
append、pop、insert、remove、iternodes方法
PS:
单向链表:
- 单向链表是一种基本的数据结构,它由一系列节点组成,每个节点包含两部分:数据和指向下一个节点的指针。每个节点只能访问其后继节点,而不能直接访问前驱节点或者其他节点。链表的第一个节点称为头节点,最后一个节点的指针指向一个特殊的值(通常是空指针或者NIL),表示链表的结束。
- 单向链表的优点之一是在插入和删除操作时具有较高的效率,因为只需调整节点的指针,而不需要像数组那样移动大量元素。然而,缺点是访问元素时需要从头节点开始逐个遍历,因此访问效率较低,尤其是在需要随机访问元素时。
双向链表:
-
双向链表是一种链表数据结构,它与单向链表相似,但每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。这使得在双向链表中,每个节点都可以从前向后或从后向前遍历。
-
与单向链表相比,双向链表在某些操作上具有更高的灵活性和效率。例如,在双向链表中,可以更容易地从后向前遍历,而不需要重新遍历整个链表。另外,插入和删除操作可能更高效,因为不需要在访问之前找到前一个节点,可以直接通过前向指针访问。但是,双向链表占用的空间更多,因为每个节点需要存储额外的指针。