前话: python简单易用,库多就是这么强大,笔者也长期使用过java、c、c++等语言,嗯不多说,最后选择了python! 但其实很多python程序猿都是其他语言转过来的,而且python兼容性也很高,所以比如java程序猿在写python的时候总能感觉到一股浓浓的java味,一个字:尬,两个字:尴尬!因此本文就是简单的通过介绍python数据模型和各种实用的小技巧来体现一下:PYTHONIC ,感受一下python语言的美妙之处,如果想更多了解python语言的风格,强烈推荐:流畅的Python
一、python数据模型
python数据模型是对python框架的描述,也就是说它规范了python这门语言自身构建模块的接口,这些自带模块中就含有一些 特殊方法 ,在python框架下写程序,当python解释器碰到一些特殊的句法时,便会调用这些 特殊方法 去执行对象操作,这些特殊方法总结了一下几个特点:
1、特殊方法的存在是为了被解释器调用的,自己并不需要调用他们
2、大多数特殊方法的调用都是隐式的,但如__init__() 便显示调用超类的构造器
3、调用特殊方法执行速度上很快,因为是在内置模块中的
4、通过实现特殊方法,自定义数据类型可以表现的跟内置类型一样
下面我们便通过实现特殊方法,自定义数据对象,来感受一下PYTHONIC
import collections
Card = collections.namedtuple('Card' , ['rank' , 'suit' ])
class FrenchDeck :
ranks = [str(n) for n in range(2 , 11 )] + list('JQKA' )
suits = 'spades diamonds clubs hearts' .split()
def __init__ (self) :
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__ (self) :
return len(self._cards)
def __getitem__ (self, position) :
return self._cards[position]
上述代码中首先用collections.namedtuple()常见了一个的纸牌对象, 并定义了FrenchDeck类,类中实现了python的特殊方法: __len__()、__getitem__()方法, 由于特殊方法__len__()定义我们可以直接对FrenchDeck对象进行len()操作,同时__getimtem__()方法把 [] 操作交给了self._cards列表, 我们可以直接把FrenchDeck对象当做list进行操作,可以直接根据索引取值,而且可以进行list的切片操作,演示如下:
deck = FrenchDeck()
print (len(deck)) #52
deck[0 ] #Card(rank='2' , suit='spades' )
deck[1 :3 ] #[Card(rank='3' , suit='spades' ), Card(rank='4' , suit='spades' )]
from random import choice
choice (deck) #随机对deck对象进行选择
简而言之, python中含有很多特殊方法,可以方便的实现且快速的实现特定功能,同时我们也可以在定义的数据类型中去实现特殊方法,这样自定义数据类型就可以表现的和python内置类型一样,写出更具有python风格的代码,下面通过一些python中实用技巧再看一下python的独到之处
二、python各种使用小技巧
1、python一行代码定义list
利用python的列表推导式, 可通过一行代码定义list
numbers = [1 , 2 , 3 , 4 , 5 , 6 ]
list1 = [n * 2 for n in numbers]
list2 = [n**2 for n in numbers]
2、字典推导式
字典推导式类似于列表推导式,在用于字典key、value翻转时十分方便
sample = ['a' , 'b' , 'c' , 'd' , 'e' ]
s_dict = {key:value for value ,key in enumerate(sample)}
print(s_dict) #{'d' : 3 , 'a' : 0 , 'b' : 1 , 'e' : 4 , 'c' : 2 }
inversed_sdict = {value :key for key,value in s_dict.items()}
print(inversed_sdict) #{0 : 'a' , 1 : 'b' , 2 : 'c' , 3 : 'd' , 4 : 'e' }
3、python中两个变量值交换
看下面,一行代码,无需构建中间变量,可以说是相当方便了
a , b = 1 , 2
a , b = b, a
print('a=%d, b=%d' %(a , b))
4、lambda创建匿名函数
python中构建函数可以不适用函数定义,直接如下一条语句定义一次性匿名函数
double = lambda x: x*2
double (5 ) #10
5、map操作和filter操作
map操作和filter操作可以结合lambda函数一起使用,利用简单的实现一些高效的操作
(1)、map(func, s): 对集合s中每个元素执行func函数操作;
(2)、filter(func, s): 筛选集合s中满足func函数定义的元素
seq = [1 , 2 , 3 , 4 , 5 ]
print (list (map(lambda x:x*2 , seq)))
print (list (filter(lambda x:x>2 , seq)))
6、python中join操作
join操作可以有效的实现字符串的拼接操作
a = ['my ', 'name ', 'is ', 'CHEONG ]
print(' '.join(a)) #my name is CHEONG
b = [1 , 2 , 3 , 4 , 5 , 6 ]
print(''.join(str(ele) for ele in b)) #123456
7、操作符链式调用、函数链式调用
(1) 操作符链式调用
num = 5
if 7 > num > 4 :
print('链式比较操作符' )
(2) 函数链式调用
class Person :
def name (self, name) :
self.name = name
return self
def age (self, age) :
self.age = age
return self
def show (self) :
print("My name is" , self.name, "and I am" , self.age, "years old." )
p = Person()
p.name("CHEONG" ).age(8 ).show()
8、字符串和list倒转
直接使用list切片操作,超简单,当然也可以使用reversed() 函数
s = 'abcdef'
print(s[::-1 ])
a = [5 , 4 , 3 , 2 , 1 ]
print(a [::-1 ])
num = 123456789
print(int(str(num )[::-1 ]))
9、按value值排序字典
sorted()函数、items()函数、lambda()函数综合使用
sample = ['C' , 'H' , 'E' , 'O' , 'N' , 'G' ]
s_dict = {key:value for value,key in enumerate(sample)}
print (s_dict) #{'O' : 3 , 'E' : 2 , 'H' : 1 , 'C' : 0 , 'N' : 4 , 'G' : 5 }
sort_sdict = sorted(s_dict.items(), key = lambda x:x[1 ])
print (sort_sdict) #[('C' , 0 ), ('H' , 1 ), ('E' , 2 ), ('O' , 3 ), ('N' , 4 ), ('G' , 5 )]
10、list中最大和最小值索引
有时候我们对list元素不感兴趣,而对list元素的索引十分感兴趣,,此时便排上用场
lst = [4 , 1 , 2 , 3 , 5 ]
min_idx = min (range(len (lst)), key=lst.__getitem__)
max_idx = max (range(len (lst)), key=lst.__getitem__)
print(min_idx)
print(max_idx)
11、list赋值技巧以及深拷贝浅拷贝
python中list对象lst1=lst2,其中对象lst1指向的是lst2的对象所在指针,在内存中lst1、lst2指向的是同一块内存,所以有时候使用浅拷贝还是深拷贝要注意
(1) list赋值技巧
lst1 = [1, 2, 3, 4]
lst2 = lst1
lst2[2] = 4
print(lst1)
注意到上面修改lst2,则lst1也相应发生了变化,如果想要lst2指向另一个内存空间,用下面操作
lst1 = [1, 2, 3, 4]
lst2 = list(a)
lst2[2] = 4
print(lst1)
lst1 = [1, 2, 3, 4]
lst2 = lst1[:]
lst2[2] = 4
print(lst1)
(2) python中浅拷贝和深拷贝
python中的浅拷贝copy()函数,b浅拷贝a后则b、a指向同一个内存空间; 但python中copy模块有深拷贝函数deepcopy()函数,当b深拷贝a后,则b、a指向不同的内存空间
import copy
a = {1 :[1 , 2 , 3 ], 2 :[1 , 2 , 3 , 4 ]}
b = a .copy()
a [1 ].append(4 )
print(a )
print(b)
c = copy.deepcopy(a )
a [1 ].append(5 )
print(a )
print(b)
print(c)
12、collections集合模块
(1) collections.namedtuple定义简单对象
from collections import namedtuple
Point = namedtuple('Point' , ['x' , 'y' ])
p = Point(1 , 2 )
print(p.x, p.y)
(2) collections.Counter代替字典进行统计
from collections import Counter
c = Counter()
lst = [1 , 1 , 2 , 2 , 2 , 3 , 4 , 5 , 5 ]
for ele in lst:
c[ele] += 1
print(dict(c))
(3) collections.deque双向列表
python中列表list按照索引访问元素速度快,但是插入和删除就很慢了,因此可以使用collections.deque实现快速的插入和删除,并且collections.deque提供了从序列头部插入和删除
from collections import deque
q = deque(['a' , 'b' , 'c' ])
q.append ('d' )
print (q) #deque(['a' , 'b' , 'c' , 'd' ])
q.appendleft('x' )
print (q) #deque(['x' , 'a' , 'b' , 'c' , 'd' ])
q.pop()
print (q) #deque(['x' , 'a' , 'b' , 'c' ])
q.popleft()
print (q) #deque(['a' , 'b' , 'c' ])
后话: 本文自然只是列举了部分常用的显示PYTHONIC风格的实用技巧,想了解更多多看看流畅的Python ,绝对良心书籍! 欢迎大家交流分享!