48 вещей о Python, которые я до недавнего времени не знал (сборник)

48 вещей, которые я до недавнего времени не знал о Python
1) Мы можем динамически устанавливать переменные, используя globals()
a = 4
b = 5
^ это то же самое, что:
globals()['a'] = 4
globals()['b'] = 5
globals()
— это словарь, содержащий все глобальные переменные, и мы можем устанавливать переменные, добавляя пары ключ-значение в него (не делайте этого в производственном коде).
2) re.sub может принимать функции
# replacing vowels with -
import re
x = re.sub('[aeiou]', '-', 'apple')
print(x) # -ppl-
# replacing vowels with UPPERCASE vowels
import re
x = re.sub('[aeiou]', lambda x:x.group().upper(), 'apple')
print(x) # ApplE
^ мы можем передать функцию вместо строки в re.sub
3) Мы можем внедрить CSS в jupyter
import pandas as pd
from IPython.display import HTML
# this function adds some CSS to our dataframe
def upsidedown(df):
html = '''<style>
.dataframe {transform: rotate(180deg)}
</style>''' + df.to_html()
display(HTML(html))
df = pd.DataFrame([
['apple', 4],['orange', 5],['pear', 6],
['pineapple', 7], ['banana', 8],
], columns=['fruit', 'price'])
upsidedown(df)

В функцию upsidedown
вводится CSS, из-за которого наш фрейм данных отображается вверх ногами.
4) Разница между __getattr__ и __getattribute__
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattr__(self, attr):
return f'__getattr__ called: {attr} does not exist'
def __getattribute__(self, attr):
return f'__getattribute__ called {attr}={super().__getattribute__(attr)}'
dog = Dog('rocky', 4)
print(dog.name) # __getattribute__ called name=rocky
print(dog.breed) # __getattr__ called: breed does not exist
__getattribute__
вызывается, когда мы пытаемся получить существующий атрибут.__getattr__
вызывается, когда мы пытаемся получить несуществующий атрибут.
Имхо, это немного странно, но это то, что есть.
5) Отладчик Python
В Python есть встроенный отладчик pdb
, который позволяет нам проверять каждую переменную на каждом этапе. Нам нужны 2 файла .py:
# testfile.py (contains the function we want to debug)
def testfunction():
x = 'apple'
breakpoint()
y = 'orange'
# debug.py (we run this file)
import pdb
import testfile
pdb.run('testfile.testfunction()')
На каждом этапе мы можем использовать команды PDB, например continue
или exist
, или вводить имена переменных, например x
или y
.
6) Учитывание регистра в Python (Python 3.10+)
Это доступно только в Python 3.10 и выше, и мы можем думать об этом как об элегантном блоке if-elif-else.
fruit = 'apple'
match fruit:
case 'apple':
print('apple pie')
case 'orange':
print('orange squash')
case 'pear':
print('pear cake')
# apple pie
7) Мы можем рисовать на Python (программно), используя turtle
import turtle
screen = turtle.getscreen()
x = turtle.Turtle()
for i in range(1000):
x.forward(200)
x.right(115)
turtle
— это встроенный модуль, который позволяет нам рисовать с помощью Python. Выполнение приведённого выше кода рисует цветок:

