from datetime import date import re class Student: def __init__(self, sid: str, name: str, gender: str, height: int, weight: float, birth_date: date | str, enrollment_date: date | str, class_name: str, id_number: str, phone: str, email: str, major: str): self.sid = sid self.name = name.strip() self.gender = gender self.height = height self.weight = weight self.birth_date = birth_date if isinstance(birth_date, date) else date.fromisoformat(birth_date) self.enrollment_date = enrollment_date if isinstance(enrollment_date, date) else date.fromisoformat(enrollment_date) self.class_name = class_name self.id_number = id_number self.phone = phone self.email = email self.major = major self._validation_errors = [] self._validate_height() self._validate_weight() self._validate_date() self._validate_name() self._validate_id_number() self._validate_gender() def _validate_height(self) -> None: if not (50 <= self.height <= 250): self._validation_errors.append(f"身高{self.height}cm超出合理范围") def _validate_weight(self) -> None: if not (5 <= self.weight <= 300): self._validation_errors.append(f"体重{self.weight}kg超出合理范围") def _validate_name(self) -> None: if not (2 <= len(self.name) <= 20): self._validation_errors.append("姓名长度需在2-20个字符之间") if not all('\u4e00' <= char <= '\u9fff' or char.isascii() for char in self.name): self._validation_errors.append("姓名只能包含中文、英文或数字") def _validate_id_number(self) -> None: if not re.match(r'^\d{17}[\dXx]$', self.id_number): self._validation_errors.append("身份证号格式不正确") def _validate_date(self) -> None: today = date.today() if self.birth_date > today: self._validation_errors.append('出生日期不能在未来') if self.enrollment_date > today: self._validation_errors.append('入学日期不能在未来') if (self.enrollment_date.year - self.birth_date.year) < 15: self._validation_errors.append('入学年龄应至少15岁') def _validate_gender(self) -> None: if self.gender not in ['男', '女']: self._validation_errors.append('性别只能是"男"或"女"') @property def is_valid(self) -> bool: return len(self._validation_errors) == 0 def get_errors(self) -> list[str]: return self._validation_errors.copy() def __eq__(self, other) -> bool: if not isinstance(other, Student): return NotImplemented return (self.sid == other.sid and self.name == other.name and self.gender == other.gender and self.height == other.height and self.weight == other.weight and self.birth_date == other.birth_date and self.enrollment_date == other.enrollment_date and self.class_name == other.class_name and self.id_number == other.id_number and self.phone == other.phone and self.email == other.email and self.major == other.major) @classmethod def from_dict(cls, data: dict) -> 'Student': birth_date = data['birth_date'] if isinstance(data['birth_date'], date) else date.fromisoformat(data['birth_date']) enrollment_date = data['enrollment_date'] if isinstance(data['enrollment_date'], date) else date.fromisoformat(data['enrollment_date']) return cls( sid=data['sid'], name=data['name'], gender=data['gender'], height=data['height'], weight=data['weight'], birth_date=birth_date, enrollment_date=enrollment_date, class_name=data['class_name'], id_number=data['id_number'], phone=data['phone'], email=data['email'], major=data['major'] ) def to_dict(self) -> dict: return { 'sid': self.sid, 'name': self.name, 'gender': self.gender, 'height': self.height, 'weight': self.weight, 'birth_date': self.birth_date.isoformat(), 'enrollment_date': self.enrollment_date.isoformat(), 'class_name': self.class_name, 'id_number': self.id_number, 'phone': self.phone, 'email': self.email, 'major': self.major } def __repr__(self) -> str: return ( f"{self.__class__.__name__}(" f"sid='{self.sid}', " f"name='{self.name}', " f"gender='{self.gender}', " f"height={self.height}, " f"weight={self.weight}, " f"birth_date=date({self.birth_date.year}, {self.birth_date.month}, {self.birth_date.day}), " f"enrollment_date=date({self.enrollment_date.year}, {self.enrollment_date.month}, {self.enrollment_date.day}), " f"class_name='{self.class_name}', " f"id_number='{self.id_number}', " f"phone='{self.phone}', " f"email='{self.email}', " f"major='{self.major}'" f")" )