1

I'm new to OOP and python and I was just wondering if what I'm doing is "allowed" in OOP and if what I'm doing has a name to it. I have a Queue class

all_postcodes = Queue(). The queue class has a method size to see how many elements are in it.

class Queue:
    def __init__(self):
        self.__items=[]

    def size(self):
        return len(self.__items)

I also have another class that accepts a Queue instance.

class something:
    def __init__(self,postcode):
        self.postcode = postcode
        self._original_matrix = numpy.zeros((self.postcode.size(), self.postcode.size()))) 

I am then calling the something class like this:

all_postcodes_matrix = something(all_postcodes)

Are you allowed to have instances from one class as an argument in another and use it's methods? If you are, is there a name to what I'm doing?

Drise
  • 4,310
  • 5
  • 41
  • 66
Uchoud1
  • 15
  • 2
  • 3
    Yes, this is allowed—in fact, in a sense it's the entire point of OO, being able to create objects that offer some kind of consistent behavior and state in the same way builtin values do. – abarnert Mar 28 '18 at 17:38
  • 1
    However, you probably don't want to use `__items` here. That mangles the name so it's slightly harder to access from outside the class, which is mostly used just for avoiding accidental collisions between a class's private attributes and those of its subclasses and superclasses. – abarnert Mar 28 '18 at 17:40
  • It is alright. It is called composition. – matusko Mar 28 '18 at 17:42
  • 2
    You should implement the magic method `__len__` instead of `size`. – Daniel Mar 28 '18 at 17:43
  • See this [very good explanation](https://stackoverflow.com/a/6581949/9209546) of how both classes and class instances are "first class objects" in Python. They can be passed around quite freely. This may even be a valid dup. – jpp Mar 28 '18 at 17:43

2 Answers2

4

This is not only allowed, it's basically the main reason you want to use OO in the first place: to design a new type, Queue, that acts like a builtin type.

Consider int. An int has some internal state that you don't know about—or care about.1 What you care about is that in some way, it represents an integer value, and it provides operations that make sense for that representation. If you add the ints 2 and 3 and print the result, you get the output 5.

That's exactly what you've done with Queue. As far as the outside world is interested, it's representing a queue of items in some way they neither know nor care about, so long as it provides operations that consistently make sense, like your size.

So, now a something can use a Queue instance as one of its attributes, exactly the same way it uses an int.


The only quibble is that you probably want to use _items instead of __items for your private list. In Python, both are "private by convention", but __items goes farther and mangles the name to make it slightly harder to use from outside. This isn't useful for protection, but it is useful for avoiding accidental collisions, especially cases where a subclass or superclass accidentally uses the same name. So, by using __items, you're signaling that you expect Queue to be part of an inheritance hierarchy, with subclasses written by people who don't know how a Queue is implemented. If that isn't true, it's better not to signal it.


1. In CPython, it's a linked list of 30-bit int32 digits, with the first one signed and the rest unsigned. See, I told you that you didn't know or care about it.

abarnert
  • 354,177
  • 51
  • 601
  • 671
0

You could make use of Python's magic methods, particularly __len__.You can call len() directly on your class instance with this magic method.

class Queue:

    def __init__(self):
        self._items = []

    def __len__(self):
        return len(self._items)


if __name__ == '__main__':
    queue = Queue()
    print(len(queue))
Luke
  • 744
  • 2
  • 7
  • 23