Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kadaliao/d9687b6a995c44a7b70e0fdce32857a3 to your computer and use it in GitHub Desktop.
Save kadaliao/d9687b6a995c44a7b70e0fdce32857a3 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 用元类验证子类"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class '__main__.Meta'> Test () {'__module__': '__main__', '__qualname__': 'Test', 'hello': 'world', '__init__': <function Test.__init__ at 0x13f29d268>}\n"
]
}
],
"source": [
"class Meta(type):\n",
" def __new__(metaclass, name, bases, class_dict):\n",
" print(metaclass, name, bases, class_dict)\n",
" return type.__new__(metaclass, name, bases, class_dict)\n",
"\n",
"class Test(metaclass=Meta):\n",
" hello = 'world'\n",
" def __init__(self, a, b):\n",
" self.a = a\n",
" self.b = b\n",
" print('Initiating Test Instance...')"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"class ValidatePolygon(type):\n",
" def __new__(meta, name, bases, class_dict):\n",
" print(meta, name, bases, class_dict)\n",
" # 有父类的时候才验证,免得自己也被验证了\n",
" if bases:\n",
" if class_dict['sides'] < 3:\n",
" raise ValueError('Polygons need at least 3 sides')\n",
" return type.__new__(meta, name, bases, class_dict)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<class '__main__.ValidatePolygon'> Polygon () {'__module__': '__main__', '__qualname__': 'Polygon', 'sides': None, 'interior_angles': <classmethod object at 0x1400c8630>}\n",
"<class '__main__.ValidatePolygon'> Triangle (<class '__main__.Polygon'>,) {'__module__': '__main__', '__qualname__': 'Triangle', 'sides': 3}\n",
"<class '__main__.ValidatePolygon'> TwoSidesPolygon (<class '__main__.Polygon'>,) {'__module__': '__main__', '__qualname__': 'TwoSidesPolygon', 'sides': 3}\n"
]
}
],
"source": [
"class Polygon(metaclass=ValidatePolygon):\n",
" sides = None\n",
" \n",
" @classmethod\n",
" def interior_angles(cls):\n",
" return (cls.sides - 2) * 180\n",
"\n",
"class Triangle(Polygon):\n",
" sides = 3\n",
" pass\n",
"\n",
"class TwoSidesPolygon(Polygon):\n",
" sides = 3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 用元类注册子类"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"class Serializable:\n",
" def __init__(self, *args, **kwargs):\n",
" self.args = args\n",
" self.kwargs = kwargs\n",
" def serialize(self):\n",
" return json.dumps({'args': self.args, 'kwargs': self.kwargs})"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"class Deseiralizable(Serializable):\n",
" @classmethod\n",
" def deserialize(cls, json_data):\n",
" params = json.loads(json_data)\n",
" return cls(*params['args'], **params['kwargs'])"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"class Point2D(Deseiralizable):\n",
" def __init__(self, x, y):\n",
" super().__init__(x, y)\n",
" self.x = x\n",
" self.y = y\n",
" def __repr__(self):\n",
" return 'Point2D(%d, %d)' % (self.x, self.y)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"args\": [1, 2], \"kwargs\": {}}\n"
]
}
],
"source": [
"p = Point2D(1, 2)\n",
"data = p.serialize()\n",
"print(data)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Point2D(1, 2)\n"
]
}
],
"source": [
"p2 = Point2D.deserialize(data)\n",
"# 不灵活,反序列化的时候需要事先知道类\n",
"print(p2)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"class BetterSerializable:\n",
" def __init__(self, *args, **kwargs):\n",
" self.args = args\n",
" self.kwargs = kwargs\n",
" def serialize(self):\n",
" data = {'target_class': self.__class__.__name__, 'args': self.args, 'kwargs': self.kwargs}\n",
" return json.dumps(data)\n",
"\n",
"class BetterPoint2D(BetterSerializable):\n",
" def __init__(self, x, y):\n",
" super().__init__(x, y)\n",
" self.x = x\n",
" self.y = y\n",
" def __repr__(self):\n",
" return f'<BetterPoint2D {self.x}, {self.y}>'"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\"target_class\": \"BetterPoint2D\", \"args\": [2, 3], \"kwargs\": {}}\n"
]
}
],
"source": [
"bp = BetterPoint2D(2, 3)\n",
"print(bp.serialize())"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"registry = {}\n",
"def registry_calss(cls):\n",
" registry[cls.__name__] = cls\n",
" \n",
"def deserialize(json_data):\n",
" params = json.loads(json_data)\n",
" target_class = params['target_class']\n",
" if not target_class:\n",
" raise ValueError('Invalid data, target_class required')\n",
" if not target_class in registry:\n",
" raise ValueError('target_class is not registered')\n",
" return registry[target_class](*params['args'], **params['kwargs'])"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"registry_calss(BetterPoint2D)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<BetterPoint2D 3, 4>\n"
]
}
],
"source": [
"bp = BetterPoint2D(3, 4)\n",
"data = bp.serialize()\n",
"bp2 = deserialize(data)\n",
"print(bp2)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'BetterPoint2D': <class '__main__.BetterPoint2D'>, 'BetterPoint3D': <class '__main__.BetterPoint3D'>}\n",
"{\"target_class\": \"BetterPoint3D\", \"args\": [1, 2, 3], \"kwargs\": {}}\n",
"<BetterPoint3D 1, 2, 3>\n"
]
}
],
"source": [
"# 如果忘记注册这个类就会报错,用元类来自动注册\n",
"class Meta(type):\n",
" def __new__(meta, name, bases, class_dict):\n",
" cls = type.__new__(meta, name, bases, class_dict)\n",
" registry[name] = cls\n",
" return cls\n",
"\n",
"class BetterPoint3D(BetterSerializable, metaclass=Meta):\n",
" def __init__(self, x, y, z):\n",
" super().__init__(x, y, z)\n",
" self.x = x\n",
" self.y = y\n",
" self.z = z\n",
" def __repr__(self):\n",
" return f'<BetterPoint3D {self.x}, {self.y}, {self.z}>'\n",
" \n",
"print(registry)\n",
"\n",
"bp3 = BetterPoint3D(1, 2, 3)\n",
"data = bp3.serialize()\n",
"print(data)\n",
"bp3 = deserialize(data)\n",
"print(bp3)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.6+"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment