描述
    中国目前采用的是18位身份证号,其第7-10位数字是出生年,11-12位是出生月份,13-14是出生日期,第17位是性别,奇数为男性,偶数为女性,第18位是校验位。
    如果身份证号码的其中一位填错了(包括最后一个校验位),则校验算法可以检测出来。如果身份证号的相邻2位填反了,则校验算法可以检测出来。校验规则如下:
    1. 将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2。
    2. 将这17位数字和系数相乘的结果相加。
    3. 用加出来和除以11,看余数只可能是:0-1-2-3-4-5-6-7-8-9-10
    分别对应的最后一位身份证的号码为:1-0-X-9-8-7-6-5-4-3-2
    4. 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的X(大写英文字母X)。如果余数是10,身份证的最后一位号码就是2。
    用户输入一个身份证号,校验其是否是合法的身份证号码:
    1. 输入长度是否合法

    1. if len(id_number) == 18
    1. 输入数据校验位是否合法
      1. if id_check(id_number):
    2. 输入数据中年月日范围是否合法,考虑闰年。
      1. if check_date(id_number):
      ```python def leap(year): “””判断闰年函数”””

    def check_date(id_num): “””判断年月日是否合法”””

    def sum_of_id(id_num): “””接收身份证号为参数,计算各位上数字与权值乘积的和,返回正整数”””

    def id_check(id_num): “””接收身份证号为参数,计算并检查校验和,返回布尔值”””

    def id_info(id_num): “””接收身份证号为参数,返回年、月、日和性别,均为字符串类型”””

    def id_to_new(id_fifteen):

    1. 如身份证号码不合法输出 '身份证校验错误!',<br />如身份证号码合法则分别在4行中输出'身份证号码校验为合法号码!'以及该人的出生年月日、年龄和性别。<br />输入格式<br />一个18位身份证号,末位为数字或大写字母X<br />输出格式<br />如身份证号码不合法输出 '身份证校验错误!',<br />如身份证号码合法则分别在4行中输出'身份证号码校验为合法号码!'以及该人的出生年月日、年龄(当前年减出生年)和性别。
    2. 解析:涉及身份证号,因需要多次使用索引或切片,务必先判断输入字符串长度是否为18位再进行其他操作,以免导致超出索引范围的问题。<br />为使程序逻辑清晰,可将判定闰年、判定出生日期、身份证号校验和获取身份信息分别定义为一个函数,输入输出放在主函数里。此处只利用datetime获取当年前份,有兴趣的同学可以到此模块中获取用于判断日期是否合法的方法。<br />判定闰年
    3. ```python
    4. def leap(year):
    5. """判断闰年函数"""
    6. if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
    7. return True
    8. else:
    9. return False

    判定出生日期合法性

    def check_date(id_num):
        """判断年月日是否合法"""
        # 年份超过当前年,或月份小于1或大于12,或日期小于1或大于31时非法
        if int(id_num[6:10]) > datetime.datetime.now().year or int(id_num[10:12]) < 1 or int(id_num[10:12]) > 12 or int(
                id_num[12:14]) < 1 or int(id_num[12:14]) > 31:
            return False
        # 当月份为4,6,9,11时,日期超过30即非法
        if int(id_num[10:12]) in [4, 6, 9, 11] and int(id_num[12:14]) > 30:
            return False
        # 月份为2时,日期大于29便非法
        if int(id_num[10:12]) == 2 and int(id_num[12:14]) > 29:
            return False
        # 月份为2时,如果不是闰年,日期大于28便非法
        if int(id_num[10:12]) == 2 and not leap(int(id_num[6:10])) and int(id_num[12:14]) > 28:
            return False
        return True   # 其他情况返回True
    

    校验和

    def sum_of_id(id_num):
        """接收身份证号为参数,计算各位上数字与权值乘积的和对11取模的结果,返回正整数"""
        check_sum = sum([weight[i] * int(id_num[i]) for i in range(17)])
        return check_sum % 11
    

    身份证号校验

    def id_check(id_num):
        """接收身份证号为参数,计算并检查校验和,返回布尔值"""
        check_sum = sum_of_id(id_num)
        if id_num[17] == 'X' and check_sum == 2:  # 若末位为'X'
            return True
        elif id_num[17] != 'X' and (check_sum + int(id_num[17])) % 11 == 1:
            return True
        else:
            return False
    

    获取身份信息

    def id_info(id_num):
        """接收身份证号为参数,输出年、月、日和性别"""
        year = id_num[6:10]
        month = id_num[10:12]
        date = id_num[12:14]
        gender = '男' if id_num[16] in '13579' else '女'
        print('出生:{}年{}月{}日'.format(year, month, date))
        print('性别:{}'.format(gender))
        print('年龄:{}岁'.format(datetime.datetime.now().year - int(year)))
    

    升18位

    def id_to_new(id_fifteen):
        """接收15位身份证号,若年份小于30,年份前插入20,否则年份前插入19。
        最后一位为检验位。
        """
        if int(id_fifteen[6:8]) >= 30:  # 第六位数后面插入19 (1930 年1 月1 日以后出生)
            id_seventeen = id_fifteen[0:6] + '19' + id_fifteen[6:]
        else:  # 第六位数后面插入20(2000.1.1以后出生)
            id_seventeen = id_fifteen[0:6] + '20' + id_fifteen[6:]
        check_sum = sum_of_id(id_seventeen)
        id_eighteen = id_seventeen + ecc[check_sum]  # 根据余数查ecc列表对应序号取得最后一位的字符,拼接到一起
        return id_eighteen
    

    完全程序如下:

    # --------      -------    --------
    # @File   : 身份证.py 
    # @Author : 赵广辉   
    # @Contact: vasp@qq.com
    # @Company: 武汉理工大学
    # @Version: 1.0
    # @Modify : 2021/11/21 18:02
    # Python程序设计基础,高等教育出版社
    # --------      -------    --------
    import datetime
    
    
    def leap(year):
        """判断闰年函数"""
        if (year % 400 == 0) or (year % 4 == 0 and year % 100 != 0):
            return True
        else:
            return False
    
    
    def check_date(id_num):
        """判断年月日是否合法"""
        if int(id_num[6:10]) > datetime.datetime.now().year or int(id_num[10:12]) < 1 or int(id_num[10:12]) > 12 or int(
                id_num[12:14]) < 1 or int(id_num[12:14]) > 31:
            return False
        if int(id_num[10:12]) in [4, 6, 9, 11] and int(id_num[12:14]) > 30:
            return False
        if int(id_num[10:12]) == 2 and int(id_num[12:14]) > 29:
            return False
        if int(id_num[10:12]) == 2 and not leap(int(id_num[6:10])) and int(id_num[12:14]) > 28:
            return False
        return True
    
    
    def sum_of_id(id_num):
        """接收身份证号为参数,计算各位上数字与权值乘积的和对11取模的结果,返回正整数"""
        check_sum = sum([weight[i] * int(id_num[i]) for i in range(17)])
        return check_sum % 11
    
    
    def id_check(id_num):
        """接收身份证号为参数,计算并检查校验和,返回布尔值"""
        check_sum = sum_of_id(id_num)
        if id_num[17] == 'X' and check_sum == 2:  # 若末位为'X'
            return True
        elif id_num[17] != 'X' and (check_sum + int(id_num[17])) % 11 == 1:
            return True
        else:
            return False
    
    
    def id_info(id_num):
        """接收身份证号为参数,返回年、月、日和性别,均为字符串类型"""
        year = id_num[6:10]
        month = id_num[10:12]
        date = id_num[12:14]
        gender = '男' if id_num[16] in '13579' else '女'
        print('出生:{}年{}月{}日'.format(year, month, date))
        print('性别:{}'.format(gender))
        print('年龄:{}岁'.format(datetime.datetime.now().year - int(year)))
    
    
    def id_to_new(id_fifteen):
        """接收15位身份证号,若年份小于30,年份前插入20,否则年份前插入19。
        最后一位为检验位。
        """
        if int(id_fifteen[6:8]) >= 30:  # 第六位数后面插入19 (1930 年1 月1 日以后出生)
            id_seventeen = id_fifteen[0:6] + '19' + id_fifteen[6:]
        else:  # 第六位数后面插入20(2000.1.1以后出生)
            id_seventeen = id_fifteen[0:6] + '20' + id_fifteen[6:]
        check_sum = sum_of_id(id_seventeen)
        id_eighteen = id_seventeen + ecc[check_sum]  # 根据余数查ecc列表对应序号取得最后一位的字符,拼接到一起
        return id_eighteen
    
    
    if __name__ == '__main__':
        id_number = input()
        weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1]
        ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']  # 校验码
        if len(id_number) == 15:
            id_number = id_to_new(id_number)
            print(id_number)
            id_info(id_number)
        elif len(id_number) == 18 and id_check(id_number) and check_date(id_number):
            print('身份证号码校验为合法号码!')
            id_info(id_number)
        else:
            print('身份证校验位错误!')