8) Мы можем скрыть пользовательский ввод в терминале
from getpass import getpass
print('Please enter your password below')
password = getpass() # whatever user types is hidden
print(password)
Что произойдёт, когда мы запустим это и наберём 'apple'
:
Please enter your password below
Password:
apple
Когда мы набираем apple
, всё, что мы набираем, скрыто, как обычный пароль.
9) Переменная __debug__
# python hello.py
print(__debug__) # __debug__ is usually True
# python -O hello.py
print(__debug__) # False
# __debug__ becomes False when we use the -O flag
Когда __debug__
равен False, операторы assert
игнорируются.
10) Мы можем открыть наш браузер с помощью Python
import webbrowser
webbrowser.open_new("https://medium.com")
^ если мы запустим приведённый выше код, medium.com
откроется в вашем браузере.
Примечание — это встроенная программа, и нам не нужно её устанавливать.
11) Дроби в Python
from fractions import Fraction
x = Fraction(1/2)
print(x/3) # 1/6
мы можем представлять дроби, используя объекты Fraction вместо чисел с плавающей запятой (встроено, не нужно устанавливать)
12) Python имеет встроенную медианную функцию
from statistics import median
print(median([3,1,5,2,4])) # 3
^ statistics
— это встроенный модуль, который нам не нужно устанавливать.
13) Мы можем заставить вещи запускаться ПОСЛЕ оператора return в функции
def test():
print('apple')
return 1
print('orange') # this won't ever be printed
^ в типичных функциях НИЧЕГО не происходит после выполнения инструкции return
. Строка print('orange')
никогда не будет выполнена.
def test():
try:
print('apple')
return 1
finally:
print('orange') # this will run even after a return statement
Однако, если мы используем блок try-finally, блок finally выполняется ВСЕГДА. Таким образом, строка print('orange')
появляется ПОСЛЕ оператора return.
14) Мы можем использовать .update() для объединения 2 словарей/наборов
dict1 = {'apple':4, 'orange':5}
dict2 = {'pear': 6}
dict1.update(dict2) # dict1 = {'apple':4, 'orange':5, 'pear':6}
set1 = {'apple', 'orange'}
set2 = {'pear'}
set1.update(set2) #set1 = {'apple', 'orange', 'pear'}
15) int() равно 0, а float() равно 0,0
print(int()) # 0
print(float()) # 0.0
16) Мы можем использовать __code__ для получения информации о функции
def test(a, b, c):
apple = 100
print(test.__code__.co_argcount) # 3
print(test.__code__.co_varnames) # ('a', 'b', 'c', 'apple')
print(test.__code__.co_consts) # (None, 100, 200)
print(test.__code__.co_filename) # /your/filepath/file.py
__code__
позволяет нам получить определённые метаданные о функциях.
17) PYTHONPATH появляется в sys.path
# how to set the PYTHONPATH env variable (use cmd/terminal)
set PYTHONPATH=yourfolder # Windows
export PYTHONPATH=yourfolder # MacOS / Linux etc
# assume we're running this from /your/filepath
import sys
print(sys.path) # ['/your/filepath', '/your/filepath/yourfolder', ... ]
После установки PYTHONPATH он появляется в sys.path
. Это означает, что мы можем запускать файлы /your/filepath/yourfolder
без необходимости записывать их на компакт-диск.
18) Расширение .py не имеет большого значения
# hello.txt
print('hello from hello.txt')
# test.chicken
print('hello from test.chicken')
Расширение .py не имеет значения, если файл содержит действительный код Python. Но, пожалуйста, не делайте этого в производственном коде.
19) Отображение прокси (неизменяемые словари)
Прокси-серверы — это словари, которые нельзя изменить после того, как мы их создадим. Мы используем их, если не хотим, чтобы наши пользователи изменяли их значения.
# defining a mapping proxy
from types import MappingProxyType
mp = MappingProxyType({'apple':4, 'orange':5})
# what happens when we try to reassign a key
from types import MappingProxyType
mp = MappingProxyType({'apple':4, 'orange':5})
mp['apple'] = 10
# Traceback (most recent call last):
# File "some/path/a.py", line 4, in <module>
# mp['apple'] = 10
# ~~^^^^^^^^^
# TypeError: 'mappingproxy' object does not support item assignment
20) __dict__ отличается для классов и объектов
class Dog :
def __init__ ( self, name, age ):
self.name = name
self.age = age
rocky = Dog( 'rocky' , 5 )
# an object's __dict__ is a normal dict
print(type(rocky.__dict__)) # <class 'dict'>
print(rocky.__dict__) # {'name': 'rocky', 'age': 5}
# a class' __dict__ is a mapping proxy (immutable dict)
print(type(Dog.__dict__)) # <class 'mappingproxy'>
print(Dog.__dict__) # {'__module__': '__main__', ...... }
Таким образом, мы не можем редактировать атрибуты класса и т. д. с помощью __dict__
.
21) any() и all()
any ([ True , False , False ]) # True
any ([ False , False , False ]) # False
^ any()
возвращает True, если хотя бы один элемент имеет значение True.
all ([ True , False , False ]) # False
all ([ True , True , True ]) # True
^ all()
возвращает True, если КАЖДЫЙ элемент имеет значение True.
22) divmod()
quotient, remainder = divmod(27, 10)
# quotient = 2, remainder = 7
^ встроенная функция divmod()
делает //
и в то же время %.
27//10
возвращает 2, а 27%10
возвращает 7, поэтому (2,7)
возвращается с divmod(27, 10)
.
23) Мы можем легко проверять переменные, используя f-строки
name = 'rocky'
age = 5
gender = 'm'
print(f'{name=} {age=} {gender=}') # name='rocky' age=5 gender='m'
^ нам просто нужно вставить {varname=}
в f-строку.
24) Мы можем автоматически конвертировать числа с плавающей запятой
print(float.as_integer_ratio(0.5)) # (1, 2)
print(float.as_integer_ratio(0.25)) # (1, 4)
print(float.as_integer_ratio(1.5)) # (3, 2)
Встроенная функция float.as_integer_ratio()
позволяет нам преобразовать число с плавающей запятой в дробь (представленную кортежем).
# but sometimes it behaves funky
print(float.as_integer_ratio(0.1)) # (3602879701896397, 36028797018963968)
25) globals() и local()
# globals() returns a dict containing all global variables
x = 1
print(globals()) # {'__name__': '__main__', '__doc__': None, ..., 'x': 1}
# locals() returns a dict containing all local variables
def test():
x,y = 1,2
print(locals())
test() # {'x': 1, 'y': 2}
26) __import__()
# normal way of importing stuff
import numpy as np
import pandas as pd
# using __import__ (doing the exact same thing as above)
np = __import__('numpy')
pd = __import__('pandas')
27) Положительная/отрицательная бесконечность в Python
a = float('inf') # positive infinity
b = float('-inf') # negative infinity
Положительная бесконечность больше всех остальных чисел, а отрицательная бесконечность меньше всех остальных чисел (обычно).
28) Мы можем использовать pprint для красивой печати
from pprint import pprint # which stands for 'pretty print'
d = {"A":{"apple":1, "orange":2, "pear":3},
"B":{"apple":4, "orange":5, "pear":6},
"C":{"apple":7, "orange":8, "pear":9}}
pprint(d)

