gpt4 book ai didi

Python - 如何将实例变量作为隐式参数一般传递给方法并使用递归方法

转载 作者:太空宇宙 更新时间:2023-11-03 15:44:26 26 4
gpt4 key购买 nike

我在将对象的实例变量传递给实例方法时遇到问题。

我在其他地方搜索过这个,但我一直在寻找关于如何使用 self 将对象传递给方法的信息,我已经知道了,或者只是关于类和类之间的一般差异的教程没有具体回答我的问题的实例方法。我的问题的答案肯定存在于某个地方,我想我只是不知道该问什么。

在我的代码中,我有这个类:

class SongData:

def __init__(self, datapoint):
self.artist = datapoint['artist']
self.track = datapoint['name']

def xtradata_rm(self, regex, string=None):
if string is None:
string = self
srchrslts = re.search(regex, string)
if srchrslts is not None:
if regex == 'f.*?t':
self = self.replace(string,'')
self.xtradata_rm('\((.*?)\)')
else:
self.xtradata_rm('f.*?t', srchrslts)

def example_method(self):
#This one isn't actually in the code, included for ease of explanation.
print(self)

#some more methods irrelevant to question down here.

假设我们通过 song = SongData(datapoint) 来实例化一个对象。 xtradata_rm 方法应该在 song.artistsong.track 字符串中搜索括号中的部分,然后如果找到的部分包含任何形式的单词“featuring”都将其从字符串中删除,然后重试,直到找不到更多括号中包含“featuring”的括号表达式。

我现在知道这可能 100% 错误地使用了 self,但我不知道该放什么来实现我想要的行为。那么在我的脚本中,我尝试这样做:

file_list = glob.glob("*procData.json")


for datafname in file_list:
datafile = json.load(open(datafname))

for i, datapoint in enumerate(datafile['EnvDict']):
song = SongData(datapoint)
song.track.xtradata_rm('\((.*?)\)')
song.releasefetch(lfmapi)
song.dcsearcher(dcapi)
datapoint.update({"album": song.release, "year": song.year})

with open("upd" + datafname, 'w') as output:
json.dump(datafile, output)

但是我得到了这个错误:

Traceback (most recent call last):
song.track.xtradata_rm('\((.*?)\)')
AttributeError: 'str' object has no attribute 'xtradata_rm'

如果我注释掉该行,代码就会运行。

所以我的第一个问题是,总的来说,我必须做什么才能使用 song.track.example_method()song.artist.example_method() 并按预期分别在控制台中打印 track_nameartist_name

我的第二个问题是,我怎样才能对 xtradata_rm 做同样的事情(即 能够执行 song.track.xtradata_rm('\((.*?)\)') 并且基本上插入 song.track 代替 self 在方法中),以及 xtradata_rm 是递归的并试图将实例变量隐式传递给自身内部的自身如何改变事情?

最佳答案

看起来您想将方法 xtradata_rm 添加到 str 对象 self.artistself.track

您对 Python 的误解是不能通过将某些内容分配给变量 self(或任何其他变量)来更改您的对象。 self = 123 没有改变对象,也就是名字 self 后面的对象变成 123,它使名字 self 指向对象 123(并且只在当前范围内执行)。

要真正获得此殊荣,您应该观看演讲 Facts and Myths about Python names and values由 Ned Batchelder 着。

另一件事是 str 对象是不可变的,因此即使名称如您预期的那样工作,您也无法修改 str。比如bytearray是可变的,而str不是,看区别:

In [1]: b = bytearray(b'My example string')

In [2]: id(b)
Out[2]: 4584776792

In [3]: b[3:10] = b'modified'

In [4]: b
Out[4]: bytearray(b'My modified string')

In [5]: id(b) # same object
Out[5]: 4584776792

In [6]: s = 'My example string'

In [7]: s[3:10] = 'modified'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-22fe89ae82a3> in <module>()
----> 1 s[3:10] = 'modified'

TypeError: 'str' object does not support item assignment

In [8]: new_s = s.replace('example', 'modified')

In [9]: id(new_s) # different object
Out[9]: 4584725936

In [10]: id(s)
Out[10]: 4584762296

In [11]: s # original string unmodified
Out[11]: 'My example string'

因此,为了实现您的方法,我们需要为 str 对象创建包装器,它看起来像 str 并且行为像 str,但也实现了您的方法。这可能相当困难,因为许多复杂的原因在 python 中代理对象 is a really involved ordeal .

但不要害怕!在标准库的底层有一个专门为你准备的类(144 lines of boring code):collections.UserString .

我们需要做的就是对其进行子类化并在其上实现您的方法:

class SongAttribute(collections.UserString):
def example_mutate(self):
"""Works UNLIKE other string methods, mutates SongAttribute object,
but I think this is how you want your code to work. Jugging just a bit ;)
Note: actual str object still is immutable and wasn't mutated,
self.data now just references another immutable str object.

P.S.: self.data is the object being proxied by UserString class
"""

self.data = self.data.replace(' ', '_')
return self

def example_return_new(self):
"""Works like all other string metods, returns new string"""
return self.replace(' ', '_')

song = SongAttribute('My Song Name') # creating new song attribute (artist or track)
print(song, type(song)) # it looks like str, but isn't
print(song.upper(), type(song.upper())) # it has all of the str methods, but they return SongAttribute objects, not str objects.

# Return new
print()
new_song = song.example_return_new()
print(new_song, type(new_song)) # we got underscored SongAttribute

# Mutate
print()
print(song, type(song))
print(song.example_mutate(), type(song.example_mutate())) # this method changed song object internally
print(song, type(song)) # and now we still see the changes

输出:

My Song Name <class '__main__.SongAttribute'>
MY SONG NAME <class '__main__.SongAttribute'>

My_Song_Name <class '__main__.SongAttribute'>

My Song Name <class '__main__.SongAttribute'>
My_Song_Name <class '__main__.SongAttribute'>
My_Song_Name <class '__main__.SongAttribute'>

现在您可以在 SongAttribute 上实现您的方法,并将 SongData 构造函数更改为:

def __init__(self, datapoint):
self.artist = SongAttribute(datapoint['artist'])
self.track = SongAttribute(datapoint['name'])

关于Python - 如何将实例变量作为隐式参数一般传递给方法并使用递归方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50875028/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com