Pythonic 的代碼編寫方法

1.模塊導入

你是否是常常對調用模塊時輸入一長串模塊索引感到頭疼?說實在的,數量少的時候或許還能夠勉強忍受,一旦程序規模上去了,這也是一項不容小覷的工程html

#Bad

import urllib.request

url = r'http://www.baidu.com'

req = urllib.request.Request(url)

response = urllib.request.urlopen(req)

#Good

from urllib import request 

url = r'http://www.baidu.com'

req = request.Request(url)

response = request.urlopen(req)

 若是遇到不一樣package中重複的模塊,咱們如何區分呢?,示例以下:python

from module_a import fun as a_fun
from module_b import fun as b_fun

 這樣的方式還適合模塊名比較長的方法,舉例以下:git

from bs4 import BeautifulSoup as BS

html = '''
       <html>
            ......
       </html>
       '''
soup = BS(html)

 

2.關於 "_" ##

這是一個很是有用的功能,惋惜不多人知道。github

當你在交互界面敲代碼,得到一個臨時結果,卻沒有用變量名去保存它的時候,能夠用"_"來獲取最近一次臨時結果。數組

>>> 3*5
15
>>> _
15

在"_"中存儲最後輸出的值。這在交互式模式中是很是有用的,當你在過程當中沒有保存計算結果,或者你想看最後一步執行的輸出結果。安全

3.合併字符串

直接用+ 號比用''.join方法更佔用內存資源閉包

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang


# Bad
string = ['a','b','c','d','e','f','g','h','ss']

def fun(string):
    all_string = ''
    for i in string:
        all_string += i
    return all_string


# Good
string = ['a','b','c','d','e','f','g','h'.'ss']

def fun(string):
    all_string = ''.join(string)
    return all_string

4.強大的zip()

它是Python的內建函數,zip函數接受任意多個(包括0個和1個)序列做爲參數,返回一個包含tuple的list。zip()函數能夠在不少場景簡化你的代碼。app

矩陣的行列互換ide

