Intermediate-python(中)

Posted by 刘知安 on 2019-10-25
文章目录
  1. python 中的可变对象(mutuable)
  2. python slots魔法
  3. python中的collection包
  4. nametuples
  5. 枚举 Enumerate
  6. python 中的自省
  7. Lambda 表达式

python 中的可变对象(mutuable)

  • 在python中,列表是可变对象.每当你将一个变量赋值为另一个可变类型的变量时,对这个数据的任意改动会同时反映到这两个变量上去。新变量只不过是老变量的一个别名而已。

  • 且在函数的参数中,默认参数只会运算一次!

1
2
3
4
5
6
foo=["abc"]
bar=foo
bar+=["666"]

print(bar)
print(foo)
['abc', '666']
['abc', '666']
1
2
3
4
5
6
7
def add_to(num,target=[]):
target.append(num)
return target

print(add_to(1))
print(add_to(2))
print(add_to(3))
[1]
[1, 2]
[1, 2, 3]

上面的定义函数方法是错误的,我们希望每次得到不同的结果

1
2
3
4
5
6
def add_to_2(num,target=None):
# 当传入的target参数为空时,会生成一个新的list
if target is None:
target=[]
target.append(num)
return target
1
2
3
print(add_to_2(1))
print(add_to_2(2))
print(add_to_2(3))
[1]
[2]
[3]

python slots魔法

在python的类,每次生成一个对象,都会生成一个保存类属性的字典__dict__,这样带来的

好处是:

  • 可以动态地增查改删属性。

缺点是:

  • 因为python不能在创建对象时指定分配内存的大小,所以如果创建成千上万个对象,就会消耗很多内存空间。

slots魔法就是可以现式地指定所包含的属性,使用类slots的类对象就不会保存__dict__属性字典。

1
2
3
4
5
6
7
8
9
10
class MyClass1(object):
def __init__(self,name,sex):
self.name=name
self.sex=sex


obj1=MyClass1("andy","male")
obj2=MyClass1("ann","female")
print(obj1.__dict__)
print(obj2.__dict__)
{'name': 'andy', 'sex': 'male'}
{'name': 'ann', 'sex': 'female'}
1
2
3
4
5
6
7
8
9
10
11
12
class MyClass2(object):
__slots__=["name","sex"]
def __init__(self,name,sex):
self.name=name
self.sex=sex


obj3=MyClass2("andy","male")
obj4=MyClass2("ann","female")

print(obj3.__dict__)
print(obj4.__dict__)
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-5-3778b53f416e> in <module>
      8 obj3=MyClass2("andy","male")
      9 obj4=MyClass2("ann","female")
---> 10 print(obj3.__dict__)
     11 print(obj4.__dict__)


AttributeError: 'MyClass2' object has no attribute '__dict__'

python中的collection包

  • defaultdict
1
2
3
4
5
6
7
8
9
10
from collections import defaultdict

fruit_name=[('banana',"香蕉"),('banana',"芭蕉"),('orange',"橘子"),('orange',"柑子"),('orange',"蜜橘")]

fruit_alias=defaultdict(list)

for name_eng,name_cn in fruit_name:
fruit_alias[name_eng].append(name_cn)

print(fruit_alias)
defaultdict(<class 'list'>, {'banana': ['香蕉', '芭蕉'], 'orange': ['橘子', '柑子', '蜜橘']})
1
2
3
import json

print(json.dumps(fruit_alias))
{"banana": ["\u9999\u8549", "\u82ad\u8549"], "orange": ["\u6a58\u5b50", "\u67d1\u5b50", "\u871c\u6a58"]}
  • Counter 计数器
1
2
3
4
5
from collections import Counter

fruit_alias_cnt=Counter(name_eng for name_eng,name_cn in fruit_name)

print(fruit_alias_cnt)
Counter({'orange': 3, 'banana': 2})
  • deque 双端队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from collections import deque

dq=deque()
dq.append(1)
dq.append("2")
dq.append("foo")

print(dq)

print("pop from left")
dq.popleft()
print(dq)

print("pop from right")
dq.pop()
print(dq)

print("append from left")
dq.appendleft(1)
print(dq)

print("append from right")
dq.append("foo")
print(dq)
deque([1, '2', 'foo'])
pop from left
deque(['2', 'foo'])
pop from right
deque(['2'])
append from left
deque([1, '2'])
append from right
deque([1, '2', 'foo'])

我们可以通过设置队列的最大长度,从而自动地从队首弹出和队尾退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
dq2=deque(maxlen=8)

for i in range(8):
dq2.append(i)


print(dq2)

print("Be about to append 8 at right most!\n")
print("After reach max length of the deque, \
the left most element will be poped out automatically!\n")
dq2.append(8)
print(dq2)
deque([0, 1, 2, 3, 4, 5, 6, 7], maxlen=8)
Be about to append 8 at right most!

After reach max length of the deque,       the left most element will be poped out automatically!

deque([1, 2, 3, 4, 5, 6, 7, 8], maxlen=8)

nametuples

nametuple和tuple一样是不可变对象,可以通过下标索引来访问到具体的元素。

而nametuple又有点类似mini型的dict,可以像dict一样访问元素,但是是不可变的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from collections import namedtuple

# 第一个参数是命名元组的名称,类似类的类名; 第二个参数是字段名称
student=namedtuple("Student","name stuNum sex")

andy=student(name="Andy",stuNum="123456",sex="male")
ann=student("Ann","123123","female")

print(andy)

print(ann.stuNum)
print(ann[2])

# 务必记住,nametuple是不可变对象(immutable)
# ann.sex="male" # ERROR!

