Bit mã này cho phép bạn tạo các lớp mới với tên động và tên tham số. Việc xác minh tham số trong __init__
chỉ không cho phép các tham số không xác định, nếu bạn cần các xác minh khác, như loại hoặc chúng là bắt buộc, chỉ cần thêm logic vào đó:
class BaseClass(object):
def __init__(self, classtype):
self._type = classtype
def ClassFactory(name, argnames, BaseClass=BaseClass):
def __init__(self, **kwargs):
for key, value in kwargs.items():
# here, the argnames variable is the one passed to the
# ClassFactory call
if key not in argnames:
raise TypeError("Argument %s not valid for %s"
% (key, self.__class__.__name__))
setattr(self, key, value)
BaseClass.__init__(self, name[:-len("Class")])
newclass = type(name, (BaseClass,),{"__init__": __init__})
return newclass
Và điều này hoạt động như thế này, ví dụ:
>>> SpecialClass = ClassFactory("SpecialClass", "a b c".split())
>>> s = SpecialClass(a=2)
>>> s.a
2
>>> s2 = SpecialClass(d=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __init__
TypeError: Argument d not valid for SpecialClass
Tôi thấy bạn đang yêu cầu chèn các tên động trong phạm vi đặt tên - bây giờ, điều đó không được coi là một phương pháp hay trong Python - bạn có tên biến, được biết đến tại thời điểm mã hóa hoặc dữ liệu - và các tên được học trong thời gian chạy thì nhiều hơn " dữ liệu "hơn" biến "-
Vì vậy, bạn chỉ có thể thêm các lớp của mình vào từ điển và sử dụng chúng từ đó:
name = "SpecialClass"
classes = {}
classes[name] = ClassFactory(name, params)
instance = classes[name](...)
Và nếu thiết kế của bạn thực sự cần các tên trong phạm vi, chỉ cần làm tương tự, nhưng sử dụng từ điển được trả về bởi globals()
cuộc gọi thay vì từ điển tùy ý:
name = "SpecialClass"
globals()[name] = ClassFactory(name, params)
instance = SpecialClass(...)
(Thực sự sẽ có thể cho hàm nhà máy lớp chèn tên động trên phạm vi toàn cục của trình gọi - nhưng điều đó thậm chí còn tệ hơn và không tương thích trên các triển khai Python. Cách để làm điều đó là lấy tên gọi khung thực thi, thông qua sys._getframe (1) và đặt tên lớp trong từ điển chung của khung trong f_globals
thuộc tính của nó ).
update, tl; dr: Câu trả lời này đã trở nên phổ biến, vẫn rất cụ thể cho phần nội dung câu hỏi. Câu trả lời chung về cách
"tạo động các lớp dẫn xuất từ một lớp cơ sở"
trong Python là một lệnh gọi đơn giản để type
chuyển tên lớp mới, một bộ giá trị với (các) baseclass và phần __dict__
thân cho lớp mới giống như sau:
>>> new_class = type("NewClassName", (BaseClass,), {"new_method": lambda self: ...})
cập nhật
Bất kỳ ai cần điều này cũng nên kiểm tra dự án thì là - nó tuyên bố có thể chọn và bỏ chọn các lớp giống như pickle đối với các vật thể thông thường và đã sống với nó trong một số thử nghiệm của tôi.
a
nó sẽ luôn luôn đượcMyClass
vàTestClass
sẽ không bao giờ mất mộta
? Tại sao không chỉ khai báo tất cả 3 đối số trongBaseClass.__init__()
mà mặc định tất cả chúng thànhNone
?def __init__(self, a=None, b=None, C=None)
?