📜 ⬆️ ⬇️

Python interesting and useful. Part 2

In the previous article we looked at several interesting points of the python language, of course, they are not limited to one article, so we will continue.

One comment considered the following code:

SEX = 'Female', 'Male' sex = SEX[True] # -> Male sex = SEX[False] # -> Female 

It works as the logical data type is equivalent to 0 and 1, moreover, at the beginning there was no special type and the values ​​0 and 1 were used. And when it was entered, it was decided to inherit from the whole.
')
 print(int.__subclasses__()) # -> [<class 'bool'>] 

But back to getting the list values, let's say we have the following data:

 books = [["Sherlock Holmes", "Arthur Conan Doyle", 1986, True, 12.51], ["The Lost World", "Arthur Conan Doyle", 2015, False, 5.95], ["The Art of Computer Programming", "Donald E. Knuth ", 2017, True, 190.54] ] 

Of course, referring to values ​​on hard indices is not our way. You can create a constant, for example AUTHOR and specify it, but you can go further:

 TITLE_AUTHOR = slice(0, 2) PRICE_IN_STOCK = slice(3, 5) print(books[0][TITLE_AUTHOR]) print([book for book in books if book[PRICE_IN_STOCK] > [True, 10.0]]) 

We can create a slice object and indicate to it the indexes for which we are interested in. We can even take enough time to write something similar to the last line in this block, which displays books that are in stock and more expensive than 10 whatever. This code will work, since the comparison of lists and tuples occurs lexicographically: first, the first elements are compared, then the second, and so on, that is, any object whose in_stock “field” is false will be smaller than [True, 10.0], since True> False.

Note: Of course, this code should not be used in projects, and it’s better to confine ourselves to getting some values ​​for a slice, sampling is better done in the database, either in Pandas, or as a method of the Book class. You can use namedtuple and write a small module, where to put methods with similar selections.

We have already considered the arguments that can be passed to the function only by key. Recently, while studying the documentation of the bool function , I discovered a postscript:
Changed in version 3.7: x is now a positional-only parameter.
Now PEP 570 is in development, which will open the possibility to set such parameters, this can be useful when the parameter name does not matter, like, bool (), pow (), etc.

The syntax draft looks like this:

 def name(positional_only_parameters, /, positional_or_keyword_parameters, *, keyword_only_parameters): 

Returning to the bool function, which works just like checking in conditions and cycles when you execute code

 if obj: #  while obj: 

Python performs a rather interesting procedure for outputting a boolean value:

  1. If the object implements the __bool __ () method, then the result of calling this method is returned.
  2. Otherwise, it is checked whether the __len __ () method is implemented, if yes, then it is checked that it returns, if it is 0, then the result will be False.
  3. If neither of these methods is implemented, then True is returned.

 class A: pass a = A() print(bool(a)) # -> True 

Integers implement the __bool__ method, standard collections do not implement it, but implement the __len__ method:

 print(dir(int)) # -> ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', ... print(dir(list)) # -> ['__add__', '__class__', '__contains__', ... 

In another comment the “non-standard” behavior of class attributes was given:

 class Example: arr=[] def __init__(self): pass a = Example() b = Example() a.arr.append(1) print(a.arr) # -> [1] print(b.arr) # -> [1] print(Example.arr) # -> [1] 

It is very important to distinguish between the attributes of a class and an object , the attributes of an object are created, SUDDENLY, on an object.
It is important to understand that any fields and methods declared in the class body belong to the class. To create an attribute for an object, you must assign it to an object, in a class method via self or in the program text, through an object variable.

If you get confused, let's disassemble the previous code, two instances of the class are created in it, after which 1 through one of the objects is added to the arr field. But there is no such attribute in the object, the constructor is empty, so python looks for this attribute in the class and finds it, but it is shared by all instances of the class. That this is an attribute of a class can be seen on the last line, since a call on the name of this attribute to the class did not generate any error.

When learning a new language, it is important to understand that each language has its own philosophy, and not all languages ​​should have the keyword static. Sometimes a similar mechanism is provided by other mechanisms.

The clearest idea is that python is not java which illustrates that adding fields to objects and classes is done through ordinary assignment:

 def make_title(self): if self.title == 'Mister': return 'Mr. ' + self.surname class Person: pass john = Person() john.title = 'Mister' john.name = 'John' john.surname = 'Peterson' john.age = 33 Person.make_title = make_title print(john.make_title()) 

General recommendation: do not store mutable types as instances of a class, this is fraught, however, if you know what you are doing, then use this functionality to the fullest, the main thing is to think about everything well first and document it afterwards.

For example, it is very simple to create a class that stores references to all its instances:

 class RememberAll(): instances = [] def __init__(self): self.instances.append(self) a = RememberAll() b = RememberAll() print(RememberAll.instances) #-> [<__main__.RememberAll object at 0x7faa4a5ab7b8>, <__main__.RememberAll object at 0x7faa4a523c88>] 

You can implement a class of a physical object and, when its characteristics change, call methods to recalculate the characteristics of other elements of the system. Either remember all the sliders on the form and when you shift one move the rest automatically. I do not presume to say that such an implementation is always good, but sometimes it can be useful.

Well, since we touched on physics, I want to mention the @ operator. Yes, there is one . It was introduced to multiply matrices, which is the most funny, but, it seems, it is not implemented for any of the standard data types, that is, it was initially introduced only for third-party libraries. But nothing prevents you from adding its support for your data types by implementing the methods __matmul__, __rmatmul__, __imatmul__

 class Person: def __init__(self, name): self.name = name def __matmul__(self, msg): return "@" + self.name + " " + msg john = Person("John") print(john @ "hello") # -> @John hello 

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


All Articles