使OOP代码成为FP的Python装饰器;好主意还是坏主意?
最近,我一直在试图找到一种解决“表达式问题”的方法,在OOP或FP(函数式编程)中实现代码。我用来说明我的问题的例子是Vector2D类。我可以创建一个包含2D向量所有必要函数(点积、幅值等)的类,也可以创建一组函数,这些函数采用表示向量的2元组。我应该选择哪一个选项 为了解决这个问题,我认为制作一个接受类的方法并将它们转换为全局函数的装饰器可能会很好。我就是这样做的:使OOP代码成为FP的Python装饰器;好主意还是坏主意?,python,oop,Python,Oop,最近,我一直在试图找到一种解决“表达式问题”的方法,在OOP或FP(函数式编程)中实现代码。我用来说明我的问题的例子是Vector2D类。我可以创建一个包含2D向量所有必要函数(点积、幅值等)的类,也可以创建一组函数,这些函数采用表示向量的2元组。我应该选择哪一个选项 为了解决这个问题,我认为制作一个接受类的方法并将它们转换为全局函数的装饰器可能会很好。我就是这样做的: import types def function(method): method._function = True
import types
def function(method):
method._function = True
return method
def make_functions(cls):
for key in cls.__dict__:
method = getattr(cls, key)
if not isinstance(method, types.FunctionType):
continue
if hasattr(method, '_function') and method._function:
globals()[method.__name__] = method
return cls
@make_functions
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%g, %g)' % (self.x, self.y)
def __iter__(self):
for component in self.x, self.y:
yield component
def __getitem__(self, key):
return (self.x, self.y)[key]
def __setitem__(self, key, val):
if key == 0:
self.x = val
elif key == 1:
self.y = val
else:
print('not cool man')
def __add__(self, other):
x = self[0] + other[0]
y = self[1] + other[1]
return self.__class__(x, y)
__radd__ = __add__
def __sub__(self, other):
x = self[0] - other[0]
y = self[1] - other[1]
return self.__class__(x, y)
def __rsub__(self, other):
x = other[0] - self[0]
y = other[1] - self[1]
return self.__class__(x, y)
def __mul__(self, other):
x = other * self[0]
y = other * self[1]
return self.__class__(x, y)
__rmul__ = __mul__
@function
def dot_product(self, other):
return self[0]*other[1] + self[1]*other[0]
现在,dot_product
不仅是Vector2D
类的一种方法,而且是一种全局函数,它接受两个向量(或类似向量的对象)。这满足了实现这样一个对象的功能性和面向对象的方法。我能预见这种方法的唯一问题是,任何可以表示为另一个对象(如元组或列表)的类都必须定义为与行为类似的对象以相同的方式工作。这对于一个也可以是元组的向量来说并不坏,因为我们所要做的就是定义\uuu getitem\uuu
和\uuuu iter\uuuu
方法,但是我可以看到对于具有多个对比实现的类来说,这会变得非常失控
这是解决问题的公平办法吗?这是坏习惯还是坏技巧?我应该只提供一个还是另一个?Python有一个修饰符,用于在不实例化该类的情况下使用类方法。只需使用静态方法包装器对类方法进行注释(注意,该方法现在不采用自引用),就可以从类本身调用它
在您的情况下,对于dot产品,只需执行以下操作:
class Vector2D():
# Magic methods here...
@staticmethod
def dot_product(a, b):
return a[0]*b[1] + a[1]*b[0]
然后,只需调用Vector2D.dot\u product(my\u vector1,my\u vector2)
即可使用Vector2D
类本身的函数
将类方法分配给全局函数听起来像是一个非常危险、有缺陷、复杂且冗长的解决方案。我会不惜一切代价避免它。使用类方法作为全局函数会产生哪些具体问题?@user3002473这使得不可能知道实际实现的位置,尤其是在不同类中具有相同名称的函数时。为什么不改用
Vector2D.dot_产品(a,b)
呢?哦,我不反对使用Vector2D.dot_产品(a,b)
,我只是好奇而已。感谢您的详细说明:)这是一个可疑的用法:|@user2864740我的道歉。我对这个术语不太熟悉,在使用它来描述我的情况之前,我应该查阅一个完整的定义。@user2864740作为将来的参考,什么是描述这个概念的合适术语?如果要给出任何名称,程序(如意义上的)可能是一个更好的“名称”;但这也是一个宽泛的术语。