[英]Python decorator that makes OOP code FP; good or bad idea?
Recently I've been trying to figure out a solution to the 'expression problem' of choosing between implementing my code in OOP or FP (functional programming). 最近,我一直在尝试解决“表达问题”的解决方案,即在OOP或FP(功能性编程)中实现我的代码之间进行选择。 The example I used to illustrate my problem was a Vector2D class.
我用来说明问题的示例是Vector2D类。 I could make a class that contains all the necessary functions for a 2D vector (dot product, magnitude, etc.), or I could make a set of functions that take a 2-tuple representing a vector.
我可以创建一个包含2D向量的所有必需函数(点积,幅度等)的类,也可以创建一组以2元组表示向量的函数。 Which option do I chose?
我选择哪个选项?
To cope with this problem, I thought it might be nice to make a decorator that takes a class's methods and turns them into global functions. 为了解决这个问题,我认为最好制作一个使用类的方法并将其转换为全局函数的装饰器。 This is how I did it:
这是我的方法:
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]
Now, dot_product
is not only a method of the Vector2D
class, but it is also a global function that takes in two vectors (or vector-like objects). 现在,
dot_product
不仅是Vector2D
类的方法,而且还是一个接受两个向量(或类似向量的对象)的全局函数。 This satisfies both the functional and object-oriented approaches to implementing an object like this. 这满足了实现这样的对象的功能和面向对象的方法。 The only problem I can foresee this approach making is that any class that can be represented as another object like a tuple or a list, must be defined to work in the same ways as the objects which act like it.
我可以预见的是,这种方法的唯一问题是,必须将可以表示为另一个对象(如元组或列表)的任何类定义为以与像其作用的对象相同的方式工作。 This is not so bad for a Vector that can also be a tuple, since all we have to do is define the
__getitem__
and __iter__
methods, however I can see this getting wildly out of control for classes that have multiple contrasting implementations 这对于也可以是一个元组的Vector来说还不错,因为我们要做的就是定义
__getitem__
和__iter__
方法,但是我可以看到,对于具有多个对比实现的类,这变得非常失控
Is this a fair solution to the problem? 这是问题的公平解决方案吗? Is it bad practice or technique?
这是不好的做法还是技巧? Should I solely provide one or the other?
我应该只提供其中一个吗?
Python has a @staticmethod
decorator for using class methods without an instantiation of that class. Python有一个
@staticmethod
装饰器,用于使用类方法而不实例化该类。 Simply annotate a class method with the static method wrapper (note the method now does not take a self reference), and you can call it from the class itself. 只需使用静态方法包装器对类方法进行注释(请注意,该方法现在不具有自我引用),您可以从类本身进行调用。
In your case, for the dot product, simply do: 对于您的情况,对于点积,只需执行以下操作:
class Vector2D():
# Magic methods here...
@staticmethod
def dot_product(a, b):
return a[0]*b[1] + a[1]*b[0]
Then, simply call Vector2D.dot_product(my_vector1, my_vector2)
to use the function from the Vector2D
class itself. 然后,只需调用
Vector2D.dot_product(my_vector1, my_vector2)
即可使用Vector2D
类本身的函数。
Assigning class methods to global functions sounds like a very dangerous, buggy, complex, and verbose solution. 将类方法分配给全局函数听起来像是一个非常危险,错误,复杂且冗长的解决方案。 I would avoid it at all costs.
我会不惜一切代价避免它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.