Search⌘ K
AI Features

Different Method Types

Explore different method types in Python, including public, protected, and private conventions, and understand their implications in PyTorch class design. Learn how to use the setattr function to dynamically add methods to classes and instances, enhancing your code management while recognizing the risks and appropriate use cases.

Different types of methods

In the last lesson, we introduced the methods _make_train_step and _make_val_step and noticed these methods having an underscore as a prefix. Why is this so and how is this different from the double underscore in the __init__ method?"

Let us take a look at why this is the case.

Public, protected, and private methods

Some programming languages like Java have three kinds of methods: public, protected, and private.

Public methods are the kind you are most familiar with; they can be called by the user.

Protected methods, on the other hand, should not be called by the user. They are supposed to be called either internally or by the child class (the child class can call a protected method from its parent class).

Finally, private methods are supposed to be called exclusively internally. They should be invisible even to a child class.

These rules are strictly enforced in Java, but Python takes a more relaxed approach; all methods are public. Meaning, you can call whatever method you want. But you can suggest the appropriate usage by prefixing the method name with a single underscore (for protected methods) or a double underscore (for private methods). This way, the user is aware of the programmer’s intention.

In our example, both _make_train_step and _make_val_step are defined as protected methods. It is expected by us for users to not call them directly, but if someone decides to define a class that inherits from StepByStep, they should feel entitled to do so.

To make the additions to our code visually simpler, that is, without having to replicate the full class every time a new method is introduced, I am resorting to something that should not be used in regular circumstances: setattr.

Python 3.5
# ATTENTION! Using SETATTR for educational purposes only :-)
setattr(StepByStep, '_make_train_step', _make_train_step)
setattr(StepByStep, '_make_val_step', _make_val_step)

What is setattr?

The setattr function sets the value of the specified attribute of a given object. But methods are also attributes, so we can use this function to “attach” a method to an existing class and all its existing instances in one go!

Yes, this is a hack! No, you should not use it in your regular code! Using setattr to build a class by appending methods to it incrementally serves educational purposes only.

To illustrate how it works and why it may be dangerous, a small example will be presented to you. Let us create a simple Dog class, which takes only the dog’s name as an argument:

Python 3.5
class Dog(object):
def __init__(self, name):
self.name = name

Next, let us instantiate our class; that is, we are creating a dog. Let us call it Rex. Its name is going to be stored in the name attribute:

Python 3.5
class Dog(object):
def __init__(self, name):
self.name = name
rex = Dog('Rex')
print(rex.name)

Then, let us create a bark function that takes an instance of Dog as an argument, and call this function to make Rex bark:

Python 3.5
def bark(dog):
print('{} barks: "Woof!"'.format(dog.name))
bark(rex)

But that is not what we want. We want our dogs to be able to bark out-of-the-box! So we will use setattr to give dogs the ability to bark. There is one thing we need to change though, and that is the function’s argument. Since we want the bark function to be a method of the Dog class itself, the argument needs to be the method’s own instance: self.

Python 3.5
def bark(self):
print('{} barks: "Woof!"'.format(self.name))
setattr(Dog, 'bark', bark)

Does it work? Let us create a new dog:

Python 3.5
def bark(self):
print('{} barks: "Woof!"'.format(self.name))
setattr(Dog, 'bark', bark)
fido = Dog('Fido')
fido.bark()

Of course, it works! Not only can new dogs bark now, but all dogs can bark:

Python 3.5
def bark(self):
print('{} barks: "Woof!"'.format(self.name))
setattr(Dog, 'bark', bark)
rex = Dog('Rex')
rex.bark()

See? We effectively modified the underlying Dog class and all its instances at once! It looks very cool, sure. And it can wreak havoc too.

Using setattr is a hack. We cannot stress this enough! Please do not use setattr in your regular code.

Instead of creating an attribute or method directly in the class, as we have been doing so far, it is possible to use setattr to create them dynamically. In our StepByStep class, the last two lines of code created two methods in the class, each having the same name of the function used to create the method.

Okay, but there are still some parts missing in order to perform model training. Let us keep adding more methods.