2

I'm new to Python and I'm learning about classes and functions and I want to print a class's function but all i get is the error "Class has no attribute"

items.py:

class Item():
    def __init___(self, name, desc, val):
        self.name   = name
        self.desc   = desc
        self.val    = val

    def print_info(self):
        return '{}\n==========\n{}\n\nValue: {}'.format(self.name, self.desc, self.val)

class Gold(Item):
    def __init__(self):
        super().__init__(name = "Gold", desc = "Golden coin.", val = str(5))

main.py:

from items import Item

print(Item.Gold.print_info)

The error is

"AttributeError: type object 'Item' has no attribute 'Gold'"
5
  • that means that the class Item has no method nor variable named Gold ... even if it did ... Gold has no method or variable named print_info Commented Feb 11, 2015 at 18:26
  • Why are you trying to call Item.Gold? Commented Feb 11, 2015 at 18:27
  • Gold is not an attribute of Item so Item.Gold doesn't make much sense. It's a subclass, it's a entirely differnt thing. What are you trying to achieve? Commented Feb 11, 2015 at 18:29
  • You can't use non-static data without instantiating a class, for one Commented Feb 11, 2015 at 18:31
  • A very Common Mistake Is: Using code snippets and having __int__ instead of __init__ as the constructor. Commented Aug 11, 2022 at 5:04

3 Answers 3

2

Gold is not an attribute on the Item class, no. It is a subclass, and a global name in its own right. You can import it from your items module:

>>> from items import Gold
>>> Gold
<class 'items.Gold'>

You cannot create an instance of it, because used the wrong name for the Item.__init__ method:

>>> from items import Item
>>> Item.__init__
<slot wrapper '__init__' of 'object' objects>
>>> Item.__init___
<function Item.__init___ at 0x1067be510>
>>> Item('a', 'b', 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object() takes no parameters

Note that the method you created has three underscores in the name. If you fix that:

class Item():
    def __init__(self, name, desc, val):
        # ^   ^ 2 underscores on both sides
        self.name   = name
        self.desc   = desc
        self.val    = val

you can create instances of the Gold() class:

>>> Gold()
<items.Gold object at 0x1067cfb00>
>>> gold = Gold()
>>> print(gold.print_info())
Gold
==========
Golden coin.

Value: 5

Now, if you really wanted to create attributes on the Item class, you'll have to add those after you created the class:

class Item():
    def __init___(self, name, desc, val):
        self.name   = name
        self.desc   = desc
        self.val    = val

    def print_info(self):
        return '{}\n==========\n{}\n\nValue: {}'.format(self.name, self.desc, self.val)

Item.gold = Item('Gold', 'Golden coin.', 5)

You don't need to create subclasses for that. You could use the enum module here though:

from enum import Enum

class Item(Enum):
    Gold = 'Golden coin.', 5
    Silver = 'Silver coin.', 1

    def __init__(self, desc, val):
        self.desc = desc
        self.val = val

    def print_info(self):
        return '{}\n==========\n{}\n\nValue: {}'.format(self.name, self.desc, self.val)

Here Gold is an attribute of Item:

>>> Item
<enum 'Item'>
>>> Item.Gold
<Item.Gold: ('Golden coin.', 5)>
>>> print(Item.Gold.print_info())
Gold
==========
Golden coin.

Value: 5
>>> Item.Silver
<Item.Silver: ('Silver coin.', 1)>
Sign up to request clarification or add additional context in comments.

Comments

0

Here's what you're doing wrong:

  • Gold is a subclass of Item, not an attribute of it. Your error is popping up when you try to do Item.Gold. Gold is accessed entirely separately.
  • You need to instantiate your classes into objects. Once you instantiate an object, you can call your methods on it and access its attributes. Each object stores methods and attributes independently, so one gold coin can have a different name, description, value, or even print its info differently.
  • When trying to access a parent class from within a subclass, you just reference the class name directly rather than using super().
  • You have an extra underscore in your Item class's __init__()

So with that in mind, your new main.py should look like this:

from items import Gold

mygold = Gold() # This is where we instantiate Gold into an object
print(mygold.print_info()) # We call the method on the object itself

And your items.py will look like this:

class Item():
    def __init__(self, name, desc, val):
        self.name   = name
        self.desc   = desc
        self.val    = val

    def print_info(self):
        return '{}\n==========\n{}\n\nValue: {}'.format(self.name, self.desc, self.val)

class Gold(Item):
    def __init__(self):
        Item.__init__(name = "Gold", desc = "Golden coin.", val = str(5))

1 Comment

This is correct, but I did notice the author did use super(). If this is desired, then all that must be done is for Item to subclass object ie class Item( object ):
0

You can call functions that are in Item from the Gold class but not the other way around. So your main should be:

from items import Gold
print(Gold.print_info)

Please note that if you don't end functions with (), then you'll just get the string representation of the function. But if you do that in your current code it wouldn't work unless you create the object first and then call print_info().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.