Python中方法参数的传递技巧及示例

73 阅读3分钟

在编写一些数值计算代码时,通常需要使用类来表示有限元模型中的元素。虽然函数式编程风格简单明了,但当与类和方法结合使用时,可能会带来一些问题。对于方法参数的传递,存在以下几个主要问题:

  • 什么是方法参数传递的惯用方式?
  • 如果想使数据流更加显式,在不偏离 Pythonic 风格的前提下,可以做到什么程度?

2、解决方案

为了更好地理解不同参数传递方式的特点和优缺点,可以参考三个类示例:

  • StandardPoint:代表了常见的 Python 代码风格,参数传递隐式进行,这使得代码不太清晰且更难以测试。
  • ExplicitPoint:使状态的改变更加显式,但仍然隐式地传递数据到方法中。单元测试仍然需要模拟对象。
  • ExtremePoint:使所有数据传递都显式化,但这也使得代码更加冗长。静态方法几乎肯定走得太远,但它有道理,因为你不必依靠 self 来维护状态。顶级函数更符合 Pythonic 风格,但只有当多个类需要它时才适用。

代码示例:

from math import sqrt

class StandardPoint(object):
    """Is this idiomatic python?"""

    def __init__(self, x, y):
        self.x = x
        self.y = y
        self._calc_distance()

    def _calc_distance(self):
        self.distance = sqrt(self.x**2 + self.y**2)

class ExplicitPoint(object):
    """Explicit setting of attributes but implicit passing-in of data."""

    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.distance = None
        # ...
        self.distance = self._calc_distance()

    def _calc_distance(self):
        return sqrt(self.x**2 + self.y**2)

class ExtremePoint(object):
    """Explicit data passing everywhere."""

    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.distance = None
        self.distance = self._calc_distance(self.x, self.y)
        # or even
        # self.distance = self._calc_distance_static(self.x, self.y)

    def _calc_distance(self, x, y):
        return sqrt(x**2 + y**2)

    @staticmethod
    def _calc_distance_static(x, y):
        return sqrt(x**2 + y**2)

def calc_distance(x, y):
    """Top-level function for use by many classes."""
    return sqrt(x**2 + y**2)

惯用方式

在 Python 中,最常用的方法参数传递方式是使用属性(property)。这样可以让方法的调用方式与普通属性的访问方式相同,更加简洁和清晰。

class TestClass(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def distance(self):
        return sqrt(self.x**2 + self.y**2)

这样,就可以直接通过类实例访问 distance 属性,而不需要调用方法:

point = TestClass(3, 4)
print(point.distance)  # Output: 5.0

显式数据传递

如果需要使数据流更加显式,可以将方法参数显式地传递给方法。这可以提高代码的可读性和测试性,但也会使代码更加冗长。

class ExplicitDistancePoint(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def distance(self, x, y):
        return sqrt((self.x - x)**2 + (self.y - y)**2)

这样,在调用 distance() 方法时,需要显式地传递两个参数:

point = ExplicitDistancePoint(3, 4)
print(point.distance(0, 0))  # Output: 5.0

总结

在 Python 中,方法参数的传递方式有多种,每种方式都有其优缺点。选择哪种方式取决于具体的需求和代码风格。惯用方式是使用属性(property),这可以让方法的调用方式与普通属性的访问方式相同,更加简洁和清晰。显式数据传递可以提高代码的可读性和测试性,但也会使代码更加冗长。