Open kagxin opened 5 years ago
In [8]: d = {'k1':[1], 'k2':3}
In [9]: d2 = d.copy()
In [10]: d
Out[10]: {'k1': [1], 'k2': 3}
In [11]: id(d)
Out[11]: 77209112L
In [12]: id(d2)
Out[12]: 94994504L
In [13]: d['k1'].append(2)
In [14]: d2
Out[14]: {'k1': [1, 2], 'k2': 3}
In [15]: d3 = copy.deepcopy(d)
In [16]: d3
Out[16]: {'k1': [1, 2], 'k2': 3}
In [17]: d['k1'].append(3)
In [18]: d
Out[18]: {'k1': [1, 2, 3], 'k2': 3}
In [19]: d2
Out[19]: {'k1': [1, 2, 3], 'k2': 3}
In [20]: d3
Out[20]: {'k1': [1, 2], 'k2': 3}
In [21]:
def defalut_fac():
return random.choice([list(), tuple()])
d = defaultdict(defalut_fac) # defalut_fac 当d取不到key的时候,会调用default_fac生成value,default_fac为callable
d['kx'].append(3)
print(d)
collections.OrderedDict(a=1, b=2)
od.update({'c':3})
od = collections.OrderedDict(a=1, b=2) #OrderedDict([('a', 1), ('b', 2), ('c', 3)])
skd0
class StrKeyDict0(dict):
def __missing__(self, key):
if isinstance(key, str):
raise KeyError(key)
return self[str(key)]
def __contains__(self, key):
"""不能直接 key in self 会递归调用,
RecursionError: maximum recursion depth exceeded while calling a Python object"""
return key in self.keys() or str(key) in self.keys()
class StrKeyDict1(collections.UserDict):
def __missing__(self, key):
if isinstance(key, str):
raise KeyError
return self.data[str(key)]
def __contains__(self, key):
return str(key) in self.data
if __name__ == "__main__":
skd0 = StrKeyDict0({'1':1, '2':2})
print(skd0[1], skd0[2])
skd1 = StrKeyDict1({'1':1, '2':2})
print(skd1[1], skd1[2])
python2中的Unicode相当于python3中的Str类型,python2中的Str类型相当于python3中的bytes(但并不是还是有区别的), python3中移除独立的unicode类型关键字,python2中存在隐式的Str=>Unicode转换
版本 | 类型 | 类型 |
---|---|---|
python2 | Unicode | Str |
python3 | Str | bytes |
==运算符比较两个对象的值,而is比较对象的标识, is 速度比 == 快,
因为is直接比较的 两个对象的ID(id()),== 则调用特殊方法 __eq__
去回去结果a.__eq__(b)
,另一方面==也可以被重载.
值类型:数值,字符串,元组等不可修改类型 引用类型:列表,字典 等可修改类型
浅复制:仅复制了最外层容器,副本中的元素是源容器中元素的引用. 深拷贝:副本不共享内部对象的引用
这样会带来,意料之外的问题,因为默认值是函数对象的属性,可能导致多个使用默认值的调用中默认值参数指向了同一个引用。
垃圾回收:当对象的引用数量归零时,就会被回收。 弱引用:不增加对象的实际引用数量即不影响对象回收,某些缓存场景会使用。当弱引用引用的对象被回收时,值为None
定义操作类而不是操作实例的方法,第一个参数是类本身,而不是实例,一个常见用途是定义备选的构造方法。
可以认为静态方法就是就是普通函数,只是碰巧定义在类中。一个典型的用法可能是使用类名作为命名空间。
对应两个特殊方法eq() hash() 如果重新实现了eq()这个方法,而没有重新实现hash()方法,那么对象就会变成不可离散的。因为hash=None
ref: https://docs.python.org/3/reference/datamodel.html#object.__hash__ https://github.com/fluentpython/example-code/blob/master/09-pythonic-obj/vector2d_v3.py
不要去子类化内置类型
from collections import UserDict
class MyDict(dict):
def get(self, *args, **kwargs):
print('get')
return super().get(*args, **kwargs)
def __getitem__(self, key):
return 2
class MyDict1(UserDict):
def get(self, *args, **kwargs):
print('gets')
return super().get(*args, **kwargs)
def __getitem__(self, key):
return 2
class MyDict2(dict):
def __getitem__(self, key):
return self[key]
class MyDict3(UserDict):
def __getitem__(self, key):
return self.data[key]
if __name__ == "__main__":
d = MyDict(a=1, b=2)
print(d.get('a'))
print('--------------------')
d1 = MyDict1(a=1, b=2)
print(d1.get('a'))
print('--------------------')
d3 = MyDict3(a=1, b=2)
print(d3['a'])
print('--------------------')
d2 = MyDict2(a=1, b=2)
print(d2['a'])
"""
get
1
--------------------
gets
2
--------------------
1
--------------------
Traceback (most recent call last):
File "e:/计划内/fluent_python/seq.py", line 84, in <module>
print(d2['a'])
File "e:/计划内/fluent_python/seq.py", line 58, in __getitem__
return self[key]
File "e:/计划内/fluent_python/seq.py", line 58, in __getitem__
return self[key]
File "e:/计划内/fluent_python/seq.py", line 58, in __getitem__
return self[key]
[Previous line repeated 329 more times]
RecursionError: maximum recursion depth exceeded while calling a Python object
"""
mro (method resolution order, MRO) 方法解析顺序 C3 算法
__iter__
__next__
, 对应虚基类 abc.Iterable。具体的Iterable.__iter__
方法返回一个Iterable实例,具体的Iterator类必须实现__next__
方法。也就是可迭代对象不必实现__next__
方法,但迭代器必须实现__next__
方法。__iter__
方法,如果实现了就调用它获取一个迭代器__iter__
方法,但实现了__getitem__
方法,python会创建一个迭代器,尝试按顺序(从索引0 开始)获取元素__iter__
方法,每次都可以实例化一个新的迭代器;迭代器要实现__next__
方法,返回单个元素,此外还要实现__iter__
方法,返回迭代器本身。__iter__
方法,但不能实现__next__
方法。迭代器的__iter__
方法应该返回自身。
s = 'str'
it = iter(s) # 使用iter函数从可迭代对象中获取到迭代器it
print(next(it), next(it), next(it)) # next 迭代数据
next(it) # 抛出StopIteration异常
from collections import abc
class IterableClass(object): # 可迭代对象本身为迭代器
def __init__(self, s):
self.items = ''.join(s.split()).split(',')
self.index = 0
def __next__(self):
try:
item = self.items[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return item
def __iter__(self):
return self
class Iter(abc.Iterable): # 可迭代对象本身不为迭代器
def __init__(self, items):
self.items = list(items)
self.index = 0
def __next__(self):
try:
item = self.items[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return item
def __iter__(self):
return self
class IterableClass1(object): # 迭代器
def __init__(self, s):
self.items = ''.join(s.split()).split(',')
def __iter__(self):
return Iter(self.items)
if name == "main": ic = IterableClass('1, 2, 3, 4, 5')
for i in ic: # 正常迭代出所有值
print(i)
for j in ic: # 对象本身为迭代器,值已经被迭代完了,无法产出新值
print(j)
print('---------------------------')
ic1 = IterableClass1('1, 2, 3, 4, 5')
for k in ic1: # 正常迭代
print(k)
for k in ic1: # 第二次迭代时,生成了一个新的对象,iter()函数产出的对象为不同的对象
print(k)
1 2 3 4 5 1 2 3 4 5 """
* 使用生成器函数简化可迭代对象 ,调用生成器函数就会产生一个新的生成器对象
```python
class IterableClass2(object): # 迭代器
def __init__(self, s):
self.items = ''.join(s.split()).split(',')
def __iter__(self): # 使用生成器函数简化可迭代对象
for item in self.items:
yield item
if __name__ == "__main__":
ic1 = IterableClass2('1, 2, 3, 4, 5')
for k in ic1: # 正常迭代
print(k)
for k in ic1: # 第二次迭代时,生成了一个新的对象,iter()函数产出的对象为不同的对象
print(k)
"""输出
1
2
3
4
5
1
2
3
4
5
"""
from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
print(x)
__iter__ __next__
__getitem__ __len__ abc.Sequence
__getitem__ __len__ __setitem__ __delitem__ insert abc.MutableSequence
当for循环没有被bradk语句中止时运行
当while循环没有被bradk语句中止时运行
当try块没有异常抛出时运行else,(else 子句中的异常不会由前面的except子句处理) 在所有情况下,如果异常或者return、break或continue 语句导致控制权跳到了复合语句的主块之外,else子句也会被跳过
__exit__
return True 时不raise 异常,否则raise__exit__
方法的三个参数,exc_type
异常类(ZeroDivisionError), exec_vale
异常实例。有时会有参数传给异常构造方法,可以用exc_value.args 获取。tracback
traceback对象。@contextmanger
装饰的生成器中, yield 的值是__enter__
方法的返回值。yield语句的作用是把函数体分成了两部分:yield语句前面的代码是with开始(即__enter__
的方法中的语句)时执行。yield语句后面的代码在with块结束时(即调用__exit__
方法时)执行。
from contextlib import contextmanager
class Catch(object):
def __enter__(self):
return 'catch'
def __exit__(self, exc_type, exc_val, traceback):
if exc_type:
print('catch exception:{}-{}'.format(str(exc_type), str(exc_val)))
return True
@contextmanager def catch(): try: yield 'catch' except Exception as e: print('catch exception:{}'.format(str(e)))
if name == "main": with catch() as s: print(s) 1/0 print('haha') print('-------------------') with Catch() as t: print(t) 1/0 print('hehe')
catch catch exception:<class 'ZeroDivisionError'>-division by zero hehe """
__getattr__
和__getattribute__
在访问对象属性时,总会调用__getattribute__
, 自由对象没有对应属性时调用__getattr__
类装饰器是参数为类对象的函数,返回原来的类或修改后的类, 只对被装饰的类起作用,对齐子类无修改作用。
*实现 set方法的描述符是覆盖型描述符
"""函数属性的描述符"""
from functools import partial
def func(self, a, b):
return a + b
class Foo(object):
def __init__(self, stroge_name):
self.stroge_name = stroge_name
def __get__(self, instance, owner, *args):
if instance is None:
return self
return partial(func, instance)
def __call__(self, *_, **kwargs):
raise Exception('can not call me by class. only by instance.')
class Bar(object):
name = Foo('name')
if __name__ == "__main__":
b = Bar()
c = b.name(1, 2)
print(c)
Bar.name()
元类是用来创建类的,
__init__
的签名:__init__(cls, name, bases, attr_dict)
__new__
方法实现
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super().__new__(cls)
return cls._instance
class Foo(Singleton):
def __init__(self, a):
self.a = a
def show(self):
print(f'{self.__class__.__name__}:show')
if name == 'main': f = Foo(1) f2 = Foo(2) f.show() f2.show() print(id(f), id(f2)) print(vars(Foo))
* 使用元类实现
class Singleton(type): def init(self, name, bases, attrs): super().init(name, bases, attrs) self._instance = None
def __call__(self, *args, **kwargs):
if not self._instance:
self._instance = super().__call__(*args, **kwargs)
return self._instance
class Foo(metaclass=Singleton): pass
if name == 'main': f1 = Foo() f2 = Foo()
print(id(f1), id(f2))
print(id(Foo._instance))
def to_datetime(time_str, fmt='%b %d %Y %I:%M%p'):
from datetime import datetime
return datetime.strptime(time_str, fmt).strftime('%Y-%m-%d %H:%M:%S')
"""
In [39]: to_datetime('Mar 11 2019 11:40AM')
Out[39]: '2019-03-11 11:40:00'
In [40]: to_datetime('Mar 11 2019 11:40PM')
Out[40]: '2019-03-11 23:40:00'
"""
接口:用于描述对象的行为 抽象类:用于描述对象的实现
扁平序列
str、bytes、bytearray、memoryview、array.array
str
array.array
当list不好用的时候可以使用array.array,由于在内存中的紧凑结构,速度比list快很多,读写二进制文件速度很快,只能存储单一的基本数据类型
memoryview
数组a 和 内存视图 m 公用同一块内存空间,把m以‘b’的形式读取, 四个为1 0 0 0, 给第3个字节赋值1,则数组a 4个字节的长整型被改变为array('l', [65537])