python的30个tips

Improve your Python knowledge and skills Improve your Python knowledge and skills


开始使用 py3+

2020-01-01开始 python 2 官方不再支持

Python 2 is officially not supported as of January 1, 2020.

检查python版本

保证脚本和python解释器的一致

make sure your users are not running your script with an incompatible version


import sys 

if not sys.version_info > (2, 7):
    ...
    # berate your user for running a 10 year
    # python version
elif not sys.version_info >= (3, 5):
    ...
    # Kindly tell your user (s)he needs to upgrade
    # because you're using 3.5 features

使用ipython

ipython不仅是一个增强型(自动补全)的shell

In [1]: mylist = [i for i in range(1, 10)]

In [2]: print(mylist)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]: mylist
Out[3]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

后边加问号, 查看变量信息
In [4]: mylist?
Type:        list
String form: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Length:      9
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items


补全
In [5]: mylist.

            append()  count()   insert()  reverse()
            clear()   extend()  pop()     sort()
            copy()    index()   remove()

还有支持许多内置的命令行命令:

%cd — to change the current working directory

%edit — to open an editor and execute the code you typed in after closing the editor

%env — to show the current environment variables

%pip install [pkgs] — to install packages without leaving the interactive shell

%time and %timeit — to time the execution of Python code

支持 全局的In-list, Out-dict 变量

In and Out are actual objects. You can use the output of the 3rd command by using Out[3]

In [5]: In
Out[5]: ['', 't = "a', 't = "a"', 'In[1]', 'In[2]', 'In']


In [8]: Out
Out[8]: {2: 'a', 7: [1, 2, 3, 4, 5, 6, 7, 8, 9]}

List Comprehensions 列表表达式

[ expression for item in list if conditional ]

#  basic
mylist = [i for i in range(10)]
print(mylist)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