##bad
>>> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] >>> re_a = [[row[col] for row in a] for col in range(len(a))] >>> re_a [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
##good >>> re_a = list(zip(*a)) >>> re_a [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

交換dict的鍵值函數

##bad
>>> a = {'a':1, 'b':2, 'c':3, 'd':4}
>>> def reve_dict(a):
...     new_dict = {}
...     for k,v in a.items():
...         new_dict[v] = k
...     return new_dict
...     
>>> reve_dict(a)
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
##good
>>> def reve_dict2(a):
...     k = a.keys()
...     v = a.values()
...     new_dict = dict(zip(v,k))
...     return new_dict
...     
>>> reve_dict2(a)
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

 

合併list相鄰項

>>> a = [1, 2, 3, 4, 5, 6]
>>> a[::2]
[1, 3, 5]
>>> a[1::2]
[2, 4, 6]
>>> list(zip(a[::2],a[1::2]))
[(1, 2), (3, 4), (5, 6)]
>>> a = list(zip(a[::2],a[1::2]))
>>> a
[(1, 2), (3, 4), (5, 6)]

5.變量值交換

# Bad
tmp = a
a = b
b = tmp

#Good
a, b = b, a

6.在循環中獲取索引(數組下標)?

>>> a = [8,12,45,33,8]
>>> for index, value in enumerate(a):
...     print(index,value)
...     
0 8
1 12
2 45
3 33
4 8

7.如何在只用一行捕獲多個異常?

try:
    pass
except (ExceptionA,ExceptionB,.....) as e:
    pass

8.把列表分割成一樣大小的塊

>>> a
[8, 12, 45, 33, 8]
>>> list(zip( *[iter(a)]*2))
[(8, 12), (45, 33)]

 

9.如何查找列表中某個元素的下標?

a = ['a', 'b', 'c', 'd', 'e', 'f']

a_i = a.index(a)
>>> 0 

10.如何快速反轉字符串?

##bad

>>> a = 'python reverse method'
>>> list_a = list(a)
>>> list_a.reverse()
>>> re_a = ''.join(list_a)
>>> re_a
'dohtem esrever nohtyp'

##good

>>> a = 'python reverse method'
>>> re_a = a[::-1]
>>> re_a
'dohtem esrever nohtyp'

 

 11. 用with打開文件

平時在使用相似文件的流對象時,使用完畢後要調用close方法關閉。with…as語句提供了一個很是方便的替代方法:open打開文件後將返回的文件流對象賦值給f,而後在with語句塊中使用。with語句塊完畢以後,會隱藏地自動關閉文件。

with open('foo.txt','r') as f:
    f.read()

with 魔法方法內部實現原理:

with語句須要支持上下文管理協議的對象, 上下文管理協議包含 __enter__ 和 __exit__ 兩個方法. with語句創建運行時上下文須要經過這兩個方法執行進入和退出操做.

其中上下文表達式是跟在with以後的表達式, 該表達示返回一個上下文管理對象

知道具體原理, 咱們能夠自定義支持上下文管理協議的類, 類中實現 __enter__ 和 __exit__ 方法

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

class MyWith(object):
    def __init__(self):
        print("__init__ method")
    def __enter__(self):
        print("__enter__ method")
        return self  # 返回對象給as後的變量
    def __exit__(self, exc_type, exc_value, exc_traceback):
        print("__exit__ method")
        if exc_traceback is None:
            print("Exited without Exception")
            return True
        else:
            print("Exited with Exception")
            return False
def test_with():
    with MyWith() as my_with:
        print("running my_with")
    print("------分割線-----")
    with MyWith() as my_with:
        print("running before Exception")
        raise Exception
        print("running after Exception")
if __name__ == '__main__':
    test_with()

 

執行結果以下:

__init__ method
__enter__ method
running my_with
__exit__ method
Exited without Exception
------分割線-----
__init__ method
__enter__ method
running before Exception
__exit__ method
Traceback (most recent call last):
Exited with Exception
  File "/Users/JasonWang/PycharmProject/spider/mywith.py", line 28, in <module>
    test_with()
  File "/Users/JasonWang/PycharmProject/spider/mywith.py", line 25, in test_with
    raise Exception
Exception

 

證實了會先執行 __enter__ 方法, 而後調用with內的邏輯, 最後執行 __exit__ 作退出處理, 而且, 即便出現異常也能正常退出

12.和你的內存說再見

crash = dict(zip(range(10 **0xA), range(10 **0xA)))
##說明
range(10 **0xA)
>>> range(0, 10000000000)
用range()生成,不會拋MemoryError,而後進行壓縮,再轉換成dict,內存很快會消耗乾淨的,電腦就一動不動了......

13.顯示有限的接口到外部

當發佈python第三方package時, 並不但願代碼中全部的函數或者class能夠被外部import, 在__init__.py中添加__all__屬性,
該list中填寫能夠import的類或者函數名, 能夠起到限制的import的做用, 防止外部import其餘函數或者類

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from base import APIBase
from client import Client
from decorator import interface, export, stream
from server import Server
from storage import Storage
from util import (LogFormatter, disable_logging_to_stderr,
                       enable_logging_to_kids, info)
__all__ = ['APIBase', 'Client', 'LogFormatter', 'Server',
           'Storage', 'disable_logging_to_stderr', 'enable_logging_to_kids',
           'export', 'info', 'interface', 'stream']

 14.filter的用法

相對filter而言, map和reduce使用的會更頻繁一些, filter正如其名字, 按照某種規則過濾掉一些元素

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

lst = [1,2,3,4,5]
# 全部奇數都會返回True, 偶數會返回False被過濾掉
f_list =filter(lambda x:x % 2 !=0,lst)

print(list(f_list))

15.一行做判斷

當條件知足時, 返回的爲等號後面的變量, 不然返回else後語句

>>> lst = [4,5,6]
>>> new_l =lst[1] if lst is not None else None
>>> new_l
5

 16.用裝飾器實現單例模式

def singleton(cls):
    instances = dict()
    def _singleton(*args,**kwargs):
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
            return instances[cls]
        return _singleton
@singleton
class Test(object):
    pass


if __name__ == '__main__':
    tt1 = Test()
    tt2 = Test()
    print(tt1,tt2)

 

staticmethod裝飾器

類中兩種經常使用的裝飾, 首先區分一下他們

  • 普通成員函數, 其中第一個隱式參數爲對象
  • classmethod裝飾器, 類方法(給人感受很是相似於OC中的類方法), 其中第一個隱式參數爲
  • staticmethod裝飾器, 沒有任何隱式參數. python中的靜態方法相似與C++中的靜態方法
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang
class A(object):
    # 普通成員函數
    def foo(self, x):
        print("executing foo(%s, %s)" % (self, x))
    @classmethod   # 使用classmethod進行裝飾
    def class_foo(cls, x):
        print("executing class_foo(%s, %s)" % (cls, x))
    @staticmethod  # 使用staticmethod進行裝飾
    def static_foo(x):
        print("executing static_foo(%s)" % x)
def test_three_method():
    obj = A()
    # 直接調用噗通的成員方法
    obj.foo("para")  # 此處obj對象做爲成員函數的隱式參數, 就是self
    obj.class_foo("para")  # 此處類做爲隱式參數被傳入, 就是cls
    A.class_foo("para")  #更直接的類方法調用
    obj.static_foo("para")  # 靜態方法並無任何隱式參數, 可是要經過對象或者類進行調用
    A.static_foo("para")
if __name__ == '__main__':
    test_three_method()

# 函數輸出
# executing foo(<__main__.A object at 0x1029ef278>, para)
# executing class_foo(<class '__main__.A'>, para)
# executing class_foo(<class '__main__.A'>, para)
# executing static_foo(para)
# executing static_foo(para)

property裝飾器

  • 定義私有類屬性

property與裝飾器結合實現屬性私有化(更簡單安全的實現get和set方法)

#python內建函數
property(fget=None, fset=None, fdel=None, doc=None)

fget是獲取屬性的值的函數,fset是設置屬性值的函數,fdel是刪除屬性的函數,doc是一個字符串(like a comment).從實現來看,這些參數都是可選的

property有三個方法getter()setter()delete() 來指定fget, fset和fdel。 這表示如下這行

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

class Student(object):
    @property  #至關於property.getter(score) 或者property(score)
    def score(self):
        return self._score
    @score.setter #至關於score = property.setter(score)
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

 

17.iter魔法

  • 經過yield和__iter__的結合, 咱們能夠把一個對象變成可迭代的
  • 經過__str__的重寫, 能夠直接經過想要的形式打印對象
class MyIter():
    def __init__(self):
        self.lst = [1, 2, 3, 4, 5]
    def read(self):
        for ele in range(len(self.lst)):
            yield ele
    def __iter__(self):
        return self.read()
    def __str__(self):
        return ','.join(map(str, self.lst))

    __repr__ = __str__
def t_iter():
    obj = MyIter()
    for num in obj:
        print(num)
    print(obj)
if __name__ == '__main__':
    t_iter()
##result
0
1
2
3
4
1,2,3,4,5

18.神奇partial

partial使用上很像C++中仿函數(函數對象).

在stackoverflow給出了相似與partial的運行方式

def partial(func, *part_args):
    def wrapper(*extra_args):
        args = list(part_args)
        args.extend(extra_args)
        return func(*args)
    return wrapper

利用用閉包的特性綁定預先綁定一些函數參數, 返回一個可調用的變量, 直到真正的調用執行

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

def partial(func, *part_args):
    def wrapper(*extra_args):
        args = list(part_args)
        args.extend(extra_args)
        return func(*args)
    return wrapper


from functools import partial
def sum(a, b):
    return a + b
def test_partial():
    fun = partial(sum, 2)   # 事先綁定一個參數, fun成爲一個只須要一個參數的可調用變量
    print(fun(3))  # 實現執行的便是sum(2, 3)
if __name__ == '__main__':
    test_partial()
    
##執行結果:
5

 

19.神祕eval,exec

eval我理解爲一種內嵌的python解釋器(這種解釋可能會有誤差), 會解釋字符串爲對應的代碼並執行, 而且將執行結果返回

看一下下面這個例子

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang


def test_first():
    return 3
def test_second(num):
    return num
action = {  # 能夠看作是一個sandbox
        "para": 6,
        "test_first" : test_first,
        "test_second": test_second,
        }
def test_eavl():
    condition = "para == 6 and test_second(test_first()) < 5"
    res = eval(condition, action)  # 解釋condition並根據action對應的動做執行
    print(res)
if __name__ == '__main__':
    test_eavl()
##result
True

exec

  • exec在Python中會忽略返回值, 老是返回None, eval會返回執行代碼或語句的返回值
  • execeval在執行代碼時, 除了返回值其餘行爲都相同
  • 在傳入字符串時, 會使用compile(source, '<string>', mode)編譯字節碼. mode的取值爲execeval
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

def test_first():
    print("hello")
def test_second():
    test_first()
    print("second")
def test_third():
    print("third")
action = {
        "test_second": test_second,
        "test_third": test_third
        }
def test_exec():
    exec("test_second()") in action
if __name__ == '__main__':
    test_exec()  # 沒法看到執行結果
##
hello
second

 

20.getattr

getattr

getattr(object, name[, default])Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, ‘foobar’) is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.

