From a25c4c09add49ff869e1f473c99a50d87a31e9dc Mon Sep 17 00:00:00 2001 From: XiongNeng Date: Thu, 5 Feb 2015 16:14:15 +0800 Subject: [PATCH] =?UTF-8?q?8.20=E5=B0=8F=E8=8A=82=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- basic/mystring/strformat.py | 4 +- cookbook/c08/p20_invoke_bystr.py | 40 +++++++++++ ...0_call_method_on_object_by_string_name.rst | 68 ++++++++++++++++++- 3 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 cookbook/c08/p20_invoke_bystr.py diff --git a/basic/mystring/strformat.py b/basic/mystring/strformat.py index 5342d4b..22685b6 100644 --- a/basic/mystring/strformat.py +++ b/basic/mystring/strformat.py @@ -7,6 +7,7 @@ __author__ = 'Xiong Neng' + def simple(): # 一般的%形式的格式化 a = 42 @@ -33,7 +34,8 @@ def simple(): name = 'Elwood' age = 99 print('%(name)s is %(age)s years old.' % vars()) - #print('{0} {1} {2}'.format()) + # print('{0} {1} {2}'.format()) + def senior(): """高级字符串格式化""" diff --git a/cookbook/c08/p20_invoke_bystr.py b/cookbook/c08/p20_invoke_bystr.py new file mode 100644 index 0000000..29c54fb --- /dev/null +++ b/cookbook/c08/p20_invoke_bystr.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +""" +Topic: 通过字符串调用方法 +Desc : +""" + +import math + + +class Point: + def __init__(self, x, y): + self.x = x + self.y = y + + def __repr__(self): + # !r表示调用后面参数的__repr__()方法 + return 'Point({!r:},{!r:})'.format(self.x, self.y) + + def distance(self, x, y): + return math.hypot(self.x - x, self.y - y) + + +p = Point(2, 3) +d = getattr(p, 'distance')(0, 0) # Calls p.distance(0, 0) + +import operator + +operator.methodcaller('distance', 0, 0)(p) + +points = [ + Point(1, 2), + Point(3, 0), + Point(10, -3), + Point(-5, -7), + Point(-1, 8), + Point(3, 2) +] +# Sort by distance from origin (0, 0) +points.sort(key=operator.methodcaller('distance', 0, 0)) diff --git a/source/c08/p20_call_method_on_object_by_string_name.rst b/source/c08/p20_call_method_on_object_by_string_name.rst index 15aeff0..314a0fd 100644 --- a/source/c08/p20_call_method_on_object_by_string_name.rst +++ b/source/c08/p20_call_method_on_object_by_string_name.rst @@ -5,14 +5,76 @@ ---------- 问题 ---------- -todo... +你有一个字符串形式的方法名称,想通过它调用某个对象的对应方法。 + +| ---------- 解决方案 ---------- -todo... +最简单的情况,可以使用 ``getattr()`` : + +.. code-block:: python + + import math + + class Point: + def __init__(self, x, y): + self.x = x + self.y = y + + def __repr__(self): + return 'Point({!r:},{!r:})'.format(self.x, self.y) + + def distance(self, x, y): + return math.hypot(self.x - x, self.y - y) + + + p = Point(2, 3) + d = getattr(p, 'distance')(0, 0) # Calls p.distance(0, 0) + +另外一种方法是使用 ``operator.methodcaller()`` ,例如: + +.. code-block:: python + + import operator + operator.methodcaller('distance', 0, 0)(p) + +当你需要通过相同的参数多次调用某个方法时,使用 ``operator.methodcaller`` 就很方便了。 +比如你需要排序一系列的点,就可以这样做: + +.. code-block:: python + + points = [ + Point(1, 2), + Point(3, 0), + Point(10, -3), + Point(-5, -7), + Point(-1, 8), + Point(3, 2) + ] + # Sort by distance from origin (0, 0) + points.sort(key=operator.methodcaller('distance', 0, 0)) + +| ---------- 讨论 ---------- -todo... \ No newline at end of file +调用一个方法实际上是两部独立操作,第一步是查找属性,第二步是函数调用。 +因此,为了调用某个方法,你可以首先通过 ``getattr()`` 来查找到这个属性,然后再去以函数方式调用它即可。 + +``operator.methodcaller()`` 创建一个可调用对象,并同时提供所有必要参数, +然后调用的时候只需要将实例对象传递给它即可,比如: + +.. code-block:: python + + >>> p = Point(3, 4) + >>> d = operator.methodcaller('distance', 0, 0) + >>> d(p) + 5.0 + >>> + +通过方法名称字符串来调用方法通常出现在需要模拟 ``case`` 语句或实现访问者模式的时候。 +参考下一小节获取更多高级例子。 +