Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 方法链接而不永久改变对象_Python_Pandas_Python 2.x_Method Chaining - Fatal编程技术网

Python 方法链接而不永久改变对象

Python 方法链接而不永久改变对象,python,pandas,python-2.x,method-chaining,Python,Pandas,Python 2.x,Method Chaining,目前我正在学习如何编写python类和方法链接。基本上,我想要一个python(2.7)类,它保存我的数据,并具有(可链接的)方法,允许我在不改变原始数据的情况下过滤数据。我用谷歌搜索了一下,似乎我的答案可能与返回self有关,但我不确定如何实现它,以使这些方法不会改变我的原始数据 假设我有一个数据存储在一个名为file的excel文件中,如下所示: +--------+-----+-------+ |个人|性别|得分| +--------+-----+-------+ |A | M | 10|

目前我正在学习如何编写python类和方法链接。基本上,我想要一个python(2.7)类,它保存我的数据,并具有(可链接的)方法,允许我在不改变原始数据的情况下过滤数据。我用谷歌搜索了一下,似乎我的答案可能与
返回self
有关,但我不确定如何实现它,以使这些方法不会改变我的原始数据

假设我有一个数据存储在一个名为
file
的excel文件中,如下所示:

+--------+-----+-------+
|个人|性别|得分|
+--------+-----+-------+
|A | M | 10|
|B | F | 9|
|C | M | 8|
|D | F | 7|
+--------+-----+-------+
我想编写一个名为
MyData
的类,这样我就可以进行一些基本的数据调用和过滤

这就是我目前得到的

class MyData:
    def __init__ (self, file):
        import pandas as pd
        self.data = pd.read_excel (file)
        self.Person = self.data['Person']
        self.Sex = self.data['Sex']
        self.Score = self.data['Score']

    def male_only(self):
        self.data = self.data[self.Sex=="M"]
        self.Person = self.Person[self.Sex=="M"]
        self.Score = self.Score[self.Sex=="M"]
        self.Sex = self.Sex[self.Sex=="M"]
        return self

    def female_only(self):
        self.data = self.data[self.Sex=="F"]
        self.Person = self.Person[self.Sex=="F"]
        self.Score = self.Score[self.Sex=="F"]
        self.Sex = self.Sex[self.Sex=="F"]
        return self
这似乎是可行的,但可悲的是,我的原始数据被这段代码永久地改变了。例如:

Data=MyData(文件)
数据
>>>数据
个人性别得分
上午10点零分
1 B F 9
2cm8
三维F 7
Data.male_only().数据
>>>Data.male_only().数据
个人性别得分
上午10点零分
2cm8
数据
>>>数据
个人性别得分
上午10点零分
2cm8

我想要一个类,它为
Data.male_only().Person
Data.Person.male_only()
Data.male_only().Data
Data.Data.male_only()返回相同的答案
无需永久变异
Data.Data
Data.Person
当您编写
self.Data=…
时,您可以在第1行中显式修改self.Data。您可以返回数据的新实例:

    def male_only(self):
        newdata = MyData()
        newdata.data = self.data[self.Sex=="M"]
        newdata.Person = self.Person[self.Sex=="M"]
        newdata.Score = self.Score[self.Sex=="M"]
        newdata.Sex = self.Sex[self.Sex=="M"]
        return newdata
根据您的意见,这里有一个过滤器解决方案的建议:有一些函数可以激活一些标志/过滤器,然后您必须编写函数来获取属性:

# self.filters should be initialized to [] in __init__
def male_only(self):
    self.filters.append('male_only')
def person(self):
    if "male_only" in self.filters:
        return self.Person[self.Sex=="M"]
    else: 
        return self.Person

要想知道这是否有意义,你应该真正完成你的测试用例来帮助你修正你的想法(最好先写测试用例,然后再写类)。

我想详细说明一下@Demi Lune的答案。我认为没有一种方法可以绕过创建
MyData
实例、修改它并从链方法返回它。这类事情首先起作用的全部原因是,所有的链方法都属于同一个类,并且它们返回该类的一个实例

例如,
str.swapcase
str.zfill
str.replace
都是
str
的一部分,它们都返回
str
s

>>> string = "Hello World"
>>> string.swapcase().zfill(16).replace("L", "T")
'00000hETTO wORTD'
>>> string
'Hello World'
>>> 

您试图做的(
Data.Person.male_only()
)打破了这种模式,因为现在暗示方法
male_only
不是
MyData
类的一部分,而是属于
Person
对象的方法。什么是
self.Person
self.data[“Person”]
?我对熊猫不是很熟悉。它是一根绳子吗?字符串列表?在任何情况下,不管是什么,您试图实现的基本目标都是在该类型的类中添加一个名为
male\u only
的新方法。

我同意@Demi Lune

我更改了OP的代码,以便
male_only()
memale_only()
方法始终返回其所属对象的副本。我更改了
\uuuu init\uuuu()
方法,因为我认为您不希望每次创建新对象时都调用
pd.read\u csv()
方法。所以
male\u only()
memale\u only()
方法总是返回新对象,它不会对其他对象产生影响