經過string類型的name, 返回對象的name屬性(方法)對應的值, 若是屬性不存在, 則返回默認值, 至關於object.name

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang

# 使用範例
class MyGetAttr(object):
    test = "test attribute"
    def say(self):
        print("test method")
def my_getattr():
    my_test = MyGetAttr()
    try:
        print(getattr(my_test, "test"))
    except AttributeError:
        print("Attribute Error!")
    try:
        getattr(my_test, "say")()
    except AttributeError: # 沒有該屬性, 且沒有指定返回值的狀況下
        print("Method Error!")
if __name__ == '__main__':
    my_getattr()
##
test attribute
test method

命令行處理

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#  Author: Jason Wang
import sys
import optparse
def process_command_line(argv):
    """
    Return a 2-tuple: (settings object, args list).
    `argv` is a list of arguments, or `None` for ``sys.argv[1:]``.
    """
    if argv is None:
        argv = sys.argv[1:]
        print(argv)
    # initialize the parser object:
    parser = optparse.OptionParser(
        formatter=optparse.TitledHelpFormatter(width=78),
        add_help_option=None)
    # define options here:
    parser.add_option(      # customized description; put --help last
        '-h', '--help', action='help',
        help='Show this help message and exit.')
    settings, args = parser.parse_args(argv)
    # check number of arguments, verify values, etc.:
    if args:
        parser.error('program takes no command-line arguments; '
                     '"%s" ignored.' % (args,))
    # further process settings & args if necessary
    return settings, args
def main(argv=None):
    settings, args = process_command_line(argv)
    print('settings:',settings,'arg:',args)
    # application code here, like:
    # run(settings, args)
    return 0        # success
if __name__ == '__main__':
    status = main()
    print(status)
    sys.exit(status)

讀寫csv文件

# 從csv中讀取文件, 基本和傳統文件讀取相似
import csv
with open('data.csv', 'rb') as f:
    reader = csv.reader(f)
    for row in reader:
        print row
# 向csv文件寫入
import csv
with open( 'data.csv', 'wb') as f:
    writer = csv.writer(f)
    writer.writerow(['name', 'address', 'age'])  # 單行寫入
    data = [
            ( 'xiaoming ','china','10'),
            ( 'Lily', 'USA', '12')]
    writer.writerows(data)  # 多行寫入

各類時間形式轉換

只發一張網上的圖, 而後差文檔就行了, 這個是記不住的

字符串格式化

一個很是好用, 不少人又不知道的功能

>>> name = 'Jason'
>>> 'my name is {name}'.format(name=name)
'my name is Jason'
相關文章
相關標籤/搜索