Python OOP:练习将一种方法的结果传递给另一种方法
Python OOP: Practice passing results of one method into another
这只是我关于 Python 面向对象编程的一般问题。我已经阅读了很多教程,但我很难将其应用到我自己的需求中。
我的问题围绕着如何使用 OOP 来完成 Python 中的某些基本任务。 OOP 可能不是解决此问题的最佳方法,但这主要是一个使用我已经熟悉的数据结构的 OOP 示例。
我想获取一个 CSV 文件,其中包含两个项目(在本例中为宠物)及其各自的组合价格,例如:
dog1,cat1,5.00
dog1,cat2,7.00
cat1,dog2,10.00
cat2,dog2,10.00
dog2,dog1,8.00
cat1,cat2,10.00
以下代码是我到目前为止的代码,不是很好,但希望它足够清楚地解释我的问题。使用一个非常基本的 OOP 过程(不管我是否需要),我的目标是:
(1) 创建实例,并确定所需的变量
(2) 使用这些变量,创建字典,
(3)将(2)的结果传给另一个方法,解析这个字典
最终,第一种方法创建了一个像这样的字典:
{'cat__cat': [10.0], 'dog__cat': [7.0, 10.0, 10.0], 'dog__dog': [8.0]}
第二种方法则生成:
['dog__cat', 'dog__dog']
...因为这些是 'cheaper' 项。如末尾所列,我想做的是在一行中调用这两种方法,使用一种方法调用另一种方法。
这是如何实现的?
import sys
import numpy as np
infile=sys.argv[1]
class PriceParser:
def __init__(self, linesplit):
linesplit = line.split(",")
self.Pet1 = linesplit[0]
self.Pet2 = linesplit[1]
self.price = linesplit[2].rstrip("\n")
self.Pet1short = self.Pet1[0:3]
self.Pet2short = self.Pet2[0:3]
self.combo = self.Pet1short+"__"+self.Pet2short
self.comborev = self.Pet2short+"__"+self.Pet1short
self.PetSame = self.Pet1short+"__"+self.Pet1short
#dictPetPrices = {}
def PriceIdentifier (self):
if self.Pet1short != self.Pet2short:
if not self.comborev in dictPetPrices:
if not self.combo in dictPetPrices:
dictPetPrices[self.combo]=[]
dictPetPrices[self.combo]=[float(self.price)]
else:
dictPetPrices[self.comborev].append(float(self.price))
elif self.Pet1short == self.Pet2short:
if not self.PetSame in dictPetPrices:
dictPetPrices[self.PetSame]=[]
dictPetPrices[self.PetSame].append(float(self.price))
return dictPetPrices
def PriceSpectrum (self):
Cheap = []
for k,v in dictPetPrices.iteritems():
for i in v:
if float(i) <= 8:
Cheap.append(k)
return Cheap
if __name__ == '__main__':
with open(infile) as f:
dictPetPrices = {}
for line in f:
A = PriceParser(line)
B=A.PriceIdentifier()
print B
print A.PriceSpectrum()
#What I would prefer to do (below), is pass one method into another, if for instance, I have multiple methods that need to be called
#print A.PriceSpectrum(PriceIdentifier)
您有一些正确的想法,但您的代码结构不正确。当您调用 PriceParser(linesplit)
时,您实际上是在调用 PriceParser.__init__(self,linesplit)
。这是初始化成员变量的正确位置。因此,将第一组代码从 PriceIdentifier
向下移动到 ## 注释,然后移动到 __init__
中。这将解决未定义变量名的问题。
我不明白你在 ## 注释后的代码中试图做什么。将您的问题放在文本中而不是将它们埋在代码注释中是个好主意。顺便说一句,self.Percentiles[:]=[]
行无法访问(在 return 之后)。
我会根据我对您代码中发生的情况的解释来尝试回答您。
我可以告诉你很多(乍一看):
...
def __init__ (self, ...):
self.Pet1 = Pet1
引发 NameError,因为您尝试放入 self.Pet1 的全局变量 Pet1 不存在。
是的,如果 Pet1 在 class 之外初始化,并且在实例化 class 之前当然可以工作。
# If you wanted just to initialize self.Pet1 then give it a value like: "Pet1", "" or None; inside __init__() constructor.
self.Pet1 = ""
你的class是一个解析器,然后解析你在构造函数中的行,并将值放入属性中。
如果你这样做,就不需要其他方法接受参数(比 self 多),你可以使用这些属性来访问所需的值。
然后你会得到类似的东西:
for line in f:
A = PriceParser(line)
print "Cat1 costs:", A.price("cat1") # Or whatever you want
print "Avg price of all dogs is:", A.PricesMean("dog")
# Use constructor __init__() to do all the job (splitting, putting into attrs, etc.).
# Do not use tons of arguments in methods. What if zoo-shop adds rabbits the next day?
# If you wish to have all kind of pets covered, use one attr with a dictionary to keep values for each, not a new attribute for each pet.
# If you really wish to have an attribute per pet, use an instance scope variable container self.__dict__
# For instance:
def add_doggy (self, dog_name, dog_colour, dog_price):
self.__dict__["dog_"+dog_name] = (dog_colour, dog_price)
# Then the following is possible:
A.add_doggy("Rex", "black", 30):
print "Rex costs:", A.dog_Rex[1]
# But this, and all other methods you can use to do same/similar things are more in field of meta programming for which, I think, you are not ready yet.
请按照我的评论编辑您的问题。
通过带有示例的教程开始学习 OOP,尝试做一些严肃的事情,例如。使用 wxPython 编写 GUI,它将帮助您掌握它。
import numpy as np
inputstr = """\
dog1,cat1,5.00
dog1,cat2,7.00
cat1,dog2,10.00
cat2,dog2,10.00
dog2,dog1,8.00
cat1,cat2,10.00"""
class PriceParser:
def __init__(self, line):
linesplit = line.strip().split(",")
self.Pet1 = linesplit[0]
self.Pet2 = linesplit[1]
self.price = linesplit[2]
self.Pet1short = self.Pet1[0:3]
self.Pet2short = self.Pet2[0:3]
self.combo = self.Pet1short+"__"+self.Pet2short
self.comborev = self.Pet2short+"__"+self.Pet1short
self.PetSame = self.Pet1short+"__"+self.Pet1short
self.dictPetPrices = {}
def PriceIdentifier (self):
if self.Pet1short != self.Pet2short:
if not self.comborev in self.dictPetPrices:
if not self.combo in self.dictPetPrices:
self.dictPetPrices[self.combo]=[]
self.dictPetPrices[self.combo]=[float(self.price)]
else:
self.dictPetPrices[self.comborev].append(float(self.price))
elif self.Pet1short == self.Pet2short:
if not self.PetSame in self.dictPetPrices:
self.dictPetPrices[self.PetSame]=[]
self.dictPetPrices[self.PetSame].append(float(self.price))
return self.dictPetPrices
def PriceSpectrum (self, call_ident=True):
if call_ident: self.PriceIdentifier()
Percentiles = []
for k in self.dictPetPrices.keys():
self.dictPetPrices[k].sort()
a = np.asarray(self.dictPetPrices[k])
Q1 = np.percentile(a, 1)
Q25 = np.percentile(a, 25)
Q50 = np.percentile(a, 50)
Q75 = np.percentile(a, 75)
Q90 = np.percentile(a, 90)
Percentiles.extend([Q1,Q50,Q75,Q90])
return Percentiles
if __name__ == '__main__':
for line in inputstr.split("\n"):
A = PriceParser(line)
print A.PriceIdentifier()
print A.PriceSpectrum()
这会产生以下结果:
{'dog__cat': [5.0]}
[5.0, 5.0, 5.0, 5.0]
{'dog__cat': [7.0]}
[7.0, 7.0, 7.0, 7.0]
{'cat__dog': [10.0]}
[10.0, 10.0, 10.0, 10.0]
{'cat__dog': [10.0]}
[10.0, 10.0, 10.0, 10.0]
{'dog__dog': [8.0]}
[8.0, 8.0, 8.0, 8.0]
{'cat__cat': [10.0]}
[10.0, 10.0, 10.0, 10.0]
请说明您希望得到什么结果。
您是否打算制作一个包含所有价格的数组,那么,您必须解析 class 内的所有输入或使用其他结构。
您在这里只解析一行。
或者,您可以让 PriceSpectrum() 接受参数,一个列表,然后它会累积所有价格或类似的东西。
如您所见,方法使用属性进行内部通信。
函数的 Milion 参数是用于结构编程的东西。
将此概念排除在任何 OO 之外。方法应该只接受请求或提供实例尚不可用的东西所需的参数。
请根据我的代码解释一切。我做错了什么,你想达到什么目的。您的问题的沟通是否令人满意,或者您的目标是某种特殊类型。
我真的希望这会有所帮助。至少,现在没有错误。
好多了,好多了! call_ident 是导致调用 self.PriceIdentifier() 的参数。如果您之前没有手动调用它,那是为了确保调用 self.PriceIdentifier() 。如果你之前确实调用过它,你可以说 self.PriceSpectrum(0) 以避免再次调用它。
如果你想将一个函数传递给另一个函数,正如我所理解的,你就像在 C 中那样做。 Python 中的可变对象通过引用访问,即指向对象的指针存储在变量中。至少你可以这样看。这就是为什么在将列表传递给函数时必须复制列表的原因,除非您希望在该函数内部更改列表时更改原始列表。
所以:
def f (another_func): return another_func()
def g (): print "blah"
f(g)
你对方法做同样的事情,因为方法只是带有附加参数 self 的函数,它是对你希望它引用的实例的引用。在大多数其他语言中,它被称为 this。
也试试这个:
def callme (func, *args, **kwargs):
print "I will call", func
print "With arguments:", args
print "And keyword arguments:", kwargs
func(*args, **kwargs)
def dateandtime (date, time, zone=None):
print "The date:", date
print "The time:", time
print "Zone:", zone
callme(dateandtime, "01.01.1881. AC", "00:00:00")
尝试添加区域看看会发生什么。
如果这是你想要的,那么看看 Stack 连接了哪些问题,现在 Q 更清晰了。
这只是我关于 Python 面向对象编程的一般问题。我已经阅读了很多教程,但我很难将其应用到我自己的需求中。 我的问题围绕着如何使用 OOP 来完成 Python 中的某些基本任务。 OOP 可能不是解决此问题的最佳方法,但这主要是一个使用我已经熟悉的数据结构的 OOP 示例。 我想获取一个 CSV 文件,其中包含两个项目(在本例中为宠物)及其各自的组合价格,例如:
dog1,cat1,5.00
dog1,cat2,7.00
cat1,dog2,10.00
cat2,dog2,10.00
dog2,dog1,8.00
cat1,cat2,10.00
以下代码是我到目前为止的代码,不是很好,但希望它足够清楚地解释我的问题。使用一个非常基本的 OOP 过程(不管我是否需要),我的目标是:
(1) 创建实例,并确定所需的变量
(2) 使用这些变量,创建字典,
(3)将(2)的结果传给另一个方法,解析这个字典
最终,第一种方法创建了一个像这样的字典:
{'cat__cat': [10.0], 'dog__cat': [7.0, 10.0, 10.0], 'dog__dog': [8.0]}
第二种方法则生成:
['dog__cat', 'dog__dog']
...因为这些是 'cheaper' 项。如末尾所列,我想做的是在一行中调用这两种方法,使用一种方法调用另一种方法。 这是如何实现的?
import sys
import numpy as np
infile=sys.argv[1]
class PriceParser:
def __init__(self, linesplit):
linesplit = line.split(",")
self.Pet1 = linesplit[0]
self.Pet2 = linesplit[1]
self.price = linesplit[2].rstrip("\n")
self.Pet1short = self.Pet1[0:3]
self.Pet2short = self.Pet2[0:3]
self.combo = self.Pet1short+"__"+self.Pet2short
self.comborev = self.Pet2short+"__"+self.Pet1short
self.PetSame = self.Pet1short+"__"+self.Pet1short
#dictPetPrices = {}
def PriceIdentifier (self):
if self.Pet1short != self.Pet2short:
if not self.comborev in dictPetPrices:
if not self.combo in dictPetPrices:
dictPetPrices[self.combo]=[]
dictPetPrices[self.combo]=[float(self.price)]
else:
dictPetPrices[self.comborev].append(float(self.price))
elif self.Pet1short == self.Pet2short:
if not self.PetSame in dictPetPrices:
dictPetPrices[self.PetSame]=[]
dictPetPrices[self.PetSame].append(float(self.price))
return dictPetPrices
def PriceSpectrum (self):
Cheap = []
for k,v in dictPetPrices.iteritems():
for i in v:
if float(i) <= 8:
Cheap.append(k)
return Cheap
if __name__ == '__main__':
with open(infile) as f:
dictPetPrices = {}
for line in f:
A = PriceParser(line)
B=A.PriceIdentifier()
print B
print A.PriceSpectrum()
#What I would prefer to do (below), is pass one method into another, if for instance, I have multiple methods that need to be called
#print A.PriceSpectrum(PriceIdentifier)
您有一些正确的想法,但您的代码结构不正确。当您调用 PriceParser(linesplit)
时,您实际上是在调用 PriceParser.__init__(self,linesplit)
。这是初始化成员变量的正确位置。因此,将第一组代码从 PriceIdentifier
向下移动到 ## 注释,然后移动到 __init__
中。这将解决未定义变量名的问题。
我不明白你在 ## 注释后的代码中试图做什么。将您的问题放在文本中而不是将它们埋在代码注释中是个好主意。顺便说一句,self.Percentiles[:]=[]
行无法访问(在 return 之后)。
我会根据我对您代码中发生的情况的解释来尝试回答您。 我可以告诉你很多(乍一看):
...
def __init__ (self, ...):
self.Pet1 = Pet1
引发 NameError,因为您尝试放入 self.Pet1 的全局变量 Pet1 不存在。 是的,如果 Pet1 在 class 之外初始化,并且在实例化 class 之前当然可以工作。
# If you wanted just to initialize self.Pet1 then give it a value like: "Pet1", "" or None; inside __init__() constructor.
self.Pet1 = ""
你的class是一个解析器,然后解析你在构造函数中的行,并将值放入属性中。 如果你这样做,就不需要其他方法接受参数(比 self 多),你可以使用这些属性来访问所需的值。 然后你会得到类似的东西:
for line in f:
A = PriceParser(line)
print "Cat1 costs:", A.price("cat1") # Or whatever you want
print "Avg price of all dogs is:", A.PricesMean("dog")
# Use constructor __init__() to do all the job (splitting, putting into attrs, etc.).
# Do not use tons of arguments in methods. What if zoo-shop adds rabbits the next day?
# If you wish to have all kind of pets covered, use one attr with a dictionary to keep values for each, not a new attribute for each pet.
# If you really wish to have an attribute per pet, use an instance scope variable container self.__dict__
# For instance:
def add_doggy (self, dog_name, dog_colour, dog_price):
self.__dict__["dog_"+dog_name] = (dog_colour, dog_price)
# Then the following is possible:
A.add_doggy("Rex", "black", 30):
print "Rex costs:", A.dog_Rex[1]
# But this, and all other methods you can use to do same/similar things are more in field of meta programming for which, I think, you are not ready yet.
请按照我的评论编辑您的问题。 通过带有示例的教程开始学习 OOP,尝试做一些严肃的事情,例如。使用 wxPython 编写 GUI,它将帮助您掌握它。
import numpy as np
inputstr = """\
dog1,cat1,5.00
dog1,cat2,7.00
cat1,dog2,10.00
cat2,dog2,10.00
dog2,dog1,8.00
cat1,cat2,10.00"""
class PriceParser:
def __init__(self, line):
linesplit = line.strip().split(",")
self.Pet1 = linesplit[0]
self.Pet2 = linesplit[1]
self.price = linesplit[2]
self.Pet1short = self.Pet1[0:3]
self.Pet2short = self.Pet2[0:3]
self.combo = self.Pet1short+"__"+self.Pet2short
self.comborev = self.Pet2short+"__"+self.Pet1short
self.PetSame = self.Pet1short+"__"+self.Pet1short
self.dictPetPrices = {}
def PriceIdentifier (self):
if self.Pet1short != self.Pet2short:
if not self.comborev in self.dictPetPrices:
if not self.combo in self.dictPetPrices:
self.dictPetPrices[self.combo]=[]
self.dictPetPrices[self.combo]=[float(self.price)]
else:
self.dictPetPrices[self.comborev].append(float(self.price))
elif self.Pet1short == self.Pet2short:
if not self.PetSame in self.dictPetPrices:
self.dictPetPrices[self.PetSame]=[]
self.dictPetPrices[self.PetSame].append(float(self.price))
return self.dictPetPrices
def PriceSpectrum (self, call_ident=True):
if call_ident: self.PriceIdentifier()
Percentiles = []
for k in self.dictPetPrices.keys():
self.dictPetPrices[k].sort()
a = np.asarray(self.dictPetPrices[k])
Q1 = np.percentile(a, 1)
Q25 = np.percentile(a, 25)
Q50 = np.percentile(a, 50)
Q75 = np.percentile(a, 75)
Q90 = np.percentile(a, 90)
Percentiles.extend([Q1,Q50,Q75,Q90])
return Percentiles
if __name__ == '__main__':
for line in inputstr.split("\n"):
A = PriceParser(line)
print A.PriceIdentifier()
print A.PriceSpectrum()
这会产生以下结果:
{'dog__cat': [5.0]}
[5.0, 5.0, 5.0, 5.0]
{'dog__cat': [7.0]}
[7.0, 7.0, 7.0, 7.0]
{'cat__dog': [10.0]}
[10.0, 10.0, 10.0, 10.0]
{'cat__dog': [10.0]}
[10.0, 10.0, 10.0, 10.0]
{'dog__dog': [8.0]}
[8.0, 8.0, 8.0, 8.0]
{'cat__cat': [10.0]}
[10.0, 10.0, 10.0, 10.0]
请说明您希望得到什么结果。 您是否打算制作一个包含所有价格的数组,那么,您必须解析 class 内的所有输入或使用其他结构。 您在这里只解析一行。 或者,您可以让 PriceSpectrum() 接受参数,一个列表,然后它会累积所有价格或类似的东西。
如您所见,方法使用属性进行内部通信。 函数的 Milion 参数是用于结构编程的东西。 将此概念排除在任何 OO 之外。方法应该只接受请求或提供实例尚不可用的东西所需的参数。 请根据我的代码解释一切。我做错了什么,你想达到什么目的。您的问题的沟通是否令人满意,或者您的目标是某种特殊类型。 我真的希望这会有所帮助。至少,现在没有错误。
好多了,好多了! call_ident 是导致调用 self.PriceIdentifier() 的参数。如果您之前没有手动调用它,那是为了确保调用 self.PriceIdentifier() 。如果你之前确实调用过它,你可以说 self.PriceSpectrum(0) 以避免再次调用它。 如果你想将一个函数传递给另一个函数,正如我所理解的,你就像在 C 中那样做。 Python 中的可变对象通过引用访问,即指向对象的指针存储在变量中。至少你可以这样看。这就是为什么在将列表传递给函数时必须复制列表的原因,除非您希望在该函数内部更改列表时更改原始列表。 所以:
def f (another_func): return another_func()
def g (): print "blah"
f(g)
你对方法做同样的事情,因为方法只是带有附加参数 self 的函数,它是对你希望它引用的实例的引用。在大多数其他语言中,它被称为 this。
也试试这个:
def callme (func, *args, **kwargs):
print "I will call", func
print "With arguments:", args
print "And keyword arguments:", kwargs
func(*args, **kwargs)
def dateandtime (date, time, zone=None):
print "The date:", date
print "The time:", time
print "Zone:", zone
callme(dateandtime, "01.01.1881. AC", "00:00:00")
尝试添加区域看看会发生什么。 如果这是你想要的,那么看看 Stack 连接了哪些问题,现在 Q 更清晰了。