import pandas as pd

# Added for creating file on memory.
import io
csv = '''Person,Sex,Score
p1,M,1
p2,M,2
p3,M,3
p4,F,4
p5,F,5
p6,F,6'''
file = io.StringIO(csv)

class MyData:
    def __init__ (self, file=None, data=None):
        import pandas as pd
        if file:
            self.data = pd.read_csv(file)
        else:
            self.data = data
        self.Person = self.data['Person']
        self.Sex = self.data['Sex']
        self.Score = self.data['Score']

    def copy_d(self):
        return MyData(data=self.data.copy())

    def male_only(self):
        d = self.copy_d()
        d.data = self.data[self.Sex=="M"]
        d.Person = self.Person[self.Sex=="M"]
        d.Score = self.Score[self.Sex=="M"]
        d.Sex = self.Sex[self.Sex=="M"]
        return d

    def female_only(self):
        d = self.copy_d()
        d.data = self.data[self.Sex=="F"]
        d.Person = self.Person[self.Sex=="F"]
        d.Score = self.Score[self.Sex=="F"]
        d.Sex = self.Sex[self.Sex=="F"]
        return d

d = MyData(file)
print(d.female_only().data)
#   Person Sex  Score
# 3     p4   F      4
# 4     p5   F      5
# 5     p6   F      6

print(d.male_only().data)
#   Person Sex  Score
# 0     p1   M      1
# 1     p2   M      2
# 2     p3   M      3

print(d.data)
#   Person Sex  Score
# 0     p1   M      1
# 1     p2   M      2
# 2     p3   M      3
# 3     p4   F      4
# 4     p5   F      5
# 5     p6   F      6
但是,如果您只是使用
pandas.DataFrame
,另一种方法就是使用裸
pandas.DataFrame
。首先,在大多数情况下,
pandas.DataFrame
对象已经具有与列名称相等的属性名称。所以实际上,您不需要定义诸如
Person
Sex
Score
之类的属性,因为它已经存在于DataFrame对象中

即:

因此,您的
仅限男性()
仅限女性()
方法编写如下

import pandas as pd

# Added for creating file on memory.
import io
csv = '''Person,Sex,Score
p1,M,1
p2,M,2
p3,M,3
p4,F,4
p5,F,5
p6,F,6'''
file = io.StringIO(csv)

def male_only(df):
    return df[df.Sex=='M']

def female_only(df):
    return df[df.Sex=='F']

df = pd.read_csv(file)
male_only(df)
# In [1034]: male_only(df)
# Out[1037]: 
#   Person Sex  Score
# 0     p1   M      1
# 1     p2   M      2
# 2     p3   M      3

female_only(df)
# In [1038]: female_only(df)
# Out[1041]: 
#   Person Sex  Score
# 3     p4   F      4
# 4     p5   F      5
# 5     p6   F      6

我希望它能对您有所帮助。

如果您不想改变正在调用这些方法的对象,那么显然您需要返回一个新对象,而不是
self
。您当前的
\uuuu init\uuuu()
并不是很理想,因为它只允许您从文件而不是从现有的数据帧创建新的
MyData
。@jasonharper我对这一点非常陌生,但我目前的理解是
返回自我
对于方法链接是必不可少的。。。对于
Data.male_only().Person
Data.Person.male_only()
返回相同答案而不永久更改
Data.Person
的代码示例,将不胜感激。非常感谢。谢谢你的回答。然而,我不认为这是我要找的。例如,此解决方案适用于
Data.Person.male_only().Person
,但对于
Data.Person.male_only()
,它将失败。然后,另一种可能是使用某种“查看/筛选”功能管理对象。你应该用更多你想做的例子或测试用例来丰富你的问题。我会用“过滤”解决方案来编辑我的答案。这不是我想要的,但肯定是一个很酷的技巧。
person
方法实际上非常有用。非常感谢更新的答案。非常感谢。你的回答很有帮助,我想这就是我想要的。只是澄清一下,它并不是专门使用
pandas.DataFrame
。这只是一个关于python类的练习,该类包含允许用户操作返回对象而无需永久更改的方法
import pandas as pd

# Added for creating file on memory.
import io
csv = '''Person,Sex,Score
p1,M,1
p2,M,2
p3,M,3
p4,F,4
p5,F,5
p6,F,6'''
file = io.StringIO(csv)

def male_only(df):
    return df[df.Sex=='M']

def female_only(df):
    return df[df.Sex=='F']

df = pd.read_csv(file)
male_only(df)
# In [1034]: male_only(df)
# Out[1037]: 
#   Person Sex  Score
# 0     p1   M      1
# 1     p2   M      2
# 2     p3   M      3

female_only(df)
# In [1038]: female_only(df)
# Out[1041]: 
#   Person Sex  Score
# 3     p4   F      4
# 4     p5   F      5
# 5     p6   F      6