[Tutor] TypeError: 'str' object is not callable
Mats Wichmann
mats at wichmann.us
Sat May 15 18:16:16 EDT 2021
On 5/15/21 4:05 PM, Alan Gauld via Tutor wrote:
> On 15/05/2021 15:13, me wrote:
>> Hello,
>>
>> I'm on my very first steps with python and I have a problem where I don't see,
>> what's wrong.
>>
>> This is the code:
>> -----<snip>-----------
>> #!/usr/bin/env python3
>> import glob
>>
>> class foo:
>
> This is a *terrible* name for a class. Use a noun that describes
> what it represents! In this case it is a wrapper around a
> string which represents a path.
>
> Not very useful, but at least calling it Path would be
> more descriptive.
>
>
>> def __init__(self, path):
>> self.path = path
>> def path(self):
>> return self.path
>
> The issue here is the order on which the code is executed.
> When you first run the code the class definition is executed which
> defines a method called self.path and another called self.__init__.
>
> When you create a new instance of the class self.init is executed.
> What it does is create a new binding of self.path to the string
> variable path. The old binding to the method is now lost.
>
>> def main():
>> hs = []
>> drives = glob.glob('/dev/sd?')
>> for d in drives:
>> print(d)
>> hs.append(foo(d))
>
> Each instance of foo overwrites the method with the string d.
>
>> for e in hs:
>> print(e.path())
>>
>>
>
> So now, when you call e.path() you are trying to call the string.
>
> A simple solution to this is to use a different name for
> the attribute path. A common trick is to put an underscore
> in front:
>
> def __init__(self.path):
> self._path = path
>
> def path(self):
> return self._path
>
> A more general option is to use an article prefix such as 'the':
>
> def __init__(self.path):
> self.thePath = path
>
> def path(self):
> return self.thePath
Or, since it's Python, which doesn't _force_ you to use getters and
setters, just dispense with the method entirely and access the path
attribute directly. So this should work:
import glob
class foo:
def __init__(self, path):
self.path = path
def main():
hs = []
drives = glob.glob('/dev/sd?')
for d in drives:
print(d)
hs.append(foo(d))
for e in hs:
print(e.path)
if __name__ == '__main__':
main()
(note for future learnings: there's a standard library module called
pathlib which is designed to work with paths, might end up being useful
someday rather than rolling your own - I realize this one is just a
learning exercise)
More information about the Tutor
mailing list