#  do some math:
squares = [x**2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


# call  function
def some_function(a):
 return (a + 5) / 2
 
my_formula = [some_function(i) for i in range(10)]
print(my_formula)
# [2, 3, 3, 4, 4, 5, 5, 6, 6, 7]


# condition filter
filtered = [i for i in range(20) if i%2==0]
print(filtered)
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

查看对象的内存占用

sys.getsizeof()

range function returns a class that only behaves like a list. A range is a lot more memory efficient than using an actual list of numbers.


#  使用 range
import sys
mylist = range(0, 10000)
print(sys.getsizeof(mylist))
# 48

# range function returns a class that only behaves like a list. A range is a
# lot more memory efficient than using an actual list of numbers.

import sys
myreallist = [x for x in range(0, 10000)]
print(sys.getsizeof(myreallist))
# 87632

多个返回值 (超过3个值应该放在(data)类中)

python的函数支持多返回值


def get_user(id):
    # fetch user from database
    # ....
    return name, birthdate
    
name, birthdate = get_user(4)

This is alright for a limited number of return values. But anything past 3 values should be put into a (data) class.

使用数据类 data classes

py3.7+ Python 提供 数据类 data classes

常规类其他替代方法(如返回多个值或字典)相比,它具有多个优点:

  • 减少代码量, a data class requires a minimal amount of code

  • 可以进行比较, 因为实现了 __eq__ , you can compare data classes because __eq__ is implemented for you

  • debugging 的时候可以打印详细的信息, 因为实现了__repr__, you can easily print a data class for debugging because __repr__ is implemented as well

  • 进行了类型hint,减少数据类型bug, data classes require type hints, reduced the chances of bugs



# 传统实现

class RegularCard:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        return (f'{self.__class__.__name__}'
                f'(rank={self.rank!r}, suit={self.suit!r})')

    def __eq__(self, other):
        if other.__class__ is not self.__class__:
            return NotImplemented
        return (self.rank, self.suit) == (other.rank, other.suit)


# 使用数据类 data class

from dataclasses import dataclass

@dataclass
class Card:
    rank: str
    suit: str = "hearts" # 位置参数, 设置默认值


card = Card("Q", "hearts")

print(card == card)
print(card.__eq__(card))

print(card.__repr__())  # Card(rank='Q', suit='hearts') __repr__

更多, python-data-classes

变量交换值


a = 1
b = 2
a, b = b, a
print (a)
# 2
print (b)
# 1


更好的字典合并方法 py3.5+

可以用来进行多个字典的去重


dict1 = { 'a': 1, 'b': 2 }
dict2 = { 'b': 3, 'c': 4 }
merged = { **dict1, **dict2 }
print (merged)
# {'a': 1, 'b': 3, 'c': 4}

把字符串与list的互相转换


# 字符串 -->> list
mystring = "The quick brown fox"
mylist = mystring.split(' ')
print(mylist)
# ['The', 'quick', 'brown', 'fox']

# list -->> 字符串
mylist = ['The', 'quick', 'brown', 'fox']
mystring = " ".join(mylist)
print(mystring)
# 'The quick brown fox'

使用 表情emoji


import emoji
result = emoji.emojize('Python is :thumbs_up:')
print(result)
# 'Python is 👍 '
# You can also reverse this:
result = emoji.demojize('Python is 👍 ')
print(result)
# 'Python is :thumbs up:'


列表切片

a[start:stop:step]


# We can easily create a new list from
# the first two elements of a list:
first_two = [1, 2, 3, 4, 5][0:2]
print(first_two)
# [1, 2]
# And if we use a step value of 2,
# we can skip over every second number
# like this:
steps = [1, 2, 3, 4, 5][0:5:2]
print(steps)
# [1, 3, 5]
# This works on strings too. In Python,
# you can treat a string like a list of
# letters:
mystring = "abcdefdn nimt"[::2]
print(mystring)
# 'aced it'



# 逆序列表和字符串 Reversing strings and lists
revstring = "abcdefg"[::-1]
print(revstring)
# 'gfedcba'
revarray = [1, 2, 3, 4, 5][::-1]
print(revarray)
# [5, 4, 3, 2, 1]

使用set 去重list和字符串


mylist = [1, 1, 2, 3, 4, 5, 5, 5, 6, 6]
print (set(mylist))
# {1, 2, 3, 4, 5, 6}
# And since a string can be treated like a
# list of letters, you can also get the
# unique letters from a string this way:
print (set("aaabbbcccdddeeefff"))
# {'a', 'b', 'c', 'd', 'e', 'f'}

查找可迭代对象中最多的元素 (max(set(iterable), key=iterable.count))

import time

test = [12, 2, 8, 6, 17, 9, 4, 8, 5, 11, 7, 4, 5, 16, 19, 10, 15, 19, 2, 19, 8, 19, 7, 8, 16, 1, 2, 18, 12, 1, 18, 14, 12, 7, 17, 11, 18, 1, 17, 9, 5, 12, 1, 2, 19, 4, 2, 17, 9, 4, 7, 9, 12, 8, 11, 13, 7, 8, 15, 10, 12, 2, 9, 6, 4, 19, 10, 14, 11, 15, 4, 10, 13, 2, 15, 12, 17, 19, 3, 1, 8, 2, 2, 8, 10, 13, 1, 17, 16, 15, 1, 9, 6, 11, 16, 1, 17, 13, 13, 3, 16, 9, 15, 5, 6, 16, 15, 5, 6, 19, 2, 2, 16, 13, 7, 7, 19, 19, 15, 17, 1, 5, 16, 19, 9, 2, 4, 4, 8, 10, 11, 6, 13, 16, 3, 8, 19, 7, 3, 13, 8, 19, 19, 18, 19, 3, 4, 8, 6, 1, 8, 4, 16, 12, 10, 14, 4, 17, 19, 19, 9, 18, 16, 16, 8, 17, 16, 13, 4, 14, 13, 11, 9, 14, 17, 10, 6, 12, 9, 3, 1, 9, 6, 16, 4, 5, 13, 17, 17, 9, 14, 15, 10, 10, 11, 8, 3, 5, 4, 8, 9, 8, 8, 1, 1, 6, 7, 11, 8, 15, 3, 11, 12, 7, 17, 19, 17, 14, 18, 5, 17, 16, 9, 19, 11, 17, 11, 13, 6, 7, 1, 6, 13, 6, 7, 16, 15, 3, 3, 9, 9, 17, 7, 18, 13, 18, 4, 10, 19, 2, 10, 1, 2, 4, 16, 13, 18, 12, 13, 19, 13, 11, 11, 6, 12, 7, 5, 19, 7, 10, 12, 11, 18, 14, 9, 3, 1, 2, 13, 16, 15, 18, 14, 1, 1, 18, 6, 4, 5, 6, 10, 9, 1, 9, 15, 6, 5, 11, 12, 4, 11, 12, 5, 16, 11, 15, 7, 3, 16, 12, 7, 2, 6, 6, 14, 13, 8, 5, 17, 15, 12, 18, 7, 8, 12, 8, 19, 10, 4, 14, 18, 15, 3, 13, 17, 14, 9, 2, 6, 5, 18, 12, 19, 17, 1, 17, 15, 10, 14, 2, 12, 14, 12, 9, 11, 17, 16, 19, 17, 19, 19, 8, 2, 6, 8, 11, 1, 6, 4, 15, 5, 13, 14, 16, 12, 16, 5, 3, 5, 9, 16, 3, 6, 19, 11, 7, 13, 11, 14, 12, 17, 4, 16, 13, 7, 19, 3, 4, 8, 18, 7, 13, 10, 7, 8, 18, 3, 12, 11, 12, 18, 4, 13, 14, 13, 6, 7, 2, 11, 8, 12, 7, 6, 10, 11, 2, 9, 14, 8, 3, 8, 2, 4, 19, 5, 4, 5, 8, 6, 3, 7, 4, 15, 10, 18, 19, 19, 4, 5, 6, 10, 13, 12, 10, 4, 15, 12, 1, 12, 10, 17, 4, 3, 3, 7, 8, 2, 12, 19, 2, 14, 13, 10, 6, 10, 9, 9, 3, 5, 7, 14, 1, 17, 9, 5, 2, 9, 19, 1, 5, 8, 11, 14, 10, 17, 2, 6, 17, 17, 7, 15, 1, 5, 10, 11, 12, 19, 11, 10, 14, 16, 19, 13, 16, 6, 14, 1, 7, 19, 3, 7, 2, 4, 4, 19, 6, 2, 4, 10, 5, 13, 4, 14, 5, 7, 15, 9, 2, 15, 10, 18, 2, 15, 6, 5, 4, 13, 19, 5, 11, 17, 10, 12, 15, 15, 14, 9, 9, 16, 12, 3, 13, 1, 8, 3, 7, 4, 15, 3, 18, 8, 11, 15, 12, 2, 6, 1, 7, 1, 10, 17, 2, 18, 14, 3, 1, 15, 15, 8, 9, 11, 7, 12, 5, 5, 14, 5, 19, 19, 4, 13, 2, 15, 13, 17, 10, 14, 8, 6, 6, 12, 17, 4, 4, 18, 9, 4, 6, 19, 19, 7, 13, 14, 11, 16, 2, 2, 13, 19, 10, 19, 3, 13, 9, 19, 4, 6, 5, 14, 6, 15, 12, 8, 2, 9, 19, 8, 14, 10, 15, 14, 13, 7, 14, 3, 2, 2, 16, 14, 2, 18, 2, 17, 9, 13, 2, 10, 18, 9, 17, 18, 8, 11, 3, 18, 10, 15, 1, 16, 1, 18, 10, 12, 1, 17, 15, 4, 6, 15, 8, 9, 5, 15, 16, 10, 6, 2, 1, 15, 16, 8, 4, 2, 7, 16, 9, 15, 15, 9, 13, 16, 6, 10, 10, 12, 9, 7, 13, 4, 3, 2, 15, 8, 7, 7, 5, 12, 8, 16, 18, 6, 17, 5, 8, 6, 7, 9, 5, 11, 7, 14, 5, 15, 15, 10, 15, 13, 15, 10, 12, 8, 13, 2, 8, 12, 6, 10, 5, 12, 9, 1, 15, 14, 2, 11, 2, 8, 3, 3, 7, 9, 7, 12, 10, 14, 15, 14, 10, 15, 10, 19, 5, 16, 2, 8, 7, 15, 8, 18, 10, 14, 4, 19, 15, 8, 13, 8, 11, 5, 10, 9, 18, 15, 1, 6, 7, 15, 13, 9, 12, 1, 2, 11, 19, 12, 8, 2, 16, 10, 3, 6, 5, 18, 14, 1, 5, 15, 19, 1, 12, 16, 1, 4, 12, 18, 13, 6, 13, 1, 2, 2, 9, 19, 7, 15, 2, 7, 16, 3, 8, 17, 4, 7, 3, 9, 19, 19, 15, 19, 4, 17, 11, 1, 19, 17, 13, 17, 7, 10, 11, 9, 17, 17, 14, 10, 7, 10, 7, 5, 5, 4, 19, 6, 17, 19, 9, 5, 10, 7, 13, 3, 19, 17, 4, 12, 18, 5, 6, 16, 12, 17, 5, 4, 7, 9, 10, 15, 7, 3, 6, 19, 17, 14, 17, 2, 2, 1, 14, 5, 6, 1, 2, 7, 6, 7, 6, 6, 4, 14, 18, 8, 1, 6, 3, 14, 2, 3, 2, 11, 19, 18, 14, 11, 3, 2, 11, 12, 17, 17, 7, 11, 18, 15, 2, 1, 19, 1, 8, 17, 15, 2, 10, 9, 3, 12, 12, 6, 10, 15, 11, 2, 3, 14, 18, 13, 3, 10, 19, 10, 2, 9, 6, 19, 15, 7, 12, 4, 14, 17, 5, 6, 15, 5, 6, 8, 10, 8, 13, 17]
# test = "dasdasdsdddddddasdasdsaddddddd"

start = time.perf_counter()
print(max(set(test), key=test.count))          # 19  0.0003058000000000019
# 去重之后, 速度更快, 减少了无效的操作
print(max(test, key=test.count))               # 19  0.0158793

print(time.perf_counter() - start )    

#  max 返回列表中的最大值,
#  key是用来进行排序的函数,
#  用set 來對列表去重, 减少无效的操作

多行字符串


s1 = """Multi line strings can be put
 between triple quotes. It's not ideal
 when formatting your code though"""

s2 = (
    "Multi line strings can be put",
    "between triple quotes. It's not ideal",
    "when formatting your code though"
)

s3 = "Multi line strings can be put" \
    "between triple quotes. It's not ideal" \
    "when formatting your code though"


查看,元素计数 Counter


from collections import Counter
mylist = [1, 1, 2, 3, 4, 5, 5, 5, 6, 6]
c = Counter(mylist)
c.update({1: 1, 2: 1, 'a': 1})
print(c)  # Counter({1: 3, 5: 3, 2: 2, 6: 2, 3: 1, 4: 1, 'a': 1})
print(c.most_common()) # [(1, 3), (5, 3), (2, 2), (6, 2), (3, 1), (4, 1), ('a', 1)]
# And it works on strings too:
print(Counter("aaaaabbbbbccccc"))
# Counter({'a': 5, 'b': 5, 'c': 5})

文本加颜色


# pip install colorama

from colorama import Fore, Back, Style
print(Fore.RED + 'some red text')
print(Back.GREEN + 'and with a green background')
print(Style.DIM + 'and in dim text')
print(Style.RESET_ALL)
print('back to normal now')


关于日期的使用 ` python-dateutil`

pip3 install python-dateutil

fuzzy parsing of dates from log files and such.

可以高效的解析log日期

from dateutil.parser import parse
logline = 'INFO 2020-01-01T00:00:01 Happy new year, human.'
timestamp = parse(log_line, fuzzy=True)
print(timestamp)
# 2020-01-01 00:00:01


在不能使用常规 datetime 库的时候, 使用 ` python-dateutil`

where the regular Python datetime functionality ends, python-dateutil comes in

整除 Integer division

py2

# Python 2
5 / 2 = 2        #  defaults to an integer division,
5 / 2.0 = 2.5    # , unless one of the operands is a floating-point number 

py3

Python 3
5 / 2 = 2.5     #  defaults to a floating-point division
5 // 2 = 2      #   // operator has become an integer division

使用charde获取字符串的字符编码格式 Charset detection with charde

pip install chardet

https://github.com/chardet/chardet/blob/master/docs/usage.rst


import urllib
from chardet.universaldetector import UniversalDetector

usock = urllib.urlopen('http://yahoo.co.jp/')
detector = UniversalDetector()

for line in usock.readlines():
    detector.feed(line)
    if detector.done: break
    
detector.close()

usock.close()

print(detector.result)

# {'encoding': 'EUC-JP', 'confidence': 0.99}


使用 enum 枚举类型替代数字字面量 直接出现在代码里的数字

提升代码可读性

提升代码正确性

# 避免直接使用 数字字面量
def mark_trip_as_featured(trip):
    """将某个旅程添加到推荐栏目
    """
    if trip.source == 11:
        do_some_thing(trip)
    elif trip.source == 12:
        do_some_other_thing(trip)
    ... 
    return
    
    
# 使用enum
# -*- coding: utf-8 -*-
from enum import IntEnum

class TripSource(IntEnum):
    FROM_WEBSITE = 11
    FROM_IOS_CLIENT = 12


def mark_trip_as_featured(trip):
    if trip.source == TripSource.FROM_WEBSITE:
        do_some_thing(trip)
    elif trip.source == TripSource.FROM_IOS_CLIENT:
        do_some_other_thing(trip)
    ... ...
    return

使用无穷大 float("inf")无穷小 float("-inf")

用來设置一个默认值


# 排序
user = {"tom": 19, "jenny": 13, "jack": None, "andrew": 43}
u = sorted(user, key=lambda item: user.get(item) or float("inf"), reverse=True)
print(u)




# 循环初始值
max_num = float("-inf")

for i in [23, 36, 71, 3]:
    if i > max_num:
        max_num = i

print(max_num)

使用来实现 装饰器


# 1 函数式的装饰器

def delay(func):
    def inner(*option, **kw):
        ...
        ret = func(*option, **kw)
        ...
        return ret
    return inner 

@delay
def foo():
    ...
    
foo()


# 1.5 带参数
import time
import functools


def delay(duration:int, func):
    def inner(*option, **kw):
        ...
        time.sleep(duration)
        ret = func(*option, **kw)
        ...
        return ret
    return inner


def delay_param(duration):
    return functools.partial(delay, duration)
    # 借用partial, 返回带param的 delay装饰器函数


@delay_param(duration=3)
def foo():
    ...

foo()



# 2 类装饰器

class DelayFunc(object):

    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        ...
        ret = self.func(*args, **kwargs)
        ...
        return ret
    

@DelayFunc  # delay(duration=3)(foo)()
def foo():
    ...

foo()


# 2.5 带参数


import time
import functools

class DelayFunc:
    def __init__(self, duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)


def delay_param_cls(duration):
    return functools.partial(DelayFunc, duration)
    # 返回 带固定参数的 DelayFunc类

@delay_param_cls(duration=3)  # delay(duration=3)(foo)()
def foo():
    ...

foo()

Buy me a 肥仔水!