独立功能或方法

2024-09-20 22:53:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要处理一个类的两个对象,它将返回同一个类的第三个对象,我正试图确定是否将它作为一个独立的函数来处理,该函数接收两个对象并返回第三个对象,还是作为一个方法来获取另一个对象并返回第三个对象。在


举个简单的例子。这会不会:

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    __slots__ = ()
    #Attached to class
    def midpoint(self, otherpoint):
        mx = (self.x + otherpoint.x) / 2.0
        my = (self.y + otherpoint.y) / 2.0
        return Point(mx, my)

a = Point(1.0, 2.0)
b = Point(2.0, 3.0)

print a.midpoint(b)
#Point(x=1.5, y=2.5)

或者这个:

^{pr2}$

为什么一个会比另一个更受欢迎呢?在


这似乎远没有我问这个问题时预想的那么明确。在

总而言之,像a.midpoint(b)这样的东西似乎并不可取,因为它似乎给一个点或另一个点赋予了一个特殊的位置,而这个对称函数实际上是返回一个全新的点实例的对称函数。但它似乎很大程度上是一个品味和风格的问题,比如一个独立的模块函数或一个附加到类的函数,但并不意味着被疯狂的人调用,比如点.中点(a、b)。在

我个人认为,我个人倾向于独立的模块功能,但这可能取决于具体情况。如果函数肯定与类紧密绑定,并且存在名称空间污染或潜在混淆的风险,那么创建类函数可能更有意义。在

另外,一些人提到要使函数更通用,可能是通过实现类的附加特性来支持这一点。在这个处理点和中点的特殊情况下,这可能是最好的方法。它支持多态性和代码重用,可读性强。不过,在很多情况下,这是行不通的(比如这个项目激发了我去问这个问题),但是点和中点似乎是一个简洁易懂的例子来说明这个问题。在

谢谢大家,很有启发性。在


Tags: 模块对象方法函数selfmy情况namedtuple
3条回答

在这种情况下,可以使用运算符重载:

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    __slots__ = ()
    #Attached to class
    def __add__(self, otherpoint):
        mx = (self.x + otherpoint.x)
        my = (self.y + otherpoint.y)
        return Point(mx, my)

    def __div__(self, scalar):
        return Point(self.x/scalar, self.y/scalar)


a = Point(1.0, 2.0)
b = Point(2.0, 3.0)

def mid(a,b): # general function
    return (a+b)/2

print mid(a,b)

我认为决定主要取决于函数的一般性和抽象性。如果您可以在实现一个小的干净接口集的所有对象上运行函数,那么就可以将它转换为一个单独的函数。你的函数依赖的接口越多,接口越具体,把它放在类上就越有意义(因为这个类的实例很可能是函数唯一可以使用的对象)。在

我会选择第二种选择,因为在我看来,它比第一种更清楚。您正在两点之间执行中点操作,而不是在某个点上执行中点操作。类似地,这个接口的自然扩展可以定义dotcrossmagnitudeaveragemedian等。其中一些函数将对Points进行操作,而其他函数则可以对列表进行操作。使其成为一个函数可以使它们都具有一致的接口。在

将它定义为函数还允许它与呈现.x.y接口的任何一对对象一起使用,而使其成为一个方法需要这两个对象中至少有一个是Point。在

最后,为了解决函数的位置问题,我认为将它与Point类放在同一个包中是有意义的。这将它放在同一个命名空间中,这清楚地表明了它与Point的关系,而且在我看来,它比静态或类方法更具python性。在

更新: 进一步阅读@staticmethodvs包/模块的pythonicity:

在thomaswouter对问题What is the difference between staticmethod and classmethod in Python的回答和Mike Steder对init and arguments in Python的回答中,作者指出相关函数的包或模块可能是更好的解决方案。托马斯·伍特说:

[staticmethod] is basically useless in Python -- you can just use a module function instead of a staticmethod.

迈克·斯特德评论道:

If you find yourself creating objects that consist of nothing but staticmethods the more pythonic thing to do would be to create a new module of related functions.

然而,codeape在下面正确地指出,Point.midpoint(a,b)的调用约定将与类型一起定位功能。BDFL似乎也值@staticmethod,因为__new__方法是^{}。在

出于上述原因,我个人倾向于使用一个函数,但似乎在@staticmethod和独立函数之间的选择很大程度上取决于旁观者。在

第一种方法是合理的,在概念上与集合.联合集合交集做。任何func(Point, Point) --> Point都明显与Point类相关,因此不存在干扰类的统一性或内聚性的问题。在

如果涉及不同的类,这将是一个更艰难的选择:draw_perpendicular(line, point) --> line。要解决类的选择问题,您可以选择具有最相关逻辑的类。例如,结构连接需要字符串分隔符和字符串列表。它可以是一个独立的函数(就像以前使用string模块时一样),也可以是列表上的方法(但它只适用于字符串列表),或者是字符串上的方法。选择后者是因为连接更多的是字符串而不是列表。尽管这个选择导致了可以说是尴尬的表达delimiter.join(things_to_join),但还是做出了这个选择。在

我不同意另一个建议使用类方法的受访者。它们通常用于替代构造函数签名,但不用于类实例的转换。例如,日期时间.fromordinal是一个类方法,用于从类的实例(在本例中,是从int中)构造日期的类方法。这与日期时间.替换这是根据现有实例生成新的datetime实例的常规方法。这将使您避免使用classmethod进行中点计算。在

另一个想法是:如果在Point()类中保留midpoint(),则可以创建具有相同Point API但内部表示不同的其他类(即极坐标对于某些类型的工作可能比笛卡尔坐标更方便)。如果midpoint()是一个单独的函数,那么您将开始失去封装和一致接口的好处。在

相关问题 更多 >

    热门问题