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)
48 вещей о Python, которые я до недавнего времени не знал (сборник)

В функцию 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. Выполнение приведённого выше кода рисует цветок:

48 вещей о 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)
48 вещей о Python, которые я до недавнего времени не знал (сборник)

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" )
48 вещей о Python, которые я до недавнего времени не знал (сборник)

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')
48 вещей о Python, которые я до недавнего времени не знал (сборник)
  • 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— переменная, представляющая имя класса, например – Dog
  • name— строка, представляющая имя класса, например.'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.pyassert 1==2 вызывает AssertionError.

Если мы запускаем python -O run.pyassert 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!

+1
1
+1
2
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *