在编写一些数值计算代码时,通常需要使用类来表示有限元模型中的元素。虽然函数式编程风格简单明了,但当与类和方法结合使用时,可能会带来一些问题。对于方法参数的传递,存在以下几个主要问题:
- 什么是方法参数传递的惯用方式?
- 如果想使数据流更加显式,在不偏离 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),这可以让方法的调用方式与普通属性的访问方式相同,更加简洁和清晰。显式数据传递可以提高代码的可读性和测试性,但也会使代码更加冗长。