You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
6.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from datetime import date
import re # 新增正则表达式模块用于身份证验证
from astropy.version import major
from pyasn1_modules.rfc2985 import gender
class Student:
"""学生实体类"""
def __init__(self, stu_id: str, name: str, height: int, gender:bool or str ,major:str,birth_date: date | str,
enrollment_date: date | str, class_name: str, id_card: str | None = None ):
self.stu_id = stu_id #sid ->stu_id
self.name = name.strip()
self.height = height
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_card = id_card
self.gender=gender
self.major=major
self._validation_errors = []
self._validate_height()
self._validate_dates()
self._validate_name()
self._validate_id_card()
def _validate_id_card(self) -> None:
"""验证身份证格式,包括校验码检验"""
if not self.id_card:
return
if len(self.id_card)!=18:
self._validation_errors.append("身份证号长度应为18位")
if not self.id_card[:17].isdigit():
self._validation_errors.append("身份证号前17位必须为数字")
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
total = sum(int(self.id_card[i]) * weights[i] for i in range(17))
expected_check = check_codes[total % 11]
if self.id_card[-1].upper()!=expected_check:
self._validation_errors.append("校验码不匹配,身份证格式不正确")
# 从身份证提取出生日期并验证
try:
if len(self.id_card) == 18:
birth_year = int(self.id_card[6:10])
birth_month = int(self.id_card[10:12])
birth_day = int(self.id_card[12:14])
extracted_birth_date = date(birth_year, birth_month, birth_day)
if extracted_birth_date != self.birth_date:
self._validation_errors.append("身份证出生日期与登记出生日期不一致")
except (ValueError, IndexError):
self._validation_errors.append("身份证日期解析失败")
gender_code=int(self.id_card[16])
gender=""if gender_code % 2==1 else ""
self.gender=gender
def _validate_height(self) -> None:
if not (50 <= self.height <= 250):
self._validation_errors.append(f"身高{self.height}cm超出合理范围50-250厘米")
def _validate_name(self) -> None:
if not (2 <= len(self.name) <= 20):
self._validation_errors.append("姓名长度需要在2到20个字符以内")
if not self.name.isprintable():
self._validation_errors.append("姓名包含不可打印的字符")
def _validate_dates(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.birth_date > self.enrollment_date:
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.stu_id == other.stu_id and self.name == other.name and self.height == other.height and
self.birth_date == other.birth_date and self.enrollment_date == other.enrollment_date and
self.class_name == other.class_name and self.id_card == other.id_card)
def to_dict(self) -> dict:
"""将对象序列化为字典"""
return {
'stu_id': self.stu_id,
'name': self.name,
'height': self.height,
'birth_date': self.birth_date.isoformat(),
'enrollment_date': self.enrollment_date.isoformat(),
'class_name': self.class_name,
'id_card': self.id_card, # 新增身份证字段
'gender':self.gender, # 新增性别
'major':self.major # 新增专业
}
@classmethod
def from_dict(cls, data: dict) -> 'Student':
"""从字典创建对象(自动处理日期解析)"""
birth_date = data['birth_date']
enrollment_date = data['enrollment_date']
birth_date = birth_date if isinstance(birth_date, date) else date.fromisoformat(birth_date)
enrollment_date = enrollment_date if isinstance(enrollment_date, date) else date.fromisoformat(enrollment_date)
# 从字典获取身份证(允许为空)
id_card = data.get('id_card')
return cls(
stu_id=data['stu_id'],
name=data['name'].strip(),
height=data['height'],
birth_date=birth_date,
enrollment_date=enrollment_date,
class_name=data['class_name'],
id_card=id_card, # 传递身份证参数
gender=data['gender'],
major= data ['major']
)
def __repr__(self) -> str:
"""完整对象表示(包含所有字段信息)"""
return (
f"{self.__class__.__name__}("
f"stu_id='{self.stu_id}', "
f"name='{self.name}', "
f"height={self.height}, "
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_card='{self.id_card}',"
f"gender='{self.gender}',"
f"major='{self.major}'"
f")"
)