看起来你想添加方法xtradata_rm
to str
物体self.artist
and self.track
.
你对 Python 的误解之一是,不能通过给变量赋值来改变你的对象self
(或任何其他变量)。self = 123
不改变名称后面的对象self
to 123
,它使名字self
指向对象123
(并且仅在当前范围内执行)。
要真正获得这种区别,您应该观看演讲关于 Python 名称和值的事实和神话 https://www.youtube.com/watch?v=_AEJHKGk9ns作者:内德·巴切尔德。
另一件事是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 中代理对象是一次真正的考验 http://code.activestate.com/recipes/496741-object-proxying/.
但不要害怕!在标准库的深处有一个类(144行无聊的代码 https://github.com/python/cpython/blob/e2e7ff0d0378ba44f10a1aae10e4bee957fb44d2/Lib/collections/__init__.py#L1098) 只为你:集合.UserString https://docs.python.org/3.6/library/collections.html#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
Output:
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'])