Python interesting and useful

I’ve been programming in python for several years, however, I recently realized that many useful techniques and interesting moments passed by me, perhaps I’m not the only one, so I decided to list them here, I hope these techniques will be useful to someone at work or encourage them to meet with this language closer.

As in many languages ​​in python 1 is equivalent to True, and 0 is False, that is,

1 == True.

It would seem, and what's wrong with that? However, this has some side effects due to the fact that identical objects must have the same hashes, respectively, you will not be able to cram the key 1 and True into one dictionary.

 >>> a = {1: "one", 0: "zero", True: "true", False: "false"}
# -> {1: 'true', 0: 'false'}

It also allows the following operations:

 >>> print(2 * False + True)
# -> 1

In this example, strings were used as dictionary values, however, I often want to use them as dictionary keys, I was always annoyed that when creating a dictionary using curly brackets, strings should be specified in quotes, I would like to omit them, it is possible if you create dictionary through the dict () constructor.

 >>> {"one": 1, "two": 2, "three": 3} == dict(one=1, two=2, three=3)
# -> True

In addition, using curly brackets creates not only dictionaries, but also sets (set).

 >>> a = {1, 2, 3}

For the union of two sets, for some reason I want to use the + operator, probably because of the method of string concatenation. However, python does not support this operator for sets. But of course, this does not mean that we always have to use functions, the creators approached this issue more systematically and added support for basic operations on sets (and not just unions) to the language and “hung” them on logical operators .


a = {1, 2, 3}
b = {0, 2, 4}
print(a & b)     # -> {2}
print(a | b)     # -> {0, 1, 2, 3, 4}
print(a ^ b)     # -> {0, 1, 3, 4}
print(a - b)     # -> {1, 3}, однако один арифметический# оператор всё же оставили

Continuing the conversation about dictionaries, starting with version 3.7, the language specification ensures that dictionaries preserve the order of insertion of elements, OrderedDict is no longer needed.

www.python.org/downloads/release/python-370
mail.python.org/pipermail/python-dev/2017-December/151283.html


d = dict(zero='Cero', one='Uno', two='Dos', three='Tres', four='Cuatro',
         five='Cinco', six='Seis', seven='Siete', eight='Ocho', night='Nueve')
for index, (key, value) in enumerate(d.items()):
    print(f"{index} is {key} in England and {value} in Spain")

Notice the output string, it starts with the prefix f - this is a special type of string, entered in python 3.6 .

There are three types of strings in the language: normal, indicated by quotes without prefixes, raw \ not processed (raw), in which special characters like \ n are not processed and inserted as text and f-lines themselves.

They were created to simplify the output, python supports a huge number of output methods:


print("result" + str(2))     # Простая конкатенация строк, python не осуществляет# автоматическое приведение всех аргументов к # строковому типу, это остаётся за программистом
print("result", 2)           # print может принимать несколько аргументов через запятую,# в таком случае они будут выводиться через пробел,# вам не нужны преобразовывать выводимые объекты в строку,# в отличие от предыдущего способа
print("result %d" % 2)                 # %-синтаксис, сделан по аналогии с языком C.
print("result %d %.2f" % (2, 2))       # https://docs.python.org/3.4/library/string.html#formatspec
print("result %(name)s" % {"name": 2}) # также разрешено создавать именованные метки
print("{}".format(2))                  # У класса строки есть метод format()# он позволяет опускать тип выводимой переменной
print("{0} {1} {0}".format(1, 2)) # так же можно указать номер переменной и таким образом# вывести её два раза# нумерация начинается с нуля# если число переданных переменных меньше использованных в выводе, будет сгенерированно исключение
print("{} {}".format(2))            # -> IndexError: tuple index out of range
print("{0} {0}".format(2, 3))       # -> 2 2 Однако если передано слишком много переменных# код отработает без ошибокfrom math import pi                 # при таком выводе так же поддерживаются строки формата
print("{:.2f}".format(pi))          # -> 3.14from string import Template         # возможен и такой способ вывода
s = Template("result  $res")        # однако он не получил большого распространения
print(s.substitute(res = [3, 4]))

Now add more f-lines. Any variables from the scope are available in them, you can call functions, get elements by key, in addition, they support format strings.

from math import pi
result = 4
name = "user"
print(f"{name:84s} pi= {pi:.2f}, result={result}, {name[2]}")
# -> user                                                                                 pi= 3.14, result=4, efrom datetime import datetime
print(f"{datetime.now():%Y:%m-%d}")

They are the fastest of all other output methods, so if python3.6 is available to you, it is recommended that you use them.

One of the coolest python chips is that it is not objects and primitives that are packed and unpacked, but parameters and collections.

deffunc(*argv, **kwargs)

