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.

113 lines
4.0 KiB

from datetime import date
from typing import Optional, Dict, Any
class Student:
def __init__(
self, name: str, id_card: str, stu_id: str,
gender: Optional[bool] = None, height: Optional[int] = None,
weight: Optional[float] = None, enrollment_date: Optional[str] = None,
class_name: Optional[str] = None, major: Optional[str] = None
):
self.name = name
self.id_card = id_card
self.stu_id = stu_id
self.gender = gender
self.height = height
self.weight = weight
if enrollment_date:
if isinstance(enrollment_date, str):
self.enrollment_date = date.fromisoformat(enrollment_date)
else:
self.enrollment_date = enrollment_date
else:
self.enrollment_date = None
self.class_name = class_name
self.major = major
@property
def birthday(self) -> Optional[date]:
if not self.id_card or len(self.id_card) != 18:
return None
try:
birth_str = self.id_card[6:14]
return date(int(birth_str[:4]), int(birth_str[4:6]), int(birth_str[6:8]))
except:
return None
@property
def age(self) -> Optional[int]:
if not self.birthday:
return None
today = date.today()
age = today.year - self.birthday.year
if (today.month, today.day) < (self.birthday.month, self.birthday.day):
age -= 1
return age
@property
def errors(self) -> Dict[str, str]:
errors = {}
id_card_err = self.__validate_id_card(self.id_card)
if id_card_err:
errors["id_card"] = id_card_err
if len(self.name) < 2 or len(self.name) > 20:
errors["name"] = "姓名长度需在2-20字符之间"
if self.height and not (50 <= self.height <= 250):
errors["height"] = "身高需在50-250cm之间"
if self.weight and not (5.0 <= self.weight <= 300.0):
errors["weight"] = "体重需在5-300kg之间"
if self.enrollment_date and self.enrollment_date > date.today():
errors["enrollment_date"] = "入学日期不能晚于当前日期"
return errors
@property
def is_valid(self) -> bool:
return not bool(self.errors)
def to_dict(self) -> Dict[str, Any]:
data = self.__dict__.copy()
if data.get("enrollment_date"):
data["enrollment_date"] = data["enrollment_date"].isoformat()
return data
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Student':
if not isinstance(data, dict):
raise TypeError("输入必须为字典类型")
enrollment_date = data.get("enrollment_date")
if enrollment_date and isinstance(enrollment_date, str):
data["enrollment_date"] = date.fromisoformat(enrollment_date)
return cls(**data)
def __repr__(self) -> str:
attrs = ", ".join([
f"{k}='{v}'" if isinstance(v, str) else f"{k}={v}"
for k, v in self.__dict__.items()
])
return f"Student({attrs})"
@staticmethod
def get_properties() -> list:
return [k for k, v in vars(Student).items() if isinstance(v, property)]
@staticmethod
def __validate_id_card(id_card: str) -> Optional[str]:
if not id_card or len(id_card) != 18:
return "身份证号长度必须为18位"
if not id_card[:17].isdigit():
return "身份证号前17位必须为数字"
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check_codes = "10X98765432"
sum_val = sum(int(id_card[i]) * weights[i] for i in range(17))
if id_card[17] != check_codes[sum_val % 11]:
return "身份证号校验码错误"
try:
birth_str = id_card[6:14]
date(int(birth_str[:4]), int(birth_str[4:6]), int(birth_str[6:8]))
except:
return "身份证号中出生日期格式错误"
return None