Reputation: 29
I'm doing a CSP assignment for school and I was getting a rather confusing error message while I was testing whether the color portion of my code functioned. This is my code:
import turtle
turtle = turtle.Turtle
turtle.color("brown")
And this is the error message
Traceback (most recent call last):
File "/tmp/sessions/1ab7a960b2c10b4b/main.py", line 3, in <module>
turtle.pencolor("brown")
File "/usr/lib/python3.6/turtle.py", line 2257, in pencolor
return self._color(self._pencolor)
AttributeError: 'str' object has no attribute '_color'
It does not make any bit of sense to me, as I am somewhat new to python. Help?
Upvotes: 0
Views: 473
Reputation: 25489
In the first line, you import the turtle
module.
In the second line, assign the Turtle
class from the turtle
module to the name turtle
. This overwrites the value of the name turtle
, so it no longer refers to the module -- it now refers to your Turtle
class.
When you try to do turtle.color
, you try to access the color
function of turtle
, which in this case is your Turtle
class, instead of acting the color
function of the turtle
module, or the color
method of an object of the Turtle
class.
Note that an object of a class is not the same as the class itself.
Calling Turtle.color("brown")
passes "brown"
as the self
argument, but the function expects the self
argument to be an object of the Turtle
class. This is why you see that error.
To fix this, assign a different name to your turtle so that you don't shadow the module. And remember to create an instance of the Turtle
class by calling turtle.Turtle()
, rather than just copying its value.
import turtle
my_turtle = turtle.Turtle() # Create an instance, and assign it to a DIFFERENT name
my_turtle.color("brown") # Call method of that instance
Upvotes: 2
Reputation: 61525
The cause here is a common typographical error, but the error message is interesting enough to be worth an answer. (There might be a duplicate, but I'm not sure how to find it right now.)
turtle.Turtle
is a class, i.e., a type of data, just like int
or str
.
By writing turtle = turtle.Turtle
, we simply give the class another name (and also stop using that name for the module, which can cause other problems), rather than creating an instance. So the code turtle.color("brown")
is trying to call the color
method on the class, instead of the instance.
Instead, we want to create an instance, by calling the class: turtle.Turtle()
. Then we should use a name for that which doesn't cause conflicts. Thus:
import turtle
my_turtle = turtle.Turtle()
my_turtle.color("brown")
Okay, but exactly how did it go wrong from there?
In Python, when the code looks for an attribute on some object (anything that follows the .
), it looks in the object itself first, and then in the class. That's how method calls work normally: the object doesn't actually contain the method, but its class does. When something is found in the object's class instead of the object itself, then more steps are followed to make the method work like an actual method, rather than an ordinary function.
But also in Python, the classes themselves are objects. (That's why they can contain the methods.) So they have their own class (normally, the one named type
), and their own attribute lookup process. The code turtle.color("brown")
first tries to find color
in the class (because that's what turtle
currently names), and finds it (because it's looking directly in the class, and that's where it actually is). Since it was found directly, the method magic doesn't happen.
That means that color
was called like an ordinary function, not like a method. Which means that the string "brown"
is received as self
.
Which means that the code in that method will try to use a string as if it were a Turtle
, which it isn't. Which causes the error we see. "brown"
is a 'str' object
, and it has no attribute '_color'
(neither the string itself, nor the str
class, contains it).
Upvotes: 1