andy_dict=andy._asdict() # 通过_asdict()将命名元组转化为字典,再改相应属性
andy_dict["stuNum"]=654321
print(andy_dict)
Student(name='Andy', stuNum='123456', sex='male')
123123
female
OrderedDict([('name', 'Andy'), ('stuNum', 654321), ('sex', 'male')])
  • enmu 枚举数据结构

注意的是,这个是在enum包里的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from collections import namedtuple
from enum import Enum

class Species(Enum):
cat=1
dog=2
horse=3

# 但我们并不想关心同一物种的年龄,所以我们可以使用一个别名
kitten = 1 # (幼小的猫咪)
puppy = 2 # (幼小的狗狗)

# 可以用三种方式访问枚举类型的值
print(Species(2))
print(Species["cat"])
print(Species.horse)
print()


Animal=namedtuple("Animal","name age type")

perry=Animal(name="Perry",age=5,type=Species.dog)
kiyomi=Animal(name="Kiyomi",age=4,type=Species.puppy)
hello_kitty=Animal(name="Hello-Kitty",age=7,type=Species.kitten)

assert(perry.type==kiyomi.type)

print(hello_kitty.type)
Species.dog
Species.cat
Species.horse

Species.cat

枚举 Enumerate

这里说的枚举和枚举类型不是一个东西,这里的枚举指的是枚举一个列表或序列。

1
2
for idx,elemnt in enumrate(my_list):
print(idx,element)

1
2
3
4
my_list=["apple","banana","pear"]
# start 指示的是下表从哪个索引开始计算
for idx,ele in enumerate(my_list,start=1):
print(idx,ele)
1 apple
2 banana
3 pear

python 中的自省

  • dir()是Python中自省的最重要的函数之一,列举出当前对象的所有可用方法或当前作用域下的所有变量。

  • inspect模块中也提供了getmembers()函数来获取一个对象的所有成员函数。

1
2
my_list=[1,2,3,"bar","foo"]
print(dir(my_list))
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
1
2
# 不加参数,返回的是当前作用域内所有名字
print(dir())
['Animal', 'Enum', 'In', 'Out', 'Species', '_', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_i', '_i1', '_i10', '_i11', '_i12', '_i13', '_i14', '_i15', '_i16', '_i17', '_i18', '_i19', '_i2', '_i20', '_i21', '_i22', '_i23', '_i24', '_i25', '_i26', '_i27', '_i28', '_i29', '_i3', '_i30', '_i31', '_i32', '_i33', '_i34', '_i35', '_i36', '_i37', '_i4', '_i5', '_i6', '_i7', '_i8', '_i9', '_ih', '_ii', '_iii', '_oh', 'andy', 'andy_dict', 'ann', 'deque', 'dq', 'dq2', 'ele', 'exit', 'get_ipython', 'hello_kitty', 'i', 'idx', 'kiyomi', 'my_list', 'namedtuple', 'perry', 'quit', 'student']
1
2
3
4
5
6
7
8
9
10
11
12
import inspect

class TestClass(object):
def __init__(self,a,b):
self.a=a
self.b=b
def add():
return self.a+self.b

test_case=TestClass(1,2)

print(inspect.getmembers(test_case))
[('__class__', <class '__main__.TestClass'>), ('__delattr__', <method-wrapper '__delattr__' of TestClass object at 0x112940978>), ('__dict__', {'a': 1, 'b': 2}), ('__dir__', <built-in method __dir__ of TestClass object at 0x112940978>), ('__doc__', None), ('__eq__', <method-wrapper '__eq__' of TestClass object at 0x112940978>), ('__format__', <built-in method __format__ of TestClass object at 0x112940978>), ('__ge__', <method-wrapper '__ge__' of TestClass object at 0x112940978>), ('__getattribute__', <method-wrapper '__getattribute__' of TestClass object at 0x112940978>), ('__gt__', <method-wrapper '__gt__' of TestClass object at 0x112940978>), ('__hash__', <method-wrapper '__hash__' of TestClass object at 0x112940978>), ('__init__', <bound method TestClass.__init__ of <__main__.TestClass object at 0x112940978>>), ('__init_subclass__', <built-in method __init_subclass__ of type object at 0x7f98c185c1c8>), ('__le__', <method-wrapper '__le__' of TestClass object at 0x112940978>), ('__lt__', <method-wrapper '__lt__' of TestClass object at 0x112940978>), ('__module__', '__main__'), ('__ne__', <method-wrapper '__ne__' of TestClass object at 0x112940978>), ('__new__', <built-in method __new__ of type object at 0x10dff55e8>), ('__reduce__', <built-in method __reduce__ of TestClass object at 0x112940978>), ('__reduce_ex__', <built-in method __reduce_ex__ of TestClass object at 0x112940978>), ('__repr__', <method-wrapper '__repr__' of TestClass object at 0x112940978>), ('__setattr__', <method-wrapper '__setattr__' of TestClass object at 0x112940978>), ('__sizeof__', <built-in method __sizeof__ of TestClass object at 0x112940978>), ('__str__', <method-wrapper '__str__' of TestClass object at 0x112940978>), ('__subclasshook__', <built-in method __subclasshook__ of type object at 0x7f98c185c1c8>), ('__weakref__', None), ('a', 1), ('add', <bound method TestClass.add of <__main__.TestClass object at 0x112940978>>), ('b', 2)]

Lambda 表达式

lambda表达式是Python中的匿名函数,它是一个callable的对象,原型为:

lambda param : operation(param)

1
2
add=lambda x,y : x+y
print(add(3,4))
7
1
2
3
4
5
# 列表排序 

a = [(1, 2), (4, 1), (9, 10), (13, -3)]
a.sort(key=lambda x:x[1]) # 按照list中每个元素的第二个值进行排序
print(a)
[(13, -3), (4, 1), (1, 2), (9, 10)]
1
2