1

I am currently writing some code and have a main class (called "startup") and a secondary class which activates something on being called (called "Ringer"). All I want to do is initiate the Ringer class with Ringer(), and then do some code and when conditions are met, call Ringer.__on(). Same goes for Ringer.__off().

Seems like I am doing something very simple wrong.

Below is some code of what I am trying to achieve... I am getting an Attribute Error with this.

class Ringer:
    def __init__(self):
        print('__init__')
    def __on(self):
        print('turn on')
    def __off(self):
        print('turn off')

class start:
    def __init__(self):
        Ringer() #init something
        Ringer.__on() #call ONLY the on function
        Ringer.__off() #call ONLY the off function


if __name__ == '__main__':
    start()

The output of the above code should be

__init__
turn on
turn off
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
sean mcc
  • 19
  • 1
  • 6
    You are using double-underscores, thus name-mangling your attribute. why are you using two underscores? also, you've instantiated a `Ringer` object then immediately discard it, then try to call methods directly on the class. don't do that – juanpa.arrivillaga Sep 03 '19 at 02:49
  • This almost solved my issue... but now I have a problem of parameter self not being filled... any suggestions? – sean mcc Sep 03 '19 at 02:53
  • I already told you, you are trying to call your instance methods directly on the class. `Ringer.on()`, but `def on(self)` is designed to be an instance method, so `ringer = Ringer(); ringer.on()` You should probably read the [documentation on classes in python](https://docs.python.org/3/tutorial/classes.html) – juanpa.arrivillaga Sep 03 '19 at 02:54
  • Ok thank you very much. This worked :) – sean mcc Sep 03 '19 at 02:56
  • Not exactly a duplicate, but the answers to [this previous question](https://stackoverflow.com/q/1301346/1405065) contain good explanations of one of the main issues here. – Blckknght Sep 03 '19 at 03:30
  • You call `Ringer` to create an instance, not simply to trigger side effects in its `__init__` method. – chepner Jul 20 '21 at 16:18

1 Answers1

0

You use using double underscores in front of attribute names. The result is that the names are mangled. (eg. __on -> _<insert class where __on is defined>__on.)

So, you should be accessing _Ringer__on instead of __on Also, after you create an instance of Ringer, you don't do anything with it.

Instead I recommend binding the instance to an variable:

ringer = Ringer()
ringer._Ringer__on()
ringer._Ringer__off()

So now that we know what the problem is, and how to fix it, a question arises:

Why does python mangle attributes with double underscores?

Well, think of a light switch. And there is a cover on the light switch. Does this prevent you from using it? No! You can still use it, but you have to take off the cover first. The cover is protecting the light switch, not making it private. And as you know, light switches can be dangerous. And the cover protects you! And that's why python name mangles. It's preventing accidental use, not preventing you to access it.

Now, where can this be helpful?

Well, if you have an attribute that you don't want accidental access to, you can name mangle. (eg. an age attribute.)

Example:

class Animal:
    def __init__(self):
        self.__age = 0
        print("My age is:", self.__age)


class Human(Animal):
    def __init__(self):
        Animal.__init__(self)


john = Human()
print(john.__age)  # error!
print(john._Animal__age)  # ok
Alan Bagel
  • 818
  • 5
  • 24