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?
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.
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.
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).
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.
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
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With