29) Мы можем печатать цветной вывод в Python
Сначала нам нужен следующий код pip install colorama
(в cmd/терминал).
from colorama import Fore
print (Fore.RED + "hello world" )
print (Fore.BLUE + "hello world" )
print (Fore.GREEN + "hello world" )

30) Более быстрый способ набрать словарь (иногда)
d1 = {'apple':'pie', 'orange':'juice', 'pear':'cake'} # normal way
d2 = dict(apple='pie', orange='juice', pear='cake') # faster way
31) Мы можем распечатать материал в Python
CURSOR_UP = '\033[1A'
CLEAR = '\x1b[2K'
print('apple')
print('orange')
print('pear')
print((CURSOR_UP + CLEAR)*2, end='') # this unprints 2 lines
print('pineapple')

CURSOR_UP
перемещает наш курсор вверх на 1 строкуCLEAR
очищает всю текущую строкуprint(CURSOR_UP + CLEAR)
вместе печатают 1 строку
32) Частные переменные в объектах не являются частными
class Dog:
def __init__(self, name):
self.__name = name # self.__name is supposed to be private
@property
def name(self):
return self.__name
rocky = Dog('rocky')
print(rocky.__dict__) # {'_Dog__name': 'rocky'}
Мы можем получить доступ к __name
с помощью __dict__
или даже rocky._Dog__name
.
33) Мы можем создавать классы, используя type()
# creating a class normally
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f'Dog({self.name}, {self.age})')
def __init__(self, name, age):
self.name = name
self.age = age
def bark(self):
print(f'Dog({self.name}, {self.age})')
# creating a class using type()
Dog = type('Dog', (), {'__init__':__init__, 'bark':bark})
Когда мы передаём 3 аргумента в type()
, мы можем создать класс:
classname = type(name, bases, dict)
classname
— переменная, представляющая имя класса, например – Dogname
— строка, представляющая имя класса, например.'Dog'
bases
— кортеж, содержащий родительские классы классаdict
— словарь, содержащий атрибуты и методы класса
34) Мы можем использовать китайские иероглифы в качестве переменных
我 = 4
你 = 5
print(我 + 你) # 9
Пожалуйста, не используйте это в производственном коде
35) Символ возврата \b
print('abc\bd') # abd
Вывод символа возврата \b
удаляет один напечатанный символ
36) Символ колокольчика \a
print('\a')
Вывод символа \a
должна издавать колокольный звон. Попробуйте это в CMD/терминале.
37) Классы могут быть декораторами
class add ():
def __init__ ( self, char ):
self.char = char
def __call__ ( self, function ):
def inner ( *args ):
return function(*args) + self.char
return inner
@add( "! " )
def welcome ( name ):
return "hello" + name
print (greet ( "tom" )) # hello tom!
Это возможно благодаря магическому методу __call__
, который определяет, что происходит, когда мы вызываем объект add
.
38) Функции могут иметь переменные и методы
def test():
test.var = 200 # setting a variable
test.func = lambda:300 # setting a method
return 100
print(test()) # 100
print(test.var) # 200
print(test.func()) # 300
Крутая вещь, но, пожалуйста, не используйте это в производственном коде
39) Простой способ выравнивания строк
# using f-strings
print(f'>{"hello":<10}<') # >hello <
print(f'>{"hello":>10}<') # > hello<
print(f'>{"hello":^10}<') # > hello <
# using ljust/rjust/center
print('>' + 'hello'.ljust(10) + '<') # >hello <
print('>' + 'hello'.rjust(10) + '<') # > hello<
print('>' + 'hello'.center(10) + '<') # > hello <
40) Что происходит, когда мы добавляем список к самому себе?
lis = ['apple', 'orange']
lis.append(lis)
print(lis)
# ['apple', 'orange', [...]]
...
называется многоточием и отображается функцией print
при наличии циклических ссылок. ...
также может использоваться в качестве кода-заполнителя.
41) Мы можем запускать строки как код, используя eval()
print ( eval ( '4+5' )) # 9
print ( eval ( '7-3' )) #4
eval ( 'print(12345)' ) #12345
42) round() принимает отрицательные десятичные разряды
# rounding off to nearest 10, 100, 1000 etc
print(round(12345, -1)) # 12340
print(round(12345, -2)) # 12300
print(round(12345, -3)) # 12000
# rounding off to 2 decimal places
print(round(3.14159, 2)) # 3.14
43) Оператор моржа := (Python 3.8+)
# a simple if block
n = 5
if n > 3:
print('n is more than 3')
# doing the exact same thing using the walrus operator :=
if (n := 5) > 3:
print('n is more than 3')
В (n := 5)
:
1. Переменной n присвоено значение 5
2. 5 также возвращается (поэтому его можно использовать для сравнения с 3)
Мы можем использовать оператор walrus, чтобы сохранить одну строку кода.
44) Мы можем собрать много объектов в один и тот же файл
Встроенный модуль pickle
позволяет нам сохранять структуры данных или объекты Python в двоичные файлы. Мы можем сохранить несколько объектов в файл.
# saving a, b & c into test.pckl
a = [1,2,3]
b = [4,5,6]
c = [7,8,9]
import pickle
with open('test.pckl', 'wb') as f:
pickle.dump(a, f) # saving a into test.pckl (1st object)
pickle.dump(b, f) # saving b into test.pckl (2nd object)
pickle.dump(c, f) # saving c into test.pckl (3rd object)
# reading test.pckl to get 3 objects
import pickle
with open('test.pckl', 'rb') as f:
a = pickle.load(f) # a = [1,2,3]
b = pickle.load(f) # b = [4,5,6]
c = pickle.load(f) # c = [7,8,9]
45) Запуск нашего скрипта Python с флагом -O позволяет нам игнорировать некоторые ошибки
м# run.py
assert 1==2
print('hi')
Если мы запускаем python run.py
, assert 1==2
вызывает AssertionError.
Если мы запускаем python -O run.py
, assert 1==2
игнорируется из-за -O
.
46) dict.fromkeys()
Это позволяет нам создать словарь из списка.
fruits = ['apple', 'orange' ,'pear']
# creating dict from fruits
d = dict.fromkeys(fruits) # {'apple':None, 'orange':None, 'pear':None}
^ все значения None
соответствуют значениям None
по умолчанию.
fruits = ['apple', 'orange' ,'pear']
d = dict.fromkeys(fruits, 5) # {'apple':5, 'orange':5, 'pear':5}
^ мы можем сами установить значение по умолчанию, передав другой аргумент в dict.fromkeys
47) Frozensets (Неизменные наборы)
Frozensets — это наборы, которые нельзя изменить после создания.
# basic frozenset creation
fs = frozenset({1,2,3})
# attempting to add stuff results in an error
fs.add(4) # ERROR
Преимущества замороженных наборов:
- Проверка существования чего-либо внутри замороженного набора по-прежнему занимает время O(1)
- Мы можем добавить замороженный набор в другой набор (мы не можем сделать это с наборами).
- Мы можем использовать замороженный набор в качестве ключа словаря (мы не можем сделать это с наборами).
48) Мы можем заставить классы принимать только определённые переменные, используя __slots__
# Dog class can only have 'name' & 'age' attributes
class Dog:
__slots__ = ['name', 'age']
dog = Dog()
dog.name = 'apple' # ok
dog.age = 1 # ok
dog.gender = 'm' # ERROR cus 'gender' is not in __slots__
Заключение
Надеюсь, сегодня вы узнали хоть что-то новое о Python!