uz
Feedback
Python etc

Python etc

Kanalga Telegram’da o‘tish

Regular tips about Python and programming in general Owner — @pushtaev The current season is run by @orsinium Tips are appreciated: https://ko-fi.com/pythonetc / https://sobe.ru/na/pythonetc © CC BY-SA 4.0 — mention if repost

Ko'proq ko'rsatish
6 179
Obunachilar
Ma'lumot yo'q24 soatlar
Ma'lumot yo'q7 kunlar
Ma'lumot yo'q30 kunlar
Postlar arxiv
How many ways you know how to convert int to str? Let's try! Note that complications of the same method don't count.
n = 13

n.__str__()     # 1
str(n)          # 2
'{}'.format(n)  # 3
'%i' % n        # 4
f'{n}'          # 5
format(n, 'd')  # 6

from string import Template
Template('$n').substitute(n=n)  # 7

# similar to other methods:
n.__repr__()
repr(n)
str.format('{}', n)
n.__format__('d')
Can you beat it?

types.SimpleNamespace is a way to make a dict with access by attributes:
from types import SimpleNamespace
sn = SimpleNamespace(a=1, b=2)
sn.a
# 1

sn.c
# AttributeError: ...
However, values from SimpleNamespace can't be accessed by getitem anymore because "There should be only one obvious way to do it":
sn['a']
# TypeError: 'types.SimpleNamespace' object is not subscriptable

Module numbers was introduced by PEP-3141 in Python 2.6. It implements the numbers hierarchy, inspired by Scheme:
Number :> Complex :> Real :> Rational :> Integral
They are ABC classes, so they can be used in isinstance checks:
import numbers
isinstance(1, numbers.Integral)
# True

isinstance(1, numbers.Real)
# True

isinstance(1.1, numbers.Integral)
# False
+ int is Integral. + fractions.Fraction is Rational. + float is Real. + complex is Complex (wow!) + decimal.Decimal is Number. In theory, Decimal should be Real but it's not because Decimal doesn't interoperate with float:
Decimal(1) + 1.1
# TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'
The most fun thing about numbers is that it's not supported by mypy.

What you use Python for?
Anonymous voting

Python caches every imported module is sys.modules:
import sys
import typing

sys.modules['typing']
# <module 'typing' from '/usr/local/lib/python3.7/typing.py'>

len(sys.modules)
# 637
You can reload any module with importlib.reload to force it to be executed again. Be careful, though, since every object from the module will be recreated, you can break all isinstance checks and have hard times with debugging it.
old_list = typing.List
old_list is typing.List
# True

importlib.reload(typing)
old_list is typing.List
# False

Everything is an object, including functions, lambdas, and generators:
g = (i for i in [])
def f(): pass

type(g).__mro__  # (generator, object)
type(f).__mro__  # (function, object)
type(lambda:0).__mro__  # (function, object)
Generators have no __dict__ but functions do!
def count(f):
    def w():
        w.calls += 1
        return f()
    # let's store an attribute in the function!
    w.calls = 0
    return w

@count
def f():
    return 'hello'

f()
f()
f.calls
# 2

What are web frameworks you use?
Anonymous voting

Every class is an instance of its metaclass. The default metaclass is type. You can use this knowledge to check if something is a class or is an instance:
class A: pass
isinstance(A, type)   # True
isinstance(A(), type) # False
However, class and instance are both an instance of object!
isinstance(A(), object) # True
isinstance(A, object)   # True
This is because type an instance of object and subclass of object at the same time, and object is an instance of type and has no parent classes.
isinstance(type, object) # True
issubclass(type, object) # True
type(type)      # type
type(object)    # type
type.__mro__    # (type, object)
object.__mro__  # (object,)

There is a built-in function format that basically just calls __format__ method of the passed argument type with passed spec. It is used in str.format as well.
class A:
    def __format__(self, spec):
        return spec

format(A(), 'oh hi mark')
# 'oh hi mark'

'{:oh hi mark}'.format(A())
# 'oh hi mark'

What are static type checkers you actively use?
Anonymous voting

What are static type checkers you ever tried?
Anonymous voting

Today we have 2 polls at once! Both with multiple answers.

Some functional languages, like Elixir, have in the standard library a huge collection of functions to work with lazy enumerables (in Python, we name them iterators). In Python, this role is on itertools. However, itertools is a relatively small collection of such functions, it contains only most important and basic ones (maybe, a bit of junk, but so). The documentation has Itertools Recipes with some useful functions. A few examples:
def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

def prepend(value, iterator):
    "Prepend a single value in front of an iterator"
    # prepend(1, [2, 3, 4]) -> 1 2 3 4
    return chain([value], iterator)

def tail(n, iterable):
    "Return an iterator over the last n items"
    # tail(3, 'ABCDEFG') --> E F G
    return iter(collections.deque(iterable, maxlen=n))

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)
All these examples and much more can be imported from more-itertools third-party library.

Python has NaN float value and it's a rule-breaking thing:
import math

sorted([5.0, math.nan, 10.0, 0.0])
# [5.0, nan, 0.0, 10.0]

3 < math.nan
# False
3 > math.nan
# False

min(3, math.nan)
# 3
min(math.nan, 3)
# nan
Be careful. Use math.isnan to check if a value is NaN.

What is the main editor you use for Python code?
Anonymous voting

Meet the poll Friday! Every week there will be a poll about Python features and tools to see what is popular in the Python world. Share the polls in chats to get more results.

The famous "Zen of Python" was introduced in PEP-20. This is 19 aphorisms authored by Tim Peters. Do import this in the Python interpreter to see them:
>>> import this                                                                 
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
The fun thing is how this module looks like. The original text is encoded by ROT13 algorithm and is decoded on the fly:
s = """Gur Mra bs Clguba, ol Gvz Crgref
...
"""

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print("".join([d.get(c, c) for c in s]))
Some say it violates almost all the principles that it contains.

buttons 👀

ast.literal_eval is a restricted version of eval that evaluates only literals:
ast.literal_eval('[1, True, "three"]')
# [1, True, 'three']

ast.literal_eval('1+2')
# ValueError: malformed node or string: <_ast.BinOp object ...>
This can be used for safely evaluating strings containing Python values from untrusted sources. For example, to support types for environment variables. However, be aware that too large and complex string can crash the interpreter:
>>> import ast
>>> ast.literal_eval('1+1'*1000000)
[1]    32177 segmentation fault  python3

Hamming distance is the number of positions at which the corresponding symbols are different. It's the simplest measure of difference between 2 strings and can be implemented in a few lines:
from itertools import zip_longest

def hamming(left, right):
    return sum(sl != sr for sl, sr in zip_longest(left, right))

hamming('hello', 'hello')
# 0

hamming('hello', 'hallo')
# 1

hamming('hello', 'helol')
# 2