Python Forum
type object 'man' has no attribute 'centerX'
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
type object 'man' has no attribute 'centerX'
#1
Here is my code:
class man:
    def __init__(self,centerX,centerY):
        Rect(centerX,centerY,40,40,fill='grey',align='bottom')
ok = man(30,10)
man.centerX += 20
But, whenever I run it, I get this error: AttributeError: type object 'man' has no attribute 'centerX'. I also tried "ok.centerX += 20", but that didn't work either. Is there any way I can use centerX to move an object from 'man'?

Also, I just realized this after posting it, it doesn't show indents like this, but I do have indents after 'def __init__' and 'Rect()'
deanhystad write Mar-05-2025, 06:41 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
The error is correct. class man (should be Man) does not have an attribute named "centerX". You should give it one. In fact, as written, your man class doesn't have any attributes other than the __init__() method. It doesn't even have a Rect.

What is man supposed to be? Is it something in pygame? I'm confused because Rect in pygame does not have a fill. Should man be a subclass of Sprite? Is man unrelated to pygame? More information is needed.
Reply
#3
(Mar-05-2025, 06:43 PM)deanhystad Wrote: The error is correct. class man (should be Man) does not have an attribute named "centerX". You should give it one. In fact, as written, your man class doesn't have any attributes other than the __init__() method. It doesn't even have a Rect.

What is man supposed to be? Is it something in pygame? I'm confused because Rect in pygame does not have a fill. Should man be a subclass of Sprite? Is man unrelated to pygame? More information is needed.

I am using CMU CS Academy for things like Rect
Reply
#4
I have no knowledge about what rect is in CMU CS Academy. My best guess is that man is supposed to be a type of rectangle that is 40x40 and grey. That code would look like this:
class Man(Rect):
    def __init__(self, center_x, center_y, color='grey'):
        super().__init__(center_x, center_y, 40, 40, fill=color, align='bottom'
This says that the new class Man is a kind of Rect. When initializing a Man you call super().__init__(args) to initialize the Rect part of Man. If Man needed additional initialization that code would follow the super().__init__ line.

I am assuming that Rect can be initialized by passing x, y, wide, high, fill color and alignment, and that the x, y arguments are the center of the new Rect.

If you can do this with a Rect
a = Rect(10, 10, 40, 40, fill='grey', align='bottom')
a.center_x += 20
You should be able to do this
a = man(10, 10)
a.center_x += 20
I changed centerX to center_x because attribute names should be in snake case (center_x or centerx, not centerX). However, if Rect uses centerX you should use that convention for subclasses of Rect. If centerX and centerY (not center_x, center_y) are really the names of Rect attributes, you have to use thos names for something like "a.centerX += 20".

I changed man to Man because python coding conventions specify pascal case for class names (ClassNames, not classNames or classnames or class_names). You should start learning and using correct coding conventions. It will speed your learning by making it easier for you to read code, most of which is written following said conventions.
Reply
#5
(Mar-06-2025, 04:14 PM)deanhystad Wrote: I have no knowledge about what rect is in CMU CS Academy. My best guess is that man is supposed to be a type of rectangle that is 40x40 and grey. That code would look like this:
class Man(Rect):
    def __init__(self, center_x, center_y, color='grey'):
        super().__init__(center_x, center_y, 40, 40, fill=color, align='bottom'
This says that the new class Man is a kind of Rect. When initializing a Man you call super().__init__(args) to initialize the Rect part of Man. If Man needed additional initialization that code would follow the super().__init__ line.

I am assuming that Rect can be initialized by passing x, y, wide, high, fill color and alignment, and that the x, y arguments are the center of the new Rect.

If you can do this with a Rect
a = Rect(10, 10, 40, 40, fill='grey', align='bottom')
a.center_x += 20
You should be able to do this
a = man(10, 10)
a.center_x += 20
I changed centerX to center_x because attribute names should be in snake case (center_x or centerx, not centerX). However, if Rect uses centerX you should use that convention for subclasses of Rect. If centerX and centerY (not center_x, center_y) are really the names of Rect attributes, you have to use thos names for something like "a.centerX += 20".

I changed man to Man because python coding conventions specify pascal case for class names (ClassNames, not classNames or classnames or class_names). You should start learning and using correct coding conventions. It will speed your learning by making it easier for you to read code, most of which is written following said conventions.

Firstly, I would like to thank you, as it worked exactly like you said it would, but I also wanted to know if there was any way to something like this:

class Man(Rect):
    def __init__(self, center_x, center_y, color='grey'):
        super().__init__(center_x, center_y, 40, 40, fill=color, align='bottom')
    def move():
        if Man.centerX <= 200:
              Man.centerX += 20
ok = Man(0,0)
okB = Man(300,0)
And then, since ok's centerX is smaller than 200, it would move it, but it wouldn't move okB since its centerX is bigger than 200. I'm assuming I would just have to change the "if Man.centerX <= 200" part to something like "if Rect.centerX <= 200", but I'm unsure what I would put there to make it work. What do you think?
Reply
#6
Should be:
    def move(self):
        if self.centerX <= 200:
              self.centerX += 20
When you call ok.move(), python converts the call to Man.move(ok), passing ok as the first argument to move. The convention is to name the first argument in the method "self", and use "self" when you want to reference the object that is calling the method.

So when you call ok.move() the code is really doing this.
if ok.centerX <= 200:
    ok.centerX += 20
since self is really the object "ok".
Reply
#7
(Mar-06-2025, 05:15 PM)deanhystad Wrote: Should be:
    def move(self):
        if self.centerX <= 200:
              self.centerX += 20
When you call ok.move(), python converts the call to Man.move(ok), passing ok as the first argument to move. The convention is to name the first argument in the method "self", and use "self" when you want to reference the object that is calling the method.

So when you call ok.move() the code is really doing this.
if ok.centerX <= 200:
    ok.centerX += 20
since self is really the object "ok".

It did end up working, so I tried to implement it in another thing I had been working on, but it ended up getting an error because I used a custom attribute

class Enemy(Rect):
    def __init__(self,centerX,centerY,speedX,speedY,speed,damage,hp):
        super().__init__(centerX,centerY,20,20,fill='red',border='darkRed')
    def ai(self):
        if self.visible==True:
            if self.centerX >= peter.centerX:
                self.centerX -= self.speedX
            if self.centerX <= peter.centerX:
                self.centerX += self.speedX
            if self.centerY <= peter.centerY:
                self.centerY += self.speedY
            if self.centerY >= peter.centerY:
                self.centerY -= self.speedY
    def angle(self):
        self.speedX = self.speed * math.cos(angleTo(self.centerX,self.centerY,peter.centerX,peter.centerY))
        self.speedY = self.speed * math.sin(angleTo(self.centerX,self.centerY,peter.centerX,peter.centerY))
        if self.speedX < 0:
            self.speedX *= -1
        if self.speedY < 0:
            self.speedY *= -1
base1 = Enemy(50,100,0,0,0.6,1,3)
I got the error because 'Enemy' had no attribute 'speedX', since speedX was previously a custom attribute I was using for the enemy before I put it in a class. Is there any way I can put custom attributes into classes?
deanhystad write Mar-06-2025, 07:40 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#8
Attributes fall into two categories: class attributes and instance attributes.

Class attributes are things associated with the class. You don't need to create an instance of the class to access these attributes. So far, the only class attribute you have created are Man.__init__() and Man.move(). Class variables are the same for all instances of the class.

Instance attributes are associated with an instance of a class. Each instance may have the same instance attribute names, but the values can differ from one instance to another.

Instance attributes are usually created in the __init__() method. In your Man class you only inherited the instance variables created by Rect.__init__(). If you want to "add" an instance attribute, you just need to assign a value to the instance. To give your Enemy instances a "speed" attribute, assign a value to self.speed in the __init__(). May as well give Enemy damage and hp attributes too.
class Enemy(Rect):
    def __init__(self, x, y, speed=0.6, angle=0, damage=1, hp=3):
        super().__init__(x, y, 20, 20, fill='red', border='darkRed')
        self.damage = damage
        self.hp = hp
        self.speed = speed
All instances of Enemy will have damage, hp and speed attributes, but different Enemy objects can have different speed, hp or damage values.

If I understand what you are trying to do with ai (crash an Enemy into peter), the code can be simplified and there is no reason to compute angles. There's also no need to compute speedX and speedY.
    def ai(self, target):
        if not self.visible:
            return
        x = target.centerX - self.centerX
        y = target.centerY - self.centerY
        if x != 0 or y != 0:
            # Convert x, y to a unit vector.
            d = (dx**2 + dy**2)**0.5  # Compute distance from self to target.
            # Move toward target at self.speed
            self.centerX += self.speed * x / d
            self.centerY += self.speed * y / d
If Rect.centerX is an int, this code may not work. The code might complain that you cannot set centerX to a float, or it might round or truncate the value to the nearest int. round(1 + 0.1) == 1, not 1.1. int(1 + 0.9) == 1, not 1.9 or 2.

The reason I use target instead of peter is because classes should not reference variables that are not part of the class. To use your Enemy class I need to create a variable named peter. If I wanted to change the game I was writing to two players, I could not use your enemy class because it is limited to one player, and the player instance needs to be peter. By passing the target as an argument, I can have multiple players, and target different enemies at different players.

Depending on how you use the Enemy objects it might make sense for the Enemy to have a target attribute. This code (I think) creates 3 enemies. Enemy "a" wanders about directionless, doggedly pursued by enemy "b" which in turn is pursued by "c". I cannot test the code as I don't have access to Rect.
class Enemy(Rect):
    def __init__(self, x, y, speed=0.6, damage=1, hp=3, color="red", fill="darkRed"):
        super().__init__(x, y, 20, 20, fill=fill, border=color)
        self.speed = speed
        self.damage = damage
        self.hp = hp
        self.target = None

    def set_target(self, target):
        self.target = target

    def ai(self):
        if not self.visible:
            return
        if self.target is not None:
            # Move toward target
            x = self.target.centerX - self.centerX
            y = self.target.centerY - self.centerY
        else:
            # Randomly wander about
            x = random.random() - 0.5
            y = random.random() - 0.5
        if x != 0 or y != 0:
            d = (x*x + y*y)**0.5
            self.centerX += self.speed * x / d
            self.centerY += self.speed * y / d

a = Enemy(50, 100, speed=5, color="blue", fill="yellow")
b = Enemy(100, 50, speed=2)
b.set_target(a)
c = Enemy(75, 75, speed=1)
c.set_target(a)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  AttributeError: '_tkinter.tkapp' object has no attribute 'username' Konstantin23 4 5,749 Aug-04-2023, 12:41 PM
Last Post: Konstantin23
  Python: AttributeError: 'PageObject' object has no attribute 'extract_images' Melcu54 2 7,089 Jun-18-2023, 07:47 PM
Last Post: Melcu54
  Object attribute behavior different in 2 scripts db042190 1 1,786 Jun-14-2023, 12:37 PM
Last Post: deanhystad
  cx_oracle Error - AttributeError: 'function' object has no attribute 'cursor' birajdarmm 1 4,652 Apr-15-2023, 05:17 PM
Last Post: deanhystad
  Pandas AttributeError: 'DataFrame' object has no attribute 'concat' Sameer33 5 10,126 Feb-17-2023, 06:01 PM
Last Post: Sameer33
  declaring object parameters with type JonWayn 2 1,631 Dec-13-2022, 07:46 PM
Last Post: JonWayn
  WebDriver' object has no attribute 'find_element_by_css_selector rickadams 3 7,784 Sep-19-2022, 06:11 PM
Last Post: Larz60+
  'dict_items' object has no attribute 'sort' Calli 6 7,987 Jul-29-2022, 09:19 PM
Last Post: Gribouillis
  AttributeError: 'numpy.ndarray' object has no attribute 'load' hobbyist 8 10,266 Jul-06-2022, 10:55 AM
Last Post: deanhystad
  AttributeError: 'numpy.int32' object has no attribute 'split' rf_kartal 6 6,775 Jun-24-2022, 08:37 AM
Last Post: Anushka00

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020