Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define what class contains

Tags:

python

Ok, this might be a very stupid question and it might not be possible, or I am thinking in a twisted way. So, consider this:

class MyClass:
    def __init__(self, x):
        self.x = x
        self.y = self.x ** 2


class MyList:
    def __init__(self, list):
        self.list = list

    def __iter__(self):
        return iter(self.list)

foo = [MyClass(x=1), MyClass(x=2)]
bar = MyList(list=foo)

for i in bar:
    print(i.x, i.y)

Ok, here we have two classes: MyClass is just something very ordinary and nothing special. It has two instance attributes: x and y. MyList, on the other hand, should be a class which defines an iterator which should only contain elements from the first class MyClass!

Then I create two instances of MyClass, put them in a list foo, and use this list to create an instance of MyList (bar).

Now, again, the list passed to MyList should only contain MyClass elements! What I want is Python to be aware of this fact! When I write a loop where I iterate over the contents of bar, I would like that Python knows that the elements in bar are MyClass objects.

A major inconvenience in my program for now is that Python is not aware of this and the autocompletion does not work. In other words: In the loop, when I write i., I would like all the possible arguments to pop up (in this case x and y). Can I define some magic method in Python for MyList which makes Python aware of the contents of this list?

like image 869
HansSnah Avatar asked Jan 23 '16 10:01

HansSnah


People also ask

What does a class contain?

A class contains data field descriptions (or properties, fields, data members, or attributes). These are usually field types and names that will be associated with state variables at program run time; these state variables either belong to the class or specific instances of the class.

How do we define a class?

a class describes the contents of the objects that belong to it: it describes an aggregate of data fields (called instance variables), and defines the operations (called methods). object: an object is an element (or instance) of a class; objects have the behaviors of their class.

What class contains in Java?

A Java class is a single, coherent unit of Java code which belongs together. A Java class may contain a mix of data (variables) and actions (methods).

What does a class contains in C++?

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions (also called member variables and member functions) as its members whose access is governed by the three access specifiers private, protected or public.


2 Answers

If you are using the PyCharm IDE, then you can do this:

for i in bar:
    assert isinstance(i, MyClass)

or this:

for i in bar: # type: MyClass
like image 187
Jacques Supcik Avatar answered Sep 30 '22 15:09

Jacques Supcik


PEP 484

In Python ≥ 3.0, you can use function annotations (PEP 3107) with the type hinting semantics of PEP 0484. Although the latter proposal was only accepted in Python 3.5 and will be provisional until the release of 3.6, it's syntactically backwards compatible to all Python versions supporting PEP 3107, so using type hint annotations in any 3.x version of Python should at least not hurt.[1]

Whether it helps your IDE or interactive interpreter (REPL) to do better autocompletion is up to that IDE or interpreter, and maybe its settings, even for Python ≥ 3.5.

For Python 2, an alternative notation using comments is available, that tools supporting PEP 0484 might or might not respect.

Add the type hints you care about

Let's look how the annotation-based hinting (Python 3.x) would look for your code. (Comment based, Python-2.x-compatible hinting is left as an exercise for the reader.)

To indicate that iterating over MyList instances yields MyClass objects, we hint the return type of __iter__() by appending a -> (Arrow made of a minus and a greater-than sign) after the function definition's colon, followed by the type of the return value. __iter__() itself doesn't return a MyClass, it returns an iterator. To indicate that it shall be an iterator over MyClass, we use the generic Iterator abstract base class from the typing module[2]:

from typing import Iterator

class MyClass:
    # ...

class MyList:
    # ...

    def __iter__(self): -> Iterator[MyClass]
        return iter(self.list)

To be able to hold this promise, self.list must contain only MyClass instances. So let's kindly ask our callers to provide such, by type-hinting the __init__() argument:

from typing import Iterator, Iterable

# ...

class MyList:
    def __init__(self, list: Iterable[MyClass]):
        self.list = list

    def __iter__(self): -> Iterator[MyClass]
        return iter(self.list)

Note that I chose the Iterable generic abstract base class, not the more specific List generic abstract base class (nor Mapping, Sequence, or AbstractSet), as your implementation only relies on iter(...).


[1] except maybe readability when overused. So as Mark writes, "please use type-hints responsibly" if you do use them.

[2] included in Python ≥ 3.5. For lower versions, use the backport installable with pip install typing.

like image 35
das-g Avatar answered Sep 30 '22 15:09

das-g