Hãy thực hiện điều này với tạo kiểu động:
import copy
def namedgroup(typename, fieldnames):
def init(self, **kwargs):
attrs = {k: None for k in self._attrs_}
for k in kwargs:
if k in self._attrs_:
attrs[k] = kwargs[k]
else:
raise AttributeError('Invalid Field')
self.__dict__.update(attrs)
def getattribute(self, attr):
if attr.startswith("_") or attr in self._attrs_:
return object.__getattribute__(self, attr)
else:
raise AttributeError('Invalid Field')
def setattr(self, attr, value):
if attr in self._attrs_:
object.__setattr__(self, attr, value)
else:
raise AttributeError('Invalid Field')
def rep(self):
d = ["{}={}".format(v,self.__dict__[v]) for v in self._attrs_]
return self._typename_ + '(' + ', '.join(d) + ')'
def iterate(self):
for x in self._attrs_:
yield self.__dict__[x]
raise StopIteration()
def setitem(self, *args, **kwargs):
return self.__dict__.__setitem__(*args, **kwargs)
def getitem(self, *args, **kwargs):
return self.__dict__.__getitem__(*args, **kwargs)
attrs = {"__init__": init,
"__setattr__": setattr,
"__getattribute__": getattribute,
"_attrs_": copy.deepcopy(fieldnames),
"_typename_": str(typename),
"__str__": rep,
"__repr__": rep,
"__len__": lambda self: len(fieldnames),
"__iter__": iterate,
"__setitem__": setitem,
"__getitem__": getitem,
}
return type(typename, (object,), attrs)
Thao tác này sẽ kiểm tra các thuộc tính để xem chúng có hợp lệ hay không trước khi cho phép tiếp tục hoạt động.
Vậy cái này có ngâm được không? Có nếu (và chỉ khi) bạn làm như sau:
>>> import pickle
>>> Point = namedgroup("Point", ["x", "y"])
>>> p = Point(x=100, y=200)
>>> p2 = pickle.loads(pickle.dumps(p))
>>> p2.x
100
>>> p2.y
200
>>> id(p) != id(p2)
True
Định nghĩa phải nằm trong không gian tên của bạn và phải tồn tại đủ lâu để pickle tìm thấy nó. Vì vậy, nếu bạn xác định điều này là trong gói của bạn, nó sẽ hoạt động.
Point = namedgroup("Point", ["x", "y"])
Pickle sẽ không thành công nếu bạn làm như sau hoặc đặt định nghĩa tạm thời (vượt ra ngoài phạm vi khi hàm kết thúc, chẳng hạn):
some_point = namedgroup("Point", ["x", "y"])
Và có, nó bảo toàn thứ tự của các trường được liệt kê trong phần tạo kiểu.