Python如何编写函数根据传入参数动态生成指定类的实例
问题描述
我是Python新手,正尝试编写一个函数,能够返回三个候选类中某一个类的实例,且将函数的传入参数作为实例的属性。
原始代码如下:
class User: def __init__(self, nick, full_name, reg_date, age, role): self.nick = nick self.full_name = full_name self.reg_date = reg_date self.age = age self.role = role class Staff(User): def __init__(self, nick, full_name, reg_date, age, role): super().__init__(nick, full_name, reg_date, age, role) class Adult(Staff): def __init__(self, nick, full_name, reg_date, age, role): super().__init__(nick, full_name, reg_date, age, role) class Young(Adult): def __init__(self,nick, full_name, reg_date, age, role): super().__init__(full_name, nick, reg_date, age, role) def sign_up(nick, full_name, reg_date, age, role): nick = (input('Choose a nickname: ')) full_name = (input('Please, introduce your name: ')) reg_date = str(date.today()) age = (input('Please, introduce your age: ')) role = (input('Please, introduce your role (Staff, Adult or Young)')) valid_roles = ['Staff', 'Adult', 'Young'] exec('nick = role(full_name, reg_date, age, role)
预期目标:运行sign_up函数时,用户输入的nick参数值将作为实例的变量名,输入的role参数对应实例所属的类,其余参数作为实例的初始化属性。
例如调用:
sign_in('nick1', 'John Doe', reg_date, 38, 'Staff')
应当得到如下等价执行结果:
nick1 = Staff(full_name, reg_date, age)
存在的问题
- 用
exec动态创建全局变量是非常差的实践,可维护性极低,还存在任意代码执行的安全风险,这类需求应该用字典做键值映射实现。 Young类的__init__调用父类构造时,把nick和full_name的传参顺序写反了,会导致实例属性赋值错误。- 函数定义了形参,但内部直接用
input的返回值覆盖了所有形参,外部传入的参数完全不生效。 role获取到的是用户输入的字符串,不是类对象,不能直接加括号当构造函数调用。- 输入的
age是字符串类型,后续如果做年龄相关的逻辑判断会报错,需要转成整数。 - 最后一行
exec的参数字符串没有闭合,存在语法错误。 - 没有做输入合法性校验,用户输入非法角色、非法年龄时代码会直接崩溃。
修正方案
用字典维护「角色名-对应类」的映射,再用另一个字典存储「昵称-用户实例」的键值对,完全替代动态创建变量的方案,同时补全输入校验、修复参数顺序错误:
from datetime import date class User: def __init__(self, nick, full_name, reg_date, age, role): self.nick = nick self.full_name = full_name self.reg_date = reg_date self.age = age self.role = role # 子类如果没有额外的初始化逻辑,不需要重复写__init__,直接继承父类实现即可 class Staff(User): pass class Adult(Staff): pass class Young(Adult): pass # 角色字符串和类的映射表 ROLE_CLASS_MAP = { 'Staff': Staff, 'Adult': Adult, 'Young': Young } # 存储所有注册用户,键为昵称,值为对应的类实例 user_registry = {} def sign_up(): # 收集用户输入,做合法性校验 nick = input('Choose a nickname: ').strip() while nick in user_registry: nick = input('Nickname already exists, please input another: ').strip() full_name = input('Please, introduce your name: ').strip() reg_date = str(date.today()) while True: age_input = input('Please, introduce your age: ').strip() if age_input.isdigit() and 0 < int(age_input) < 120: age = int(age_input) break print("Please input a valid age (integer between 1 and 119)") while True: role = input('Please, introduce your role (Staff, Adult or Young): ').strip() if role in ROLE_CLASS_MAP: break print(f"Invalid role, please choose from {list(ROLE_CLASS_MAP.keys())}") # 创建对应类的实例 target_class = ROLE_CLASS_MAP[role] new_user = target_class(nick, full_name, reg_date, age, role) # 存入注册表,后续通过昵称即可取到实例 user_registry[nick] = new_user print(f"Register success, welcome {nick}") return new_user
使用方式
调用sign_up()完成注册流程后,直接通过user_registry['你的昵称']就能拿到对应的实例,比如注册时输入昵称为nick1、角色选Staff,user_registry['nick1']就是你需要的Staff类实例,和你预期的动态创建nick1变量效果完全一致,且更安全、更容易维护。
补充:如果子类后续要加独有的属性/方法,再重写
__init__即可,不需要写和父类完全一致的初始化逻辑重复调用super,减少冗余代码。
内容的提问来源于stack exchange,提问作者Arochal
相关产品推荐
相关产品推荐

