Determine Which Class Contains

Well, this can be a very stupid question, and it can be impossible, or I think with a twist. So, consider the following:

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(ix, iy) 

Well, 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 that defines an iterator that should contain only elements from the first class MyClass !

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

Now again, the list passed to MyList should contain only MyClass elements! I want Python to know about this! When I write a loop where I repeat the contents of bar , I would like Python to know that the elements in bar are MyClass objects.

The main inconvenience in my program so far is that Python does not know about this, and autocomplete does not work. In other words: in a loop when I write i. , I would like all possible arguments to pop up (in this case x and y ). Can I define any magic method in Python for MyList that makes Python know the contents of this list?

+5
source share
3 answers

PEP 484

In Python & ge; 3.0, you can use function annotations ( PEP 3107 ) with semantics like hinting PEP 0484 . Although the last sentence was accepted only in Python 3.5 and will be conditional until version 3.6 , it is syntactically inverse compatible with all versions of Python that support PEP 3107, so using hint annotations in any version 3.x of Python should at least not hurt . [1]

Does your IDE or Interactive Interpreter (REPL) help improve autocomplete to this IDE or interpreter and, possibly, its settings even for Python & ge; 3.5.

For Python 2, an alternative notation using comments is available that tools supporting PEP 0484 may or may not be respected.

Add the type tips you care about

See how annotations (Python 3.x) will look for your code. (Comment based, Pinton-2.x-compatible hint remains as an exercise for the reader.)

To indicate that iterating over MyList instances gives MyClass objects, we return the return type __iter__() by adding -> (an arrow made of minus sign and a larger sign) after defining the colon function, followed by the return type. __iter__() itself does not return MyClass , it returns an iterator. To indicate that it should be an iterator over MyClass , we use the generic Iterator abstract base class from typing module [2] :

 from typing import Iterator class MyClass: # ... class MyList: # ... def __iter__(self): -> Iterator[MyClass] return iter(self.list) 

To keep this promise, self.list should only contain instances of MyClass . Therefore, let me kindly ask our callers to provide such, by type-hinting argument __init__() :

 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 generic abstract base class Iterable , and not the more specific List generic abstract base class (and Mapping , Sequence or AbstractSet ), since your implementation depends only on iter(...) .


[1] with the possible exception of readability in abuse. So, as Mark writes , “please use a type-type response” if you use them.

[2] is included in Python & ge; 3.5. For lower versions, use the backport installed with pip install typing .

+2
source

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

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

or that:

 for i in bar: # type: MyClass 
+3
source

Python is not aware of any types until you actually run your code. That is, when types are checked and actions based on the type are performed.

During code development, you are looking for the IDE / REPL function. In the standard Python REPL, this kind of search may not be available. In more complex environments, this really happens, and you can see the attributes for this class.

For example, in IPython REPL, I often use it when inside a loop:

 for i in bar: 

I press i. and click tab both ix iy elements. This is because REPL was designed to provide greater introspection in code development.

I am sure the most famous IDEs provide this; Pythons default REPL is quite simplified ( 3.5 has some autocomplete, though !: D) and doesn't offer too much.

+1
source

Source: https://habr.com/ru/post/1241302/


All Articles