However, there is one architectural flaw in the implementation:

  • argv is a tuple, its values ​​cannot be changed, values ​​cannot be added or deleted
  • kwargs - dictionary, changeable, so caching is impossible

The disadvantage, of course, is not big, but it’s still unpleasant that you cannot directly transfer kwargs to a cache based on a dictionary, on the other hand, if you add a list to a tuple, then such a tuple cannot be added to the dictionary either.

Sets are also created on the basis of a hash table, this means that the values ​​must be hashed, besides the set itself is a mutable and non-hash type, there is a special type frozenset - not a mutable set (do not ask me why it is needed).

We discussed the creation of the type frozendict, but so far it has not been added (although at least one application already exists for it - as kwargs). For an immutable dictionary, you have to take the rap on namedtuple . And also for writing and simple classes.

In his student / school years, who wrote cycles to output the values ​​of the array and was furious because of the comma at the end, each time he decided to score or rewrite it to be beautiful, and only in the course of 2-3 did he learn about the join method? Or am I the only one?

One of the unpleasant features of the join method is with strings - it works only with string elements, if the collection has at least one non-string, you have to use a generator expression, which looks too complicated for such a simple task, but there is a way to simplify the output of list values ​​(without parentheses) .


a = list(range(5))
print(" ".join(a))                 # -> TypeError: sequence item 0: expected str instance, int found
print(" ".join(str(i) for i in a)) # -> 0 1 2 3 4
print(*a)                          # -> 0 1 2 3 4

Since the strings are collections too, they can also be “jointed”.


print('-'.join("hello"))             # -> h-e-l-l-o

Consider the line from the previous example.


print(" ".join(str(i) for i in a)) # -> 0 1 2 3 4

The generator expression is passed to the join function without any brackets; parentheses can be omitted to simplify reading the code. Python takes care of expressiveness.


print(sum(i**2for i in range(10))) # -> 285

In addition, parentheses can be omitted when creating tuples:


article = "python", 2018, "LinearLeopard"# объявление кортежа
theme, year, author = "python", 2018, "LinearLeopard"# распаковка кортежа
theme, year, _ = "python", 2018, "LinearLeopard"# слева и справа должно# находиться одинаковое количество# переменных, можно выделить,# что какая-то вам не нужна,# обозначив её через#  подчёркивание
theme, _, _ = "python", 2018, "LinearLeopard"# имена могут повторяться
theme, *, author = "python", 2018, "LinearLeopard"# можно объявить жадный# параметр, который съест# все неподходящие,# разумеется, допустим# только один# жадный оператор

The asterisk can also be used in function declarations, thus it is possible to create parameters that can be specified only by key .

defsortwords(*wordlist, case_sensitive=False):

You can transfer to the function as many parameters as you like without fear that one of them will be perceived as the value of the case_sensitive parameter.

Could be so.

deffunc(first, second, *, kwonly):


Let's take a closer look at how it simply * differs from * args.

deffunc(first, second, *, kwonly=True):
    print(first, second, kwonly)
deffunc2(first, second, *args, kwonly=True):
    print(first, second, *args, kwonly)
func(1)           #-> TypeError: func() missing 1 required positional argument: 'second'
func(1, 2)        #-> 1 2 True
func(1, 2, False) #-> TypeError: func() takes 2 positional arguments but 3 were given# используя * в объявлении вы укажите, что# ваша функция должна быть вызвана с двумя# позиционными параметрами
func(1, 2, kwonly=False) #-> 1 2 False
func2(1, 2, False) #-> 1 2 False True# *args заберёт в себя все позиционные# параметры, то есть вашу функцию может будет# вызывать с неограниченным (>2) числом# параметров


One interesting feature is connected with the default parameters: they are calculated at the stage of the module compilation into bytecode, so it is better not to use variable types there. We declare a function that adds an element to the end of the list, if the second argument is omitted, the function returns a new list that contains only this element.

defadd_to(elem, collection=[]):
    collection.append(elem)
    return collection
a = ["a", "c"]
print(add_to("b", a))           # -> ['a', 'c', 'b']
print(add_to("a"))              # -> ['a']
print(add_to("b"))              # -> ['a', 'b']  Откуда здесь 'a'?

The default values ​​of the f-tion stored in the field __defaults__, you can at any time to find out what is there.


print(add_to.__defaults__) # -> (['a', 'b'],)

Since the default argument (an empty list) was created at the time the program was started and is not recreated every time, we received exactly this behavior.

You can correct this behavior if you make the default value an unchangeable type, and create a list in the function body:

defadd_to(elem, collection=None):
    collection = collection or []
    collection.append(elem)
    return collection

Pay attention to the team


collection = collection or []

it is a shorter (and less understandable, though not for all) analogue


collection = collection if collection else []


Link to the next part

Also popular now: