【问题标题】:Python: How to implement polymorphic binary op. magic methods?Python:如何实现多态二进制操作。魔法方法?
【发布时间】:2017-06-11 21:39:06
【问题描述】:

上下文:

我每天都在使用 Pandas(处理测量数据),我想了解更多关于 Python 的信息。

为此,我正在开发一个(包装器)类——MyDataFrame——它将 Pandas DataFrame 功能与Pint 的功能相结合——一个用于定义、操作和操纵物理量的 Python 包。

我已经设法通过__str____get/setitem____truediv__ 获得一些基本功能,用于 MyDataFrame 的底层 MySeries(Pandas 系列的包装器):

API 示例:

import pint
_u = pint.UnitRegistry()

_u("meter")
>>> 1 meter

type(_u("meter"))
>>> pint.unit.build_quantity_class.<locals>.Quantity

data = [[0,1,2,3],[4,5,6,7]]

df = pd.DataFrame(data,columns=["time","distance"])

units = {"distance":_u("meter"), "time":_u("second")}

mdf = MyDataFrame(df, units)

mdf["speed"] = mdf["distance"]/mdf["time"]

mdf["speed"].unit == _u("meter per second")
>>> True

到目前为止,我将实现保持在最低限度,例如:

class MyDataFrame:
"""df: pandas DataFrame, units: dict of str - Pint quantity key-value pairs."""
    def __init__(self,df,units):

        error_handling(df,units)

        self.df = df
        self.units = units

    def __getitem__(self,key):
        if key in units.keys():
            return MySeries(self.df[key],self.units[key]) 

class MySeries:
"""series: pandas Series, units: a Pint quantity value."""
    def __init__(self,series,unit):
        self.series = series
        self.unit = unit

    def __truediv__(self,other):
        return MySeries(self.series/other.series,self.unit/other.unit)

问题:

但现在我想扩展这个基本概念,以便我们可以做例如

mdf["speed"] * 60*_u(second)

换句话说,使 MySeries __mul__() 多态 --- 不仅将 MySeries 与 MySeries 相乘,而且将 MySeries 与品脱数量相乘(反之亦然)。有什么好的方法?

我的第一个想法是让__mul__(self,other) 检查selfother 的类型。然而,阅读更多关于 Python 中的多态性 (here) 让我想知道其他人将如何实现这种多态二进制操作。

让我知道我是否应该澄清一下。

PS:顺便说一句。我注意到在尝试模仿 Pandas 语法时,我正在编写包装器,例如

def __getitem__(self,key):
    return self.series[key]

def notnull(self):
    return self.series.notnull()

关于将所有常用的 Pandas 方法调用重定向到 MyDataFrame / MySeries 类的 Pandas 部分有什么建议吗?

顺便说一句,我知道是时候深入研究 Python 的文档了...

【问题讨论】:

    标签: python pandas polymorphism pint


    【解决方案1】:

    很遗憾,没有其他办法。通过为每种类型的 Pandas 实现 mul 已经使用了多态性,因此相应的运算符在第一个参数的类型上表现不同。但是,对于第二个参数,您必须检查类型。在静态语言中,这将通过重载基于第二个参数类型的函数来完成,但在 Python 中,您必须使用 isinstance。如果您查看源代码,甚至 Python 标准库本身也使用这种方法。

    【讨论】:

    • 感谢您的解释。通过isistance 处理对我来说没问题,如果不是因为处理Pint 主类类型的一些困难:例如type(_u("meter")) 返回 pint.unit.build_unit_class.&lt;locals&gt;.Unit 我希望它返回类似 Unit 的东西。有什么线索吗?
    • 不要使用type,它会忽略子类。请改用isinstance(_u("meter"), Unit)
    • 这已经很清楚了,但是上面的返回 name 'Unit' is not defined 这让我认为 import pint 不足以让 Python 知道 Pint 的 Unit 类。顺便说一句,我正在使用 Jupyter 笔记本以防万一。解决方案是否类似于from pint import Unit
    • 不,还不够,import pint 只导入包。您应该from pint.a.b.c import Unit(或类似的东西),或将类称为pint.a.b.c.Unit。 (a、b、c是pint的子包,不知道是什么,见pint结构)。这与 Python 的导入方式有关(阅读文档的相应章节),与 jupyter 或库无关。
    • 看来我的问题与 Pint 类的实际实现有关,或者不是? _u = pint.UnitRegistry()Quantity = pint.unit.build_quantity_class(_u)isinstance(_u("m"),Quantity)&gt;&gt;&gt;False
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 2016-04-06
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-15
    相关资源
    最近更新 更多