-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
251 lines (251 loc) · 104 KB
/
search.xml
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[Go类型断言|类型分支|类型转换]]></title>
<url>%2F2020%2F01%2F14%2Fgo%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%2F</url>
<content type="text"><![CDATA[1.类型断言的使用说明1234567891011121314151617181920212223242526272829303132333435// 类型断言是作用在接口值上的操作,类似于x.(T)package mainimport ( "bytes" "fmt" "io" "os")func main() { var w io.Writer w = os.Stdout // 1.如果T是一个具体类型,类型断言会去检查x的动态类型是否是T? // 如果检查成功,类型断言的结果就是x的动态值,类型就是T。 // 可以理解为:类型断言就是从x中把具体类型T的值提取出来的操作。 f := w.(*os.File) fmt.Printf("%T\n", f) if c, ok := w.(*bytes.Buffer); ok { fmt.Println(c) } else { fmt.Println("check fail") } // 2.如果T是一个接口类型,那么类型断言检查x的动态值是否满足T? // 如果检查成功,动态值并没有提取出来,结果仍然是一个接口值,接口值的类型和值部分也没有发生变更, // 只是结果的类型为接口类型T. // 可以理解为:类型断言是一个接口值表达式,从一个接口类型变为拥有另外一套方法的接口类型(通常方法数量增多), // 但是保留了接口值中的动态类型和动态值部分。 rw := w.(io.ReadWriter) fmt.Printf("%T\n", rw) // 此时rw接口变为ReadWriter, 拥有实现ReadWriter接口中的所有方法 // 3.无论类型T作为具体类型还是接口类型,当操作数x是一个空接口值,类型断言都要失败} 2.通过类型断言来判断操作数x的动态类型是否满足一个新接口1234567891011121314151617181920212223242526272829303132333435// 通过类型断言来判断w的动态类型是否满足一个新接口package mainimport ( "io" "os")func writerString(w io.Writer, s string) (n int, err error) { type stringWriter interface { WriterString(string) (n int, err error) } if sw, ok := w.(stringWriter); ok { return sw.WriterString(s) } return w.Write([]byte(s))}func writerHeader(w io.Writer, contentType string) error { if _, err := writerString(w, "Content-Type: "); err != nil { return err } if _, err := writerString(w, contentType); err != nil { return err } return nil}func main() { w := os.Stdout _ = writerHeader(w, "Application/json")} 3.类型分支1234567891011121314151617181920212223242526package mainimport "fmt"func sqlQuote(x interface{}) string { switch x := x.(type) { case nil: return "NULL" case int, uint: return fmt.Sprintf("%d", x) case bool: if x { return "TRUE" } return "FALSE" case string: return x default: panic(fmt.Sprintf("unexpected type %T: %v", x, x)) }}func main() { var x = 34.2 fmt.Println(sqlQuote(x))} 4.实用技巧12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849package mainimport "fmt"var container = []string{"zero", "one", "two"}func main() { { // ------------------ 类型转换 ----------------- container := map[int]string{0: "zero", 1: "one", 2: "two"} fmt.Printf("The element is %q.\n", container[0]) // 对于一个未知类型的变量如何做类型转换? // 1.先把变量转换为一个空接口类型; // 2.再通过类型断言,做类型转换. value, ok := interface{}(container).(map[int]string) fmt.Printf("ok: %t, value: %v\n", ok, value) // 通过类型分支进行类型转换 container2 := interface{}(map[int]string{0: "zero", 1: "one", 2: "two"}) switch container3 := container2.(type) { case []string: fmt.Printf("container3: %T, %v\n", container3, container3) case map[int]string: fmt.Printf("container3: %T, %v\n", container3, container3) } } { // ----------------- 别名类型|类型再定义|潜在类型 --------------- type MyString = string // MyString是string的别名类型,别名类型与其源类型的区别只是在名称上,它们是完全相同的 var str MyString str = "HHH" fmt.Printf("str: %T\n", str) // str: string type MyString2 string // 类型的再定义, 把string定义为一个新的类型MyString2, MyString2与string是不同的类型 // 1.string可以称为MyString2的潜在类型,潜在类型的含义是某个类型本质上是哪个类型 // 2.潜在类型相同的不同类型之间可以进行类型转换。因此MyString2类型的值与string类型的值之间可以使用类型转换表达式进行转换。 var str2 MyString2 str2 = "HHH" fmt.Printf("str2: %T\n", str2) // str2: main.MyString2 type MyStrings []MyString2 // 对于集合类的类型[]MyString2与[]string之间做类型转换是非法的。因为[]MyString2与[]string的潜在类型不同, // 分别是[]MyString2与[]string. // 即使两个不同类型的潜在类型相同,它们之间的值也不能进行判等或比较,它们的变量之间也不能赋值。 }}]]></content>
<categories>
<category>Go</category>
</categories>
<tags>
<tag>GoType</tag>
</tags>
</entry>
<entry>
<title><![CDATA[聊天服务器]]></title>
<url>%2F2019%2F12%2F25%2FChatServer%2F</url>
<content type="text"><![CDATA[引用于《go语言圣经》,仅供学习使用. 1.服务端实现共四个goroutine: 主goroutine 广播goroutine 连接处理goroutine 客户写入goroutine 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283package mainimport ( "bufio" "fmt" "log" "net")type client chan<- string // 对外发送消息的通道var ( entering = make(chan client) // 连接通道 leaving = make(chan client) // 离开通道 messages = make(chan string) // 所有接受的客户消息)// broadcaster 广播消息func broadcaster() { clients := make(map[client]bool) // 所有联接的客户端 for { select { case msg := <-messages: // 把所有接受的消息广播给所有的客户 // 发送消息通道 for cli := range clients { cli <- msg } case cli := <-entering: clients[cli] = true case cli := <-leaving: delete(clients, cli) close(cli) } }}// handleConn 处理连接func handleConn(conn net.Conn) { ch := make(chan string) // 对外发送消息的通道 go clientWriter(conn, ch) who := conn.RemoteAddr().String() ch <- "You are " + who + "." messages <- who + " has arrived." entering <- ch input := bufio.NewScanner(conn) for input.Scan() { messages <- who + ": " + input.Text() } leaving <- ch messages <- who + " has left." conn.Close()}// clientWriter 发送消息func clientWriter(conn net.Conn, ch <-chan string) { for msg := range ch { _, _ = fmt.Fprintln(conn, msg) // 忽略网络层面的错误 }}func main() { listener, err := net.Listen("tcp", "localhost:8000") // 监听端口 if err != nil { log.Fatal(err) } // 广播 go broadcaster() for { conn, err := listener.Accept() // 接受连接 if err != nil { log.Print(err) continue } fmt.Println(conn.RemoteAddr(), " already establish connection.") // 处理连接 go handleConn(conn) }} 2.客户端实现1234567891011121314151617181920212223242526272829303132package mainimport ( "io" "log" "net" "os")func main() { conn, err := net.Dial("tcp", "localhost:8000") if err != nil { log.Fatal(err) } done := make(chan struct{}) go func() { _, _ = io.Copy(os.Stdout, conn) log.Print("done") done <- struct{}{} }() mustCopy(conn, os.Stdin) conn.Close() <-done}// mustCopy 从网络连接中读取,并写入标准输出func mustCopy(dst io.Writer, src io.Reader) { if _, err := io.Copy(dst, src); err != nil { log.Fatal(err) }} 3.最终效果]]></content>
<categories>
<category>Go</category>
</categories>
<tags>
<tag>channel</tag>
<tag>goroutine</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part3:chapter05 一等函数]]></title>
<url>%2F2019%2F06%2F06%2F%E7%AC%AC%E4%BA%94%E7%AB%A0%20%E4%B8%80%E7%AD%89%E5%87%BD%E6%95%B0%2F</url>
<content type="text"><![CDATA[5.一等对象在python中,函数是一等对象.整数、字符串、字典等都是一等对象.一等对象需要满足的条件: 在运行时创建; 能赋值给变量或数据结构中的元素; 能作为参数传递给函数; 能作为函数的返回结果. 5.1 把函数视作对象123456789101112131415def fact(n): """ 求n的阶乘 :param int n: 整数 :return: n! """ return 1 if n < 2 else n * fact(n - 1)if __name__ == '__main__': print(fact(5)) # 120 print(type(fact)) # <class 'function'> print(fact.__doc__) print(list(map(fact, range(11)))) # 函数可以作为参数传递给另外一个函数 5.2 高阶函数sorted 12345678910111213# sorted: 可选的key参数用于提供一个函数,它会运用到各个元素上进行排序li = ['a', 'aaaaa', 'aaa', 'aaaaaaa', 'aaaa']new_li = sorted(li, key=len)print(new_li) # ['a', 'aaa', 'aaaa', 'aaaaa', 'aaaaaaa']# 根据反向拼写,给一个单词排序def reserve(word): return word[::-1]li1 = ['apple', 'cherry', 'banana', 'fig']new_li1 = sorted(li1, key=reserve)print(new_li1) # ['banana', 'apple', 'fig', 'cherry'] map、filter、reduce的现代替代品 –>列表推导式/生成器推导式12345678910111213def fact(n): """ 求n的阶乘 :param int n: 整数 :return: n! """ return 1 if n < 2 else n * fact(n - 1)li2 = list(map(fact, range(6)))li3 = [fact(i) for i in range(6)]li4 = list(map(fact, filter(lambda i: i % 2, range(6))))li5 = [fact(i) for i in range(6) if i % 2] reduce、sum1234567from functools import reducefrom operator import add# 计算0到100的和print(reduce(add, range(101)))print(sum(range(101))) any、all12345# 共同点:都接受一个可迭代对象;# all: 可迭代对象的每个值都为真,则结果为真,否则为假# any: 可迭代对象的值,只要有一个为真,则结果为真,否则为假print(all([1, True, ''])) # Falseprint(any([1, False, []])) # True 5.3 匿名函数lambda12fruits = ['apple', 'banana', 'fig', 'cherry']print(sorted(fruits, key=lambda word: word[::-1])) 5.4 可调用对象callable()python中7种可调用对象: 用户定义的函数: def语句或者lambda表达式创建; 内置函数; 内置方法; 类种定义的方法; 类; 类的实例; 生成器函数; 12>>>[callable(obj) for obj in (abs, str, 13)][True, True, False] 5.5 用户定义的可调用类型123456789101112131415161718192021222324import randomclass BingoCage: def __init__(self, items): self._item = list(items) random.shuffle(self._item) def pick(self): try: return self._item.pop() except IndexError: raise LookupError('pick from empty Bingo') def __call__(self, *args, **kwargs): """使得任何python对象表示得像函数一样""" return self.pick()if __name__ == '__main__': bingo = BingoCage("abcdefg") print(bingo.pick()) print(bingo()) 5.6 函数内省12345>>> def fact(n):... return 1 if n < 2 else n * fact(n - 1)... >>> dir(fact)['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] 对函数对象可以赋予属性:123>>>fact.short_description = "cal n!"dir(fact)['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'short_description'] 常规对象有而函数没有的属性:1234567>>> class C: pass... >>> obj = C()>>> def func(): pass... >>> sorted(set(dir(func)) - set(dir(obj)))['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__'] 5.7 从定位参数到仅限关键字参数123456789101112131415161718192021222324252627282930def tag(name, *content, cls=None, **attrs): """生成一个或者多个HTML标签""" if cls is not None: attrs['class'] = cls if attrs: attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items())) else: attr_str = '' if content: return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content) else: return '<%s%s />' % (name, attr_str)if __name__ == '__main__': print(tag('br')) print(tag('p', 'hello', 'world')) print(tag('p', 'hello', 'world', cls='sidebar')) print(tag(content='testing', name='img')) my_tag = { 'name': 'img', 'title': 'beautiful girl', 'src': 'xxx.jpg', 'cls': 'framed' } print(tag(**my_tag)) 5.8 获取关于参数的信息提取关于参数的信息123456789101112131415161718192021222324def clip(text, max_len=80): """在max_len前面或后面的第一个空格处截断文本""" end = None if len(text) > max_len: space_before = text.rfind(' ', 0, max_len) if space_before >= 0: end = space_before else: space_before = text.rfind(' ', max_len) if space_before >= 0: end = space_before if end is None: end = len(text) return text[:end].rstrip()if __name__ == '__main__': print(clip.__defaults__) # 参数的默认值 print(clip.__code__) print(clip.__code__.co_varnames) # 参数名称(其中包含局部变量) ('text', 'max_len', 'end', 'space_before') print(clip.__code__.co_argcount) # 参数数量 2 print(clip.__code__.co_varnames[:clip.__code__.co_argcount]) # 真正的参数:('text', 'max_len') 更便捷的方式:通过inspect模块12345678910111213141516171819202122232425262728293031323334353637383940from inspect import signaturedef clip(text, max_len=80): """在max_len前面或后面的第一个空格处截断文本""" end = None if len(text) > max_len: space_before = text.rfind(' ', 0, max_len) if space_before >= 0: end = space_before else: space_before = text.rfind(' ', max_len) if space_before >= 0: end = space_before if end is None: end = len(text) return text[:end].rstrip()if __name__ == '__main__': sig = signature(clip) print(sig) # (text, max_len=80) for name, param in sig.parameters.items(): print(param.kind, ':', name, '=', param.default) """ POSITIONAL_OR_KEYWORD : text = <class 'inspect._empty'> POSITIONAL_OR_KEYWORD : max_len = 80 # default属性 inspect._empty值表示没有默认值 # kind属性 POSITIONAL_OR_KEYWORD:可以通过定位参数和关键字参数传入行参; VAR_POSITIONAL:定位参数元组; VAR_KEYWORD:关键字参数字典; KEYWORD_ONLY:仅限关键字参数; POSITIONAL_ONLY:仅限定位参数; """ 5.9 函数注解12345678910111213141516171819202122232425262728293031323334353637def clip(text: str, max_len: 'int > 0'=80) -> str: """在max_len前面或后面的第一个空格处截断文本""" end = None if len(text) > max_len: space_before = text.rfind(' ', 0, max_len) if space_before >= 0: end = space_before else: space_before = text.rfind(' ', max_len) if space_before >= 0: end = space_before if end is None: end = len(text) return text[:end].rstrip()if __name__ == '__main__': """ 注解:存储在函数的__annotations__属性(一个字典中) """ # 方式一: print(clip.__annotations__) # {'text': <class 'str'>, 'max_len': 'int > 0', 'return': <class 'str'>} # 方式二: sig = signature(clip) print(sig.return_annotation) # <class 'str'> for param in sig.parameters.values(): note = repr(param.annotation).ljust(13) print(note, ':', param.name, '=', param.default) """ <class 'str'> : text = <class 'inspect._empty'> 'int > 0' : max_len = 80 """]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[MySql索引]]></title>
<url>%2F2019%2F06%2F02%2F%E7%B4%A2%E5%BC%95%2F</url>
<content type="text"><![CDATA[1.主要索引的分类 B+tree索引 哈希索引 1.1 二叉树结构B+tree是由二叉树–>平衡二叉树–>B-tree演化而来. 二叉树每个节点至多有两个子节点. 二叉树中,左子树的键值永远小于右子树的子节点,且小于根节点. 1.2 平衡二叉树结构二叉树随着节点深度的加大,查询的均分复杂度就会上升,为了提高查询速度,出现了平衡树,是一颗空树. 平衡二叉树需要满足它的左子树和右子树都是一颗平衡二叉树; 左右子树的高度差的绝对值不超过1; 它与二叉树的区别在于:需要随时保证插入后的整颗二叉树是平衡的;它会通过左旋和右旋使不平衡树变为平衡树. 1.3 B-tree结构又称Btree. B树结构一个结点可以拥有多于两个子节点的多叉查找树; 若根结点不是叶子结点,应至少有两个子结点; 所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息; 1.4 B+tree结构B+tree是B-tree的变体,也是一种多路搜索树. 它所有的关键字信息都出现在叶子结点中,并且包含这些关键字记录的指针; 它所有的数据都保持在叶子结点中,也是与B-tree最大的区别. 2.B+tree索引的分类和哈希索引 聚集索引; 非聚集索引(普通索引); 2.1 聚集索引InnoDB存储引擎表是索引组织表,聚集索引其实就是一种索引组织形式,索引键值的逻辑顺序决定了表数据行的物理存储顺序. 聚集索引叶子结点存放表中所有的行数据记录的信息,所以才会有索引即数据,这是针对聚集索引来说的. 我们在创建一张表时,显示的为表创建一个主键(聚集索引),如果不主动创建主键,那么InnoDB会选择第一个不包含null值的唯一索引作为主键,如果唯一索引也不存在,InnoDB就会巍峨该表默认生成6字节的rowid作为主键. 2.2 普通索引普通索引在叶子结点并不包含所有行的数据记录,只是会在叶子结点存有自己本身的键值和主键的值,在检索数据时,通过普通索引叶子结点上的主键来获取想要查询的行数据记录.创建方式如下:123alter table table_name add index index_name(索引字段);或create index index_name on table_name(索引字段); 2.3 主键索引和唯一索引2.3.1 主键索引主键索引其实就是聚集索引,每张表中有且只有一个主键,可以由表中一个或者多个字段组成.主键索引必须满足的三大条件: 主键值必须唯一; 不能为null; 一定要保证该值时自增属性.使用自增列做主键,可以保证写入的顺序也是自增的,在很大程度上提高了自增效率. 创建主键的语法:1alter table table_name add primary key(column); 2.3.2 唯一索引唯一索引是约束条件的一种,就是不允许有重复的值出现,但是可以出现null.一张表中只能有一个主键,但是可以有多个唯一索引.创建唯一索引的语法:1alter table table_name add unique(column); 2.4 覆盖索引上面提到普通索引中包含主键即聚集索引的值,那么覆盖索引查询时除了索引本身的包含的列,还可以使用其默认的聚集索引列. 注意:如果使用了覆盖索引,一定要让select列出所需要的列.坚决不可以直接select *. 2.5 前缀索引对应BLOB(二进制)、TEXT,或者很长的VARCHAR类型的列,为它们的前几个字符建立索引,可以指定具体几个字符,这种索引称为前缀索引. 使用前缀索引的好处:索引小,查询速度快;使用前缀索引的坏处:不能在ORDER BY或GROUP BY中使用前缀索引,也不能用作覆盖索引. 创建前缀索引的语法:1alter table table_name add key(column(prefix_length)); 2.6 联合索引联合索引又称为复合索引,是表中两个或两个以上的列创建的索引.创建联合索引的语法:1create index index_name on table_name(column1, column2); 联合索引需要遵从最左前缀原则.一般把选择性更高的列放在前面.一条查询语句可以使用索引的一部分,但必须从最左侧开始. 例:为表t的c1, c2字段创建联合索引.12345678910111213141516create index ix_c1_c2 on t(c1, c2);以下情况使用到了索引:select * from t where c1="xxx";select * from t where c2="xxx" and c1="xxxx";select * from t where c1="xxx" and c2 in ("xxxx1", "xxxx2");select * from t order by c1, c2;select * from t where c1="xxx" order by c2;以下情况使用不到索引:select * from t where c2="xxxx";select * from t where c2="xxxx" order by c1;特殊情况:select * from t where c1="xxx" or c2="xxxx";虽然遵循了最左前缀,但是该情况使用不到索引,可以分别为c1和c2创建两个单列索引. 2.7 哈希索引哈希索引采用哈希算法,把键值换算成新的哈希值.哈希索引只可以进行等值比较,不能进行排序、模糊查找、范围查询等.哈希索引检索时,不需要像B+tree那样从根结点到叶子结点逐级查找,只需要一次哈希算法就可以立即定位到相应的位置,查询速度非常快. 3.索引总结3.1 索引的优点 提高检索效率 提高聚合函数的效率 提高排序效率 使用覆盖索引可以避免回表 3.2 索引创建的四不要 选择性很低的字段不要创建索引; 很少查询的列不要创建索引; 大数据类型字段不要创建索引; 尽量避免使用NULL,因为含有NUll的列很难做索引优化,可以使用空字符串代替索引. 3.3 使用不到索引的情况 通过索引扫描的行记录数超过全表的30%,优化器不会走索引,而会变成全表扫描; 联合索引中,第一个查询条件不是最左索引列; 联合索引中,第一个索引列使用了范围查询,只能使用到部分索引,有ICP出现(< = <= BETWEEN and); 联合索引中,第一个查询条件不是最左前缀列; 模糊查询条件列最左以通配符%开始; 两个单列索引,一个用于检索,一个用于排序,这种情况下,只能使用到一个索引,因为查询语句中,最多只能使用一个索引,考虑建立联合索引; 查询字段上有索引,但是使用了函数运算.]]></content>
<categories>
<category>MySql</category>
</categories>
<tags>
<tag>MySql</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter07 元类编程01]]></title>
<url>%2F2019%2F05%2F05%2Fchapter07%E5%85%83%E7%B1%BB%E7%BC%96%E7%A8%8B01%2F</url>
<content type="text"><![CDATA[7-1 property动态属性123456789101112131415161718192021222324252627#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-04from datetime import date, datetimeclass User: def __init__(self, name, birthday): self.name = name self.birthday = birthday @property # 将动态属性装饰成静态属性 def age(self): return datetime.now().year - self.birthday.year @age.setter def age(self, value): self.birthday = date(datetime.now().year - value, 1, 1) # 此处处理比较简单,仅供演示属性作用if __name__ == '__main__': user = User("david", date(1995, 10, 1)) print(user.age) # 24 user.age = 32 print(user.age) # 32 7-2 getattr和getattribute魔术方法12345678910111213141516171819202122232425262728293031323334#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-04"""在属性查找时,若类中没有实现__getattr__方法,会直接--> AttributeError: 'User' object has no attribute 'age'__getattr__ 在属性查找不到的时候,会调用该方法。__getattribute__ 属性查找会直接进入该方法,一般不建议自己动手去实现该方法。"""from datetime import dateclass User: def __init__(self, name, birthday): self.name = name self.birthday = birthday def __getattr__(self, item): return f"{item.title()} not found!" def __getattribute__(self, item): return "666"if __name__ == '__main__': user = User("david", date(1995, 10, 1)) print(user.age) 7-3 属性描述符和属性查找过程123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-04"""数据描述符 类中定义了__set__和__get__方法非数据描述符 类定义了__get__方法,没有定义__set__方法"""import numbersclass IntField: """ 数据描述符 """ def __get__(self, instance, owner): return 100 def __set__(self, instance, value): if not isinstance(value, numbers.Integral): raise ValueError("int value need") if value < 0: raise ValueError("positive value need") self.value = value def __delete__(self, instance): passclass NoDataIntField: """ 非数据描述符 """ def __get__(self, instance, owner): return 300class User: # age = IntField() # age = NoDataIntField() # age = 400 # def __getattr__(self, item): # return 500 passif __name__ == '__main__': user = User() # user.__dict__['age'] = 200 print(user.age)"""如果user是某个类的实例,那么user.age(以及等价的getattr(user, 'age')首先调用__getattribute__,如果类中定义了__getattr__方法,那么在__getattribute__抛出 AttributeError 的时候就会调用__getattr__,而对于描述符__get__的调用,则发生在__getattribute__内部的。user = User(), 那么user.age 查找顺序如下:1.如果"age"是出现在User或者其基类的__dict__中, 且 age 是 数据描述符, 那么调用数据描述符的__get__方法,否则:2.如果"age"是出现在user的__dict__中,那么直接返回 obj.__dict__['age'], 否则:3.如果"age"出现在User或者其基类的__dict__中,3.1 如果age是非数据描述符,那么调用其__get__方法,否则:3.2 返回__dict__['age']4.如果User有__getattr__方法,调用__getattr__方法,否则:5.抛出AttributeError""" 7-4 new和init12345678910111213141516171819202122232425#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-05class User: def __new__(cls, *args, **kwargs): """Create and return a new object.""" print("in new") return super().__new__(cls) def __init__(self, name): """Initialize self""" print("in init") self.name = name"""__new__用来控制对象的生成过程,在对象生成之前发生;__init__是用来完善对象的;如果__new__不返回一个对象,则不会调用__init__函数;"""if __name__ == "__main__": user = User(name="david") 7-5 自定义元类12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-05def create_class(name): if name == "user": class User: def __str__(self): return "user" return User if name == "company": class Company: def __str__(self): return "company" return Companydef say(self): return "I'm saying."class Person: def __init__(self, name): self.name = name def answer(self): return "I'm answering."# 3.--------元类编程---------"""什么是元类,元类是创建类的类,python一切皆对象,所以类也是对象,类是由type类创建的。python中类对象创建的过程 首先去找类本身的metaclass, 通过metaclass去创建类; 若找不到,去找基类的metaclass; 若基类中也找不到,再去模块中找,若找不到,调用内置type去创建类"""class MetaClass(type): def __new__(cls, *args, **kwargs): """将对象的生成过程交给元类来控制""" return super().__new__(cls, *args, **kwargs)class Animal(metaclass=MetaClass): def __init__(self, name, kind): self.name = name self.kind = kind def run(self): return f"{self.name} is running."# ----------------------------if __name__ == '__main__': # 1.-------动态创建类的方法一---------- # my_class = create_class("user") # my_obj = my_class() # print(my_obj) # 2.-------动态创建类的方法二----------type动态创建类 User = type("User", (Person,), {"say": say}) # 第一个参数是类名,第二个参数是继承的类,第三个参数是属性dict my_obj = User("lisa") print(my_obj.say()) print(my_obj.name) cat = Animal("Tom", "Cat") print(cat.run()) ——未完待续!]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter06 对象引用、可变性和垃圾回收]]></title>
<url>%2F2019%2F05%2F02%2Fchapter06-%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%E3%80%81%E5%8F%AF%E5%8F%98%E6%80%A7%E5%92%8C%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%2F</url>
<content type="text"><![CDATA[6-1 python中的变量是什么12345678910111213141516171819#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01"""python变量的本质实质上是一个指针,可以假象为一个便利贴;声明一个变量的时候,先生成对象,然后再将便利贴贴在对象上;"""a = [1, 2, 3]b = aprint(a is b) # Trueprint(id(a), id(b)) # 4527763336 4527763336"""先生成list对象,再将便利贴a贴在对象上;b = ab这个便利贴是等于便利贴a的,即b对应的对象和a对应的对象是同一个""" 6-2 ==和is的区别123456789101112131415161718192021222324252627#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01# (1)id 查询内存地址name = "david"print(id(name))print(id(3))# (2)= 赋值运算 == 比较运算name1 = "david"name2 = "david"print(name1 == name2) # True 判断值是否相等# (3)is 判断内存地址是否相等l1 = [1, 2, 3]l2 = [1, 2, 3]print(l1 is l2) # False 判读ID是否相等# (4)小数据池"""只有数字/字符串/布尔值有小数据池的概念看一下这位大哥的博客:https://www.cnblogs.com/jin-xin/articles/9439483.html""" 6-3 del语句和垃圾回收的区别12345678910111213141516171819202122232425262728293031#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-02a = object()b = adel aprint(b) # <object object at 0x10d49e0b0># print(a) # NameError: name 'a' is not defined"""在cpython中垃圾回收算法采用引用计数: 1.在一个变量创建之后,引用计数加一,每被引用一次,都会再加一; 2.del 变量时,会将引用计数减一,而不是直接做垃圾回收; 3.python解释器会自动回收引用计数为0的对象;"""class A: def __del__(self): print(111)"""在创建的类内部实现__del__方法,当做del时,以及python解释器做垃圾回收时,将一些资源释放的内容或者自定义内容写在方法内,可达到想要的一定目的"""a = A()del a 6-4 一个经典的参数错误demo112345678910111213141516171819202122232425262728293031323334#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-02# Demo1def add(a, b): a += b return aif __name__ == '__main__': a = 1 b = 2 c = add(a, b) print(c) print(a, b) a = [1, 2] b = [3, 4] c = add(a, b) print(c) # [1, 2, 3, 4] print(a, b) # [1, 2, 3, 4] [3, 4] """ list1 += list2 这个操作实质上是在list1.extend(list2), 因此会将a的值做修改 """ a = (1, 2) b = (3, 4) c = add(a, b) print(c) # (1, 2, 3, 4) print(a, b) # (1, 2) (3, 4) demo21234567891011121314151617181920212223242526272829303132333435363738394041424344454647#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-02class Company: def __init__(self, name, staffs=[]): self.name = name self.staffs = staffs def add(self, staff_name): self.staffs.append(staff_name) def remove(self, staff_name): self.staffs.remove(staff_name)if __name__ == '__main__': com1 = Company("com1", ["david1", "david2"]) com1.add("david3") com1.remove("david1") print(com1.staffs) # ['david2', 'david3'] com2 = Company("com2") print(Company.__init__.__defaults__) # ([],) com2.add("david4") print(com2.staffs) # ['david4'] print(Company.__init__.__defaults__) # (['david4'],) com3 = Company("com3") print(Company.__init__.__defaults__) # (['david4'],) com3.add("david5") print(com3.staffs) # ['david4', 'david5'] print(Company.__init__.__defaults__) # (['david4', 'david5'],) print(com2.staffs is com3.staffs) # True """ 为什么com3实例对象中含有com2对象添加的值? 原因:com2和com3在实例化的时候都未传staffs,因此都使用默认值[], 在com2对默认值[]添加元素后,默认值就变为["david4"], com3对默认值添加元素"david5", 自然是在已经变化后的默认值中添加, 该默认值在是同一个变量 """]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter05 深入Set和dict]]></title>
<url>%2F2019%2F05%2F02%2Fchapter05-%E6%B7%B1%E5%85%A5set%E5%92%8Cdict%2F</url>
<content type="text"><![CDATA[5-1 dict的abc继承关系12345678910111213#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01from collections.abc import Mapping, MutableMappingprint(isinstance(dict(name='david'), MutableMapping))print(isinstance(dict(name="david"), Mapping))"""dict并不是继承了Mapping和MutableMapping,而是实现了二者中需要实现的abc方法""" 5-2 dict的常用方法123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01import copydic = dict(name="david", age=18)dic.clear()print(dic)"""浅拷贝: 第一级独立,第二级开始共享内存"""dic1 = { "address": { "province": "zhejiang", "city": "hangzhou" }}dic2 = dic1.copy()dic2["name"] = "david"dic2["address"]["city"] = "ningbo"print(dic1) # {'address': {'province': 'zhejiang', 'city': 'ningbo'}}print(dic2) # {'address': {'province': 'zhejiang', 'city': 'ningbo'}, 'name': 'david'}# 以上证明浅拷贝,一级独立,二级开始共享内存空间"""深拷贝: 各级独立"""dic3 = { "address": { "province": "zhejiang", "city": "hangzhou" }}dic4 = copy.deepcopy(dic3)dic3["name"] = "lisa"dic4["name"] = "david"dic4["address"]["city"] = "ningbo"print(dic3) # {'address': {'province': 'zhejiang', 'city': 'hangzhou'}, 'name': 'lisa'}print(dic4) # {'address': {'province': 'zhejiang', 'city': 'ningbo'}, 'name': 'david'}# 以上证明深拷贝,各级独立# ------------------# fromkeys方法li = ["name", "age", "hobby"]dic5 = dict.fromkeys(li, "") # 第一个参数接受一个可迭代对象,第二个参数是默认值print(dic5) # {'name': '', 'age': '', 'hobby': ''}# get方法value = dic5.get("id", 1) # dic5["id"] 取不到会keyError, 通过get方法取不到,会返回一个默认值# setdefault方法# 两步操作,第一步去取值,能取到直接返回# 若第一步,取不到值,会将键值对放入dict, 同时返回值value2 = dic5.setdefault("id", 1) # {'name': '', 'age': '', 'hobby': '', 'id': 1}print(value2) # 1print(dic5)# update方法dic6 = {"name": "david", "age": 18}dic6.update(name="lisa")dic6.update([("age", 19)])dic6.update({"hobby": ["play game"]})print(dic6) # {'name': 'lisa', 'age': 19, 'hobby': ['play game']} 5-3 dict的子类1234567891011121314151617181920212223242526272829303132333435#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01from collections import UserDict, defaultdictclass MyDict(dict): def __setitem__(self, key, value): super(MyDict, self).__setitem__(key, value * 2)my_dict = MyDict(one=1)print(my_dict) # {'one': 1} 未生效my_dict["one"] = 1print(my_dict) # {'one': 2} 生效# 不建议继承dict/list等C实现的内置数据类型class MyUserDict(UserDict): def __setitem__(self, key, value): super(MyUserDict, self).__setitem__(key, value * 2)my_dict = MyDict(one=1)print(my_dict) # {'one': 1} 未生效my_dict["one"] = 1print(my_dict) # {'one': 2} 生效my_dict2 = defaultdict(list) # 接受一个callablemy_value = my_dict2["david"] # defaultdict 重写了__missing__方法,取不到值的时候,会设置键值对print(my_value) # [] 5-4 set和frozenset12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01"""set:集合frozenset: 不可变集合特点: 无序,不重复"""s = set("abca") # 接受一个可迭代对象s.add("e")print(s)s1 = {"a", "b", "c", "a"}print(s1)s = frozenset("abcde")print(s) # frozenset({'a', 'b', 'd', 'c', 'e'}) 不可变# set常用方法my_set1 = {"a", "b", "c"}my_set2 = {"c", "d", "e"}# 差集: my_set1中有,my_set2中没有的元素res1 = my_set1.difference(my_set2)print(res1) # {'a', 'b'}res2 = my_set1 - my_set2print(res2) # {'a', 'b'}# 并集: 两个集合之和res3 = my_set1.union(my_set2)res4 = my_set1 | my_set2print(res3) # {'d', 'c', 'e', 'a', 'b'}print(res4) # {'d', 'c', 'e', 'a', 'b'}# 交集: 两个集合共同元素res5 = my_set1.intersection(my_set2)res6 = my_set1 & my_set2print(res5) # {'c'}print(res6) # {'c'}# addmy_set1.add("g")print(my_set1) # {'b', 'g', 'a', 'c'}# remove# 移除元素不存在会报错# my_set1.remove("x")# print(my_set1) # keyError# discordmy_set1.discard("x")print(my_set1) # 移除元素不存在,不会报错# issubset# 判断一个集合是不是另外一个集合的子集my_set3 = set("a")print(my_set3.issubset(my_set1)) # True# 判断某个元素在不在其中print("x" in my_set3) # False 5-5 dict和set的实现原理1234567891011121314#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-05-01"""1.dict的查好效率远远高于list;2.在list中随着list数据的增大,查找时间会增大;3.在dict中查找元素不会随着dict的增大而查找时间增大;""""""实现原理: 这位大哥说的比较清楚,借用一下:https://blog.csdn.net/answer3lin/article/details/84523332"""]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter04-序列类型]]></title>
<url>%2F2019%2F04%2F28%2Fchapter04-%E5%BA%8F%E5%88%97%E7%B1%BB%E5%9E%8B%2F</url>
<content type="text"><![CDATA[4-1 python中的序列分类纬度一:根据是否可以存放任意数据类型来划分 容器序列:可以存放任意数据类型 list tuple deque 扁平序列:只能存放特定的数据类型 str bytes bytearray array.array 纬度2:根据存放的数据类型是否可以被修改 可变序列:可以增删改 list deque bytearray array 不可变序列:不可以增删改 str tuple bytes 4-2 python中的序列类型123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07from collections import abcimport _collections_abc"""Sequence: 不可变序列;MutableSequence: 可变序列""""""继承关系如下:"""class Sized(metaclass=ABCMeta): __slots__ = () @abstractmethod def __len__(self): return 0 @classmethod def __subclasshook__(cls, C): if cls is Sized: return _check_methods(C, "__len__") return NotImplemented class Iterable(metaclass=ABCMeta): __slots__ = () @abstractmethod def __iter__(self): while False: yield None @classmethod def __subclasshook__(cls, C): if cls is Iterable: return _check_methods(C, "__iter__") return NotImplemented class Container(metaclass=ABCMeta): __slots__ = () @abstractmethod def __contains__(self, x): return False @classmethod def __subclasshook__(cls, C): if cls is Container: return _check_methods(C, "__contains__") return NotImplementedclass Collection(Sized, Iterable, Container): __slots__ = () @classmethod def __subclasshook__(cls, C): if cls is Collection: return _check_methods(C, "__len__", "__iter__", "__contains__") return NotImplemented class Reversible(Iterable): __slots__ = () @abstractmethod def __reversed__(self): while False: yield None @classmethod def __subclasshook__(cls, C): if cls is Reversible: return _check_methods(C, "__reversed__", "__iter__") return NotImplemented class Collection(Sized, Iterable, Container): __slots__ = () @classmethod def __subclasshook__(cls, C): if cls is Collection: return _check_methods(C, "__len__", "__iter__", "__contains__") return NotImplemented class Sequence(Reversible, Collection): passclass MutableSequence(Sequence): pass 4-3 list中的extend方法12345678910111213141516171819202122232425262728#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-21li = [1, 2, 3]li.append([11, 22])print(li) # [1, 2, 3, [11, 22]] # 追加到列表中li.extend([111, 222])print(li) # [1, 2, 3, [11, 22], 111, 222] # 迭代着追加li1 = [1, 2]li2 = li1 + [3, 4]print(li2) # [1, 2, 3, 4]# li3 = li1 + (3, 4) # TypeError: can only concatenate list (not "tuple") to listli1 += (3, 4)print(li1) # [1, 2, 3, 4]"""原理: += 是调用__iadd__魔术方法,而该方法中调用extend迭代着追加元素到列表中 def __iadd__(self, values): self.extend(values) return self""" 4-4 实现可切片的对象1234567891011121314151617181920212223242526#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-21"""切片操作会返回一个新的列表"""li = [3, 4, 5, 6, 7, 9, 11, 13, 15, 17]"""[start:end:step][起始:结束:步进]"""print(li[::]) # 切片操作,不填默认start:0,end:len(li),step:1print(li[::-1]) # 倒序print(li[:100]) # 超出范围,默认end为列表长度print(li[::2]) # 步进为2print(li[100:]) # 起始位置超出列表长度,返回空列表"""[3, 4, 5, 6, 7, 9, 11, 13, 15, 17][17, 15, 13, 11, 9, 7, 6, 5, 4, 3][3, 4, 5, 6, 7, 9, 11, 13, 15, 17][3, 5, 7, 11, 15][]""" 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-27import numbersclass Group: """ 实现一个不可变序列 """ def __init__(self, group_name, company_name, staffs): self.group_name = group_name self.company_name = company_name self.staffs = staffs def __reversed__(self): self.staffs.reverse() def __getitem__(self, item): cls = type(self) if isinstance(item, slice): # 切片会调用__getitem__, 同时会把 return cls(self.group_name, self.company_name, self.staffs[item]) if isinstance(item, numbers.Integral): return cls(self.group_name, self.company_name, [self.staffs[item]]) def __len__(self): return len(self.staffs) def __iter__(self): return iter(self.staffs) def __contains__(self, item): return True if item in self.staffs else False def __str__(self): return "{}".format(self.staffs)staffs = ['david', 'lisa', 'lucas', 'john']group = Group("technology", "TX", staffs=staffs)print(group[2]) # ['lucas']print(group[:3]) # ['david', 'lisa', 'lucas']for user in group: print(user)reversed(group)print(group) # ['john', 'lucas', 'lisa', 'david']"""__str__ 当你打印一个对象的时候 触发__str__ 当你使用%s格式化的时候 触发__str__ str强转数据类型的时候 触发__str____repr__ repr是str的备胎 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__ repr(obj)内置函数对应的结果是 __repr__的返回值 当你使用%r格式化的时候 触发__repr__""" 4-5 bisect维护已排序的序列1234567891011121314151617181920#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-28import bisect"""用来处理已排序的序列,用来维持已排序的序列,升序排列二分查找"""inter_list = []bisect.insort(inter_list, 3)bisect.insort(inter_list, 8)bisect.insort(inter_list, 1)bisect.insort(inter_list, 4)print(inter_list) # [1, 3, 4, 8]print(bisect.bisect(inter_list, 4)) # 3 返回插入位置的索引,默认是bisect_rightprint(bisect.bisect_left(inter_list, 4)) # 2 4-6 什么时候使用列表1234567891011121314151617181920212223242526272829303132333435#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-28import array"""array和list的区别 array: 只能存放指定的数据类型 list: 可以存放各种数据类型 array Methods: append() -- append a new item to the end of the array buffer_info() -- return information giving the current memory info byteswap() -- byteswap all the items of the array count() -- return number of occurrences of an object extend() -- extend array by appending multiple elements from an iterable fromfile() -- read items from a file object fromlist() -- append items from the list frombytes() -- append items from the string index() -- return index of first occurrence of an object insert() -- insert a new item into the array at a provided position pop() -- remove and return item (default last) remove() -- remove first occurrence of an object reverse() -- reverse the order of the items in the array tofile() -- write all items to a file object tolist() -- return the array converted to an ordinary list tobytes() -- return the array converted to a string"""my_array = array.array('i')my_array.append(111)print(my_array) 4-7 列表推导式、生成器推导式、字典推导式、集合推导式1234567891011121314151617181920212223242526272829#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-28# 01 列表推导式# 提取1到20之间的奇数li = [i for i in range(1, 21) if i % 2 == 1]print(li) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]# 提取1到20之间奇数的平方li1 = [i ** 2 for i in range(21) if i % 2 == 1]print(li1)# 02 生成器表达式gen = (i for i in range(21) if i % 2 == 1)print(type(gen), gen) # <class 'generator'> <generator object <genexpr> at 0x109a08a98># 03 字典推导式my_dict = {'david': 21, 'lisa': 44, 'lucas': 66}reversed_dict = {value: key for key, value in my_dict.items()}print(reversed_dict) # {21: 'david', 44: 'lisa', 66: 'lucas'}# 04 集合推导式my_set = {key for key in my_dict}print(my_set) # {'lisa', 'david', 'lucas'}my_set = set(my_dict.keys())print(my_set)]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter03-深入类和对象02]]></title>
<url>%2F2019%2F04%2F07%2F%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A12%2F</url>
<content type="text"><![CDATA[3-7 数据封装和私有属性私有属性: 在属性前加上双下划线__, python内部会对该属性名称进行转换,转换为:_类名__私有属性名。使得外部对象不能直接调用__私有属性,实质上并没有做到数据安全。123456789101112131415161718192021222324252627282930313233343536373839404142434445 #! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07import timeclass Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def __str__(self): return f"{self.year}/{self.month}/{self.day}"class User: def __init__(self, birthday): self.__birthday = birthday # self.__birthday <==> self._User__birthday def get_age(self): return time.localtime().tm_year - self.__birthday.yearclass Student(User): def __init__(self, birthday): super().__init__(birthday) self.__birthday = birthday # self.__birthday <==> self._Student__birthdayuser = User(Date(1995, 12, 12))print(user.get_age())print(user._User__birthday)stu = Student(Date(1997, 8, 4))print(stu.get_age())print(stu._Student__birthday)"""私有属性: 在属性前加上双下划线__, python内部会对该属性名称进行转换,转换为:_类名__私有属性名""" 3-8 python对象的内省机制如果需要看到类和对象内部的结构时,可以使用__dict__和dir来查看。12345678910111213141516171819202122232425262728293031323334353637class Person: kind = 'person'class Student(Person): def __init__(self, name): self.name = nameif __name__ == '__main__': stu = Student('david') print(stu.__dict__) # {'name': 'david'} print(Person.__dict__) """ {'__module__': '__main__', 'kind': 'person', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} """ # 直接操作对象的__dict__ stu.__dict__['age'] = 18 print(stu.age) # 18 # 列出对象的所有属性和方法,比__dict__强大 print(dir(stu)) """ ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'kind', 'name'] """ # 对列表进行__dict__和dir li = [1, 2, 3] print(dir(li)) print(li.__dict__) # 会报错 3-9 super真的是调用父类吗?123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07"""问题1:既然重写了构造函数,为什么还要去调用super"""from threading import Threadclass MyThread(Thread): def __init__(self, name, user): self.user = user # super(MyThread, self).__init__(name=name) # Python2的写法 super().__init__(name=name) # python3的写法,针对问题1,调用super可以避免重复造轮子的问题发生。此处,父类中已实现name属性"""问题2:super的执行顺序是怎样的?"""class A: def __init__(self): print('A')class B(A): def __init__(self): print('B') super().__init__()class C(A): def __init__(self): print('C') super().__init__()class D(B, C): def __init__(self): print('D') super().__init__()d = D()print(D.__mro__)"""super不是简单的去调用父类的__init__方法,而是根据__mro__顺序,去调用类中的__init__方法。DBCA(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)""" 3-10 mixin模式特点Mixin模式 mixin类功能单一; 不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功; 在mixin中不要使用super这种用法; 3-11 python中的with语句123456789101112131415161718192021222324252627282930#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07def exe_try(): try: print('code started') raise KeyError return 1 except KeyError as e: print('key error') return 2 else: print('other error') return 3 finally: print('finally') return 4if __name__ == '__main__': ret = exe_try() print(ret)"""code startedkey errorfinally4 # 此处返回4原因是,代码被捕获到KeyError进入逻辑中,本该返回2,此时会放入一个堆栈中,直到走到finally,将4放入栈顶,取栈顶返回。""" 1234567891011121314151617181920212223242526272829#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07class Sample: """ 上下文管理器协议:需要实现__enter__和__exit__,二者组成了上下文协议,可以通过with调用 """ def __enter__(self): print('enter') # 获取资源 return self def __exit__(self, exc_type, exc_val, exc_tb): # 释放资源 print('exit') def do_something(self): print('do something')with Sample() as sample: sample.do_something()"""enter # 首先调用__enter__获取资源do something # 对资源进行操作exit # 最后调用__exit__释放资源""" 3-12 contextlib简化上下文管理器1234567891011121314151617181920212223#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-04-07import [email protected] file_open(file_name): print('file open') # 可以理解为实现__enter__ yield {} # 此处必须要实现生成器, 可以理解为实现do_something print('file end') # 可以理解为实现__exit__with file_open('david.txt') as f: print('file processing')"""file openfile processingfile end"""]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter03-深入类和对象01]]></title>
<url>%2F2019%2F04%2F05%2F%E6%B7%B1%E5%85%A5%E7%B1%BB%E5%92%8C%E5%AF%B9%E8%B1%A11%2F</url>
<content type="text"><![CDATA[3-1 鸭子类型和多态鸭子类型 当你看见一只鸟走起来像鸭子,游泳起来像鸭子,叫起来像鸭子,那么这只鸟就可以被称为鸭子。12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152"""鸭子类型 当你看见一只鸟走起来像鸭子,游泳起来像鸭子,叫起来像鸭子,那么这只鸟就可以被称为鸭子。"""class Cat: def say(self): print('I am a cat!')class Dog: def say(self): print('I am a dog!')class Duck: def say(self): print('I am a duck!')animal_list = [Cat, Dog, Duck]for animal in animal_list: animal().say()"""I am a cat!I am a dog!I am a duck!""""""python天生自带多态,上面例子中只要每个类中都实现同样的方法say(),那么它们就是同种类型,不用去继承共同的父类。"""li = ['david1', 'david2']tu = ('david3', 'david4')set = {'david5', 'david6'}li.extend(tu)li.extend(set)print(li)"""['david1', 'david2', 'david3', 'david4', 'david6', 'david5']li.extend(),接受一个可迭代对象,而不是具体指定的某个类型。传入数据后,会在数据本身的类中去转换为可迭代对象,即调用__iter__(), 若找不到调用__getitem__().而静态语言,则需要指明传入的数据类型。同时,python中的魔法函数,不是需要父类中一定要实现该方法,而是直接在本身的类中实现即可,对于上述例子中元组和集合只要它们在内部类中都实现__iter__,那么他们就可以说是共同的类型,即可迭代对象。这就是鸭子类型的一个例子。""" 3-2 抽象基类abc模块12345678910111213141516171819202122"""使用abc模块的场景 1.判断某个类是是否实现了某种方法 - python中有hasattr()可以判断; - 但是如果要通过isinstance()来判断,那么就需要实现一个抽象基类,抽象基类要求实现某些特定的方法。 如果当前检测类实现了特定方法,则表明继承了抽象基类,是输入这个抽象类型"""from collections.abc import Sizedclass Company: def __init__(self, employee_list): self.employee_list = employee_list def __len__(self): return len(self.employee_list)company = Company(['tom', 'jan', 'jack'])print(hasattr(company, '__len__')) # Trueprint(isinstance(company, Sized)) # True --> 是因为实现了__len__()方法,Sized是一个抽象类,该类中要求实现__len__() 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-03-31"""抽象基类 2.我们需要强制某个子类必须实现某些方法: 如实现了一个web框架,集成cache(redis, cache, memorycache) 需要设计一个抽象基类,指定子类必须实现某些方法"""# 方式一class CacheBase: def get(self): raise NotImplementedError def set(self, key, value): raise NotImplementedErrorclass RedisCache(CacheBase): passredis_cache = RedisCache()redis_cache.set('name', 'david')"""若在RedisCache中不实现set方法,那么会调用父类CacheBase的set方法,而父类中的set方法则会抛出异常NotImplementedError"""# 在子类中实现set方法class CacheBase: def get(self): raise NotImplementedError def set(self, key, value): raise NotImplementedError class RedisCache(CacheBase): def set(self, key, value): return True redis_cache = RedisCache() print(redis_cache.set('name', 'david')) # True# 方式二 import abc class CacheBase(metaclass=abc.ABCMeta): @abc.abstractmethod def get(self): pass @abc.abstractmethod def set(self, key, value): pass class RedisCache(CacheBase): pass redis_cache = RedisCache() print(redis_cache.set('name', 'david')) """ TypeError: Can't instantiate abstract class RedisCache with abstract methods get, set """ ``` ### 3-3 isinstance和type的区别```pyclass A: passclass B(A): passb = B()print(isinstance(b, B)) # Trueprint(isinstance(b, A)) # Trueprint(type(b) is B) # Trueprint(type(b) is A) # False"""is 和 == 的区别 is:判断id是否相等 ==:判断值是否相等 isinstance判断继承关系是否成立type判断类型是否相同""" 3-4 类变量和实例变量的区别12345678910111213141516171819202122232425class A: aa = 1 def __init__(self, x, y): self.x = x self.y = ya = A(2, 3)print(a.x, a.y, a.aa) # 2 3 1A.aa = 100 # 此处是对类的变量进行赋值操作print(a.x, a.y, a.aa) # 2, 3, 100 # 对象a自身在此处没有变量aa,就去类中找aaa.aa = 200 # 此处是在对象a的内存空间中进行赋值操作,对象a多一个属性aa = 200print(a.x, a.y, a.aa) # 2 3 200 查找时,自下而上,先从对象的内存空间中找,若找不到,再去类的内存空间中找b = A(4, 5)print(b.aa) # 100 此处查找同上,对象b自身空间中没有,就去类空间中找"""注意需要区分清楚类变量和实例对象变量的区别 - 二者都有各自的内存空间 - 在属性查找时,对象自下而上,先找自己的内存空间,若找不到,再去类空间中找 而类在查找属性时,只能去自己的类空间中找,不能自上而下找""" 3-5类和实例属性的查找顺序1234567891011121314151617181920212223242526272829303132333435363738"""菱形继承 AB CD E F"""class A: passclass B(A): passclass C(A): passclass D(B): passclass E(C): passclass F(D, E): passprint(F.__mro__) # 3C算法"""(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)""" 1234567891011121314151617181920212223242526272829303132"""B CD E F"""class B: passclass C: passclass D(B): passclass E(C): passclass F(D, E): passprint(F.__mro__)"""(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class 'object'>)""" 3-6 类方法、静态方法和实例方法1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def __str__(self): return f"{self.year}/{self.month}/{self.day}" def tomorrow(self): """ 下一天(简单演示示例方法) :return: """ self.day += 1 @staticmethod def parse_date_str(date_str): year, month, day = tuple(date_str.split('-')) return Date(int(year), int(month), int(day)) @classmethod def format_date_str(cls, date_str): year, month, day = tuple(date_str.split('-')) return cls(int(year), int(month), int(day)) @staticmethod def check_date_str(date_str): """ 检查是否时合法的时间,只为演示静态方法使用场景,功能简单,真实场景需要重新调整 :param data_str: "2019-04-04" :return: """ year, month, day = tuple(date_str.split('-')) if (int(year) > 0) and (0 < int(month) < 13) and (0 < int(day) < 32): return True else: return Falsenew_day = Date(2019, 4, 4)print(new_day) # 2019/4/4# 实例方法new_day.tomorrow() # 2019/4/5print(new_day)# 静态方法date_str = '2019-04-04'new_day = Date.parse_date_str(date_str)print(new_day) # 2019/4/4# 类方法# 上面用静态方法格式化时间字符串存在一个缺陷,即当我们类名修改时,同时需要修改静态方法中的类名# 因此使用类方法,实现该功能更合适date_str = '2019-04-04'new_day = Date.format_date_str(date_str)print(new_day) # 2019/4/4# 当我们实现的方法即不涉及到类,也不涉及到示例,只是与该类功能相关时,使用静态方法较好date_str = '2019-11-41'print(Date.check_date_str(date_str)) # False ············································未完待续]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter02魔法函数]]></title>
<url>%2F2019%2F03%2F30%2F%E9%AD%94%E6%B3%95%E5%87%BD%E6%95%B0%2F</url>
<content type="text"><![CDATA[2-1 什么是魔法函数魔法函数,即对python中以__开头的函数的一种叫法,如__init__、__repr__等。demo123456789101112131415161718class Company: def __init__(self, employee_list): self.employee_list = employee_list def __getitem__(self, item): return self.employee_list[item]company = Company(['tom', 'jan', 'jack'])for em in company: print(em)"""for循环的对象是一个可迭代对象,在类中若没有定义__iter__, 那么会去找__getitem__,通过它来取值,直到取到值或者抛异常,才会结束for循环""" 2-2 python数据模型对python的影响demo123456789101112131415161718class Company: def __init__(self, employee_list): self.employee_list = employee_list def __getitem__(self, item): return self.employee_list[item] def __len__(self): return len(self.employee_list)company = Company(['tom', 'jan', 'jack'])company1 = company[:2] # 通过__getitem__支持切片print(len(company1)) # 2# 若company没有实现__len__,则不支持len(), 而len(company1)不用实现也支持,是因为company1是列表,列表支持len()print(len(company)) # 3 2-3 魔法函数概览__str__和__repr__12345678910111213141516171819202122class Company: def __init__(self, employee_list): self.employee_list = employee_list def __str__(self): return ','.join(self.employee_list) def __repr__(self): return ','.join(self.employee_list)company = Company(['tom', 'jan', 'jack'])print(company) # 会隐含的调用str(company)"""开发模式在python脚本中直接>>>company此处是调用__repr__>>>company>>>repr(company)""" __abs__和__add__1234567891011class MyNum(object): def __init__(self, num): self.num = num def __abs__(self): return abs(self.num) num_obj = MyNum(-3)print(abs(num_obj)) # 3 12345678910111213141516class MyVector(object): def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return MyVector(self.x + other.x, self.y + other.y) def __str__(self): return f"MyVector({self.x}, {self.y})" vector1 = MyVector(1, 2)vector2 = MyVector(2, 5)print(vector1 + vector2) # MyVector(3, 7) 2-4 len函数的重要性12345print(len(list((1, 2, 3, 4))))"""len()对python原生的list/dict/set/tuple计算时,会直接读取c语言的数据,不会遍历数据性能比纯python语言高"""]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chapter01python中一切皆对象01]]></title>
<url>%2F2019%2F03%2F25%2Fchapter01python%E4%B8%AD%E4%B8%80%E5%88%87%E7%9A%86%E5%AF%B9%E8%B1%A101%2F</url>
<content type="text"><![CDATA[1-1 python一切皆对象python中一切皆对象。函数和类也是对象,属于python的一等公民。 函数和类可以赋值给一个变量 可以添加到集合对象中 可以作为参数传递给函数 可以当作函数的返回值 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-03-25"""python中一切皆对象- 函数和类也是对象,属于python的一等公民 - 函数和类可以赋值给一个变量 - 可以添加到集合对象中 - 可以作为参数传递给函数 - 可以当作函数的返回值"""def print_name(name='lisa'): print(name)class Person: def __init__(self): print('david')# 1.将函数赋值给变量my_func = print_namemy_func('bird')# 2.将类赋值给变量my_class = Personmy_class()# 3.将函数和类添加到集合对象中obj_list = []obj_list.append(print_name)obj_list.append(Person)print(obj_list)"""birddavid[<function print_name at 0x107657268>, <class '__main__.Person'>]"""# 4.可以当作函数的返回值def decorator_func(): return print_namefunc = decorator_func()func('fish') 1-2 type、object和class之间的关系 此处非常的绕,关键理解以下三点: type是一个类,也是一个实例; type类创建所有实例(函数、类都是实例对象),type类自身也是自己的实例,这就是一切皆对象; 所有的类都继承object, object又是type类的实例, type作为类也继承object; 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283"""type的作用 - 生成一个类 - 通过type可以知道是谁的实例type --> int --> 1type --> str --> 'xyz'type --> list --> [1, 2]type --> class --> object type生成class,class实例化得到对象类是由type类实例化生成的对象,我们平常熟悉的对象是由类对象创建的对象>>>a = 1>>>type(a)<class 'int'>>>>type(int)<class 'type'>>>>b = 'xyz'>>>type(b)<class 'str'>>>>type(str)<class 'type'>>>> a = [1, 2]>>> type(a)<class 'list'>>>> type(list)<class 'type'>>>> class Student:... pass...>>> stu = Student()>>> type(stu)<class '__main__.Student'>>>> type(Student)<class 'type'>object 所有类继承的最顶层的类,是一个基类的概念>>> class Student:... pass...>>> stu = Student()>>> Student.__bases__(<class 'object'>,)>>> class Student:... pass...>>> stu = Student()>>> Student.__bases__(<class 'object'>,)>>> class Mystudent(Student):... pass...>>> Mystudent.__bases__(<class '__main__.Student'>,)>>> Student.__bases__(<class 'object'>,)""""""type本身也是一个类,同时type也是一个对象type的__bases__是object>>> type.__bases__(<class 'object'>,)object这个基类对象,是由type生成的,他两互相指向对方>>>type(object)<class 'type'>object的基类是空>>> object.__bases__()""""""- type是一个类,也是一个实例;- type类创建所有实例(函数、类都是实例对象),type类自身也是自己的实例,这就是一切皆对象;- 所有的类都继承object, object又是type类的实例, type作为类也继承object;""" 1-3 python中的内置类型12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455"""python中的内置类型""""""对象的三个特征 身份 >>>id(1) 4546333872 类型 >>> type(1) <class 'int'> 值 1""""""常见类型None(全局只有一个) >>> a = None >>> b = None >>> id(a) 4546031720 >>> id(b) 4546031720数值 int float complex(复数) bool迭代类型序列类型 list bytes/bytearray/memoryview(二进制序列) range tuple str array映射类型 dict集合 set frozenset上下文管理类型 with语句其他 模块类型 class和实例 函数类型 方法类型 代码类型 object类型 type类型 ellipsis类型 notimplemented类对象"""]]></content>
<categories>
<category>Python3 Advanced Programme</category>
</categories>
<tags>
<tag>Python3 Advanced Programme</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Python并行编程:线程1]]></title>
<url>%2F2019%2F03%2F24%2Fpython%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B-%E7%BA%BF%E7%A8%8B1%2F</url>
<content type="text"><![CDATA[线程的使用线程是一个独立的执行流,系统中的多个线程可以并行及并发执行。多个线程可以共享数据与资源,利用了所谓的共享信息空间。线程与进程的具体实现取决于应用所运行的操作系统,不过一般来说,线程位于进程内,同一进程中的不同线程共享一些资源。与之相反,不同的进程则不会共享它们的资源。 一.开始使用线程demo123456789101112131415161718192021222324252627282930313233343536373839404142434445464748from threading import Threadfrom time import sleepclass CookBook(Thread): def __init__(self): Thread.__init__(self) self.message = "Hello Python CookBook!" def print_message(self): print(self.message) def run(self): print("Thread Starting\n") x = 0 while x < 10: self.print_message() sleep(2) x += 1 print("Thread Ended\n")if __name__ == '__main__': print("Process Started") hello_python = CookBook() hello_python.start() # 启动线程 print("Process Ended")"""Process StartedThread StartingHello Python CookBook!Process EndedHello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Hello Python CookBook!Thread Ended""" 二.基于线程的并行 关于并行和并发的认识https://laike9m.com/blog/huan-zai-yi-huo-bing-fa-he-bing-xing,61/ 1.如何定义线程demo1234567891011121314import threadingdef function(i): print(f'function called by thread {i}') returnthreads = []for i in range(5): t = threading.Thread(target=function, args=(i, )) threads.append(t) t.start() # 线程开始执行 t.join() # 调用线程等待,直到线程执行完毕 1234567Thread(group=None, target=None, name=None, args=(), kwargs={})group: 这是group的值,应该为None;这是一个保留参数,供未来实现所用。target: 这是一个在启动一个线程活动时将会执行的函数。 name: 线程的名字;在默认情况下,形式为Thread-N的唯一的名字会赋给它。 args: 这是传给目标的一个参数元组。 kwargs: 这是一个关键字参数字典,供目标函数所用。 2.如何确定当前线程demo12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-03-24import threadingimport timedef first_function(): print(threading.current_thread().getName() + ' is Starting!\n') time.sleep(2) print(threading.current_thread().getName() + ' is Exiting!\n') returndef second_function(): print(threading.current_thread().getName() + ' is Starting!\n') time.sleep(2) # 通过time模块来暂停线程2秒 print(threading.current_thread().getName() + ' is Exiting!\n') returndef third_function(): print(threading.current_thread().getName() + ' is Starting!\n') time.sleep(2) print(threading.current_thread().getName() + ' is Exiting!\n') returnif __name__ == '__main__': t1 = threading.Thread(target=first_function, name='first_function') t2 = threading.Thread(target=second_function, name='second_function') t3 = threading.Thread(target=third_function, name='third_function') t1.start() t2.start() t3.start() t1.join() t2.join() t3.join()"""不加join()first_function is Starting!second_function is Starting!third_function is Starting!first_function is Exiting!third_function is Exiting!second_function is Exiting!""""""加join(), 去掉time.sleep(2)first_function is Starting!first_function is Exiting!second_function is Starting!second_function is Exiting!third_function is Starting!third_function is Exiting!""" 3.如何在子类中实现线程demo1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162import _threadimport threadingimport timeexitFlag = 0class MyThread(threading.Thread): def __init__(self, threadID, name, counter): threading.Thread.__init__(self) self.threadID = threadID self.name = name self.counter = counter def run(self): print('Starting ' + self.name) print_time(self.name, self.counter, 5) print("Exiting " + self.name)def print_time(threadName, delay, counter): while counter: if exitFlag: _thread.exit() time.sleep(delay) print(f"{threadName}: {time.ctime()}") counter -= 1# 创建新线程thread1 = MyThread(1, 'Thread-1', 1)thread2 = MyThread(2, 'Thread-2', 2)# 启动新线程thread1.start() # 运行start()会调用run()thread2.start()thread1.join()thread2.join()print('Exiting Main Thread')"""Starting Thread-1Starting Thread-2Thread-1: Sun Mar 24 21:39:43 2019Thread-2: Sun Mar 24 21:39:44 2019Thread-1: Sun Mar 24 21:39:44 2019Thread-1: Sun Mar 24 21:39:45 2019Thread-2: Sun Mar 24 21:39:46 2019Thread-1: Sun Mar 24 21:39:46 2019Thread-1: Sun Mar 24 21:39:47 2019Exiting Thread-1Thread-2: Sun Mar 24 21:39:48 2019Thread-2: Sun Mar 24 21:39:50 2019Thread-2: Sun Mar 24 21:39:52 2019Exiting Thread-2Exiting Main Thread""" ······未完待续]]></content>
<categories>
<category>Python Concurrent Programming</category>
</categories>
<tags>
<tag>Python Concurrent Programming</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Asyncio]]></title>
<url>%2F2019%2F03%2F18%2Fasyncio%2F</url>
<content type="text"><![CDATA[asynciopython版本3.7+ 简单调用一个协程demo112345678910import asyncioasync def main(): print('hello') await asyncio.sleep(2) print('world')asyncio.run(main()) 123hello-->2秒后world demo2123456789101112131415161718192021222324import asyncioimport timeasync def say_later(delay, what): await asyncio.sleep(delay) print(what)async def main(): print(f"started at {time.strftime('%X')}") await say_later(1, 'hello') await say_later(2, 'world') print(f"finished at {time.strftime('%X')}")asyncio.run(main())"""started at 22:00:28helloworldfinished at 22:00:31""" demo3并发运行asyncio任务的多个协程1234567891011121314151617181920212223242526272829import asyncioimport timeasync def say_after(delay, what): await asyncio.sleep(delay) print(what)async def main(): task1 = asyncio.create_task(say_after(1, 'hello')) task2 = asyncio.create_task(say_after(2, 'world')) print(f"started at {time.strftime('%X')}") await task1 await task2 print(f"finished at {time.strftime('%X')}")asyncio.run(main())"""# 总用时2秒started at 22:06:12helloworldfinished at 22:06:14""" 可等待对象如果一个对象可以在await语句中使用,那么它就是可等待对象。可等待对象有三种主要类型:协程、任务和Future. 协程12345678910111213141516import asyncioasync def nested(): return 42async def main(): # 协程函数:定义为async def 的函数 # nested() print(await nested()) # 协程对象:调用协程函数所返回的对象asyncio.run(main())"""42""" 任务用来并发执行协程。12345678910111213import asyncioasync def nested(): return 42async def main(): task = asyncio.create_task(nested()) print(await task)asyncio.run(main()) # 42 Future 对象Future是一种特殊的低层级可等待对象,表示一个异步操作的最终结果。当一个Future对象被等待,这意味着协程将保持等待直到该Future对象在其他地方操作完毕。在asyncio中需要Future对象以便允许通过async/await使用基于回调的代码。通常情况下没有必要在应用层级的代码中创建Future对象。]]></content>
<categories>
<category>Python Concurrent Programming</category>
</categories>
<tags>
<tag>Python Concurrent Programming</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-6双向队列deque]]></title>
<url>%2F2019%2F03%2F18%2F2-6%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97deque%2F</url>
<content type="text"><![CDATA[双向队列deque123456789101112131415161718192021222324>>> from collections import deque>>> dq = deque(range(10), maxlen=10)>>> dqdeque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)>>> dq.rotate(3)# rotate()接受一个参数,当n>0将最右边的n个数移到最左边>>> dqdeque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)>>> dq.rotate(-4)# 当n<0时,将最左边的n个参数移动到最右边>>> dqdeque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)>>> dq.appendleft(-1)# 最左边添加一个数>>> dqdeque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)>>> dq.extend([11, 22, 33])# 最右边迭代着添加>>> dqdeque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)>>> dq.extendleft([10, 20, 30, 40])# 最左边迭代着添加>>> dqdeque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10) 列表和队列的方法比较]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-5列表排序/bisect模块/数组]]></title>
<url>%2F2019%2F03%2F14%2F2-5%E5%88%97%E8%A1%A8%E6%8E%92%E5%BA%8F-bisect%E6%A8%A1%E5%9D%97-%E6%95%B0%E7%BB%84%2F</url>
<content type="text"><![CDATA[list.sort方法和内置函数sortedlist.sort方法会就地排序,不会把原列表复制一份,返回值为None。sorted则相反,会新建一个列表作为返回值,接受任何形式的的可迭代对象作为参数,甚至包括不可变序列和生成器。二者都有两个可选的关键字参数: reverse,为True,倒序。默认值为False。 key,一个只有一个参数的函数,这个函数会被用到序列里的每一个元素上,所产生的结果将是排序算法依赖的对比关键字。如:key=str.lower来实现忽略大小写的排序,key=len进行基于字符串长度的排序。默认值是恒等函数,也就是默认用元素自己的值来排序。 12345678910111213141516>>> fruits = ['grape', 'raspberry', 'apple', 'banana']>>> sorted(fruits)['apple', 'banana', 'grape', 'raspberry']>>> fruits['grape', 'raspberry', 'apple', 'banana']>>> sorted(fruits, reverse=True)['raspberry', 'grape', 'banana', 'apple']>>> sorted(fruits, key=len)['grape', 'apple', 'banana', 'raspberry']>>> sorted(fruits, key=len, reverse=True)['raspberry', 'banana', 'grape', 'apple']>>> fruits['grape', 'raspberry', 'apple', 'banana']>>> fruits.sort()>>> fruits['apple', 'banana', 'grape', 'raspberry'] 用bisect来管理已经排序的序列bisect模块包含两个主要函数,bisect和insort,两个函数都利用二分查找算法来在有序序列中查找或插入元素。 用bisect来搜索bisect(haystack, needle) 在 haystack(干草垛)里搜索 needle(针)的位置,该位置满足的条件是,把 needle 插入这个位 置之后,haystack 还能保持升序。也就是在说这个函数返回的位置前 面的值,都小于或等于 needle 的值。其中 haystack 必须是一个有 序的序列。你可以先用 bisect(haystack, needle) 查找位置 index,再用 haystack.insert(index, needle) 来插入新值。 但你也可用 insort 来一步到位,并且后者的速度更快一些。 12345678910111213141516171819202122232425262728293031323334353637383940414243import bisectimport sysHAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'def demo(bisect_fn): for needle in reversed(NEEDLES): position = bisect_fn(HAYSTACK, needle) # 用特定的bisect函数来计算元素应该出现的位置 offset = position * ' |' # 利用该位置来算出需要几个分割符号 print(ROW_FMT.format(needle, position, offset)) # 把元素和其对应的位置打印出来if __name__ == '__main__': if sys.argv[-1] == 'left': # 根据命令上最后一个参数来选用bisect函数 bisect_fn = bisect.bisect_left else: bisect_fn = bisect.bisect print('DEMO:', bisect_fn.__name__) # 把选定的函数在抬头上打印出来 print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK)) demo(bisect_fn)"""DEMO: bisecthaystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 3031 @ 14 | | | | | | | | | | | | | |3130 @ 14 | | | | | | | | | | | | | |3029 @ 13 | | | | | | | | | | | | |2923 @ 11 | | | | | | | | | | |2322 @ 9 | | | | | | | | |2210 @ 5 | | | | |10 8 @ 5 | | | | |8 5 @ 3 | | |5 2 @ 1 |2 1 @ 1 |1 0 @ 0 0 """ 根据一个分数找到它对应的成绩12345678910import bisectdef grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'): i = bisect.bisect(breakpoints, score) # 将score插入到列表中,使得它前面的数都比它小,返回它的索引 return grades[i]grade_li = [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]print(grade_li) # ['F', 'A', 'C', 'C', 'B', 'A', 'A'] 用bisect.insort插入新元素insort可以保持有序序列的顺序1234567891011121314151617181920212223import bisectimport randomSIZE=7random.seed(1729)my_list = []for i in range(SIZE): new_item = random.randrange(SIZE*2) bisect.insort(my_list, new_item) print('%2d ->' % new_item, my_list)"""10 -> [10] 0 -> [0, 10] 6 -> [0, 6, 10] 8 -> [0, 6, 8, 10] 7 -> [0, 6, 7, 8, 10] 2 -> [0, 2, 6, 7, 8, 10]10 -> [0, 2, 6, 7, 8, 10, 10]""" 可以替换列表的数据结构数组如果我们需要一个只包含数字的列表,那么array.array比list更高效。数组支持所有跟可变序列有关的操作,包括.pop、.insert和.extend。另外,数组还提供从文件读取和存入文件的更快的方法,如.frombytes和.tofile。12345678910111213141516171819202122232425from array import array # 引入array对象from random import randomfloats = array('d', (random() for i in range(10**7))) # 利用可迭代对象建立双精度浮点数组print(floats[-1]) # 0.39453872600664874, 查看数组最后一个元素fp = open('floats.bin', 'wb')floats.tofile(fp) # 将数组写入文件fp.close()floats2 = array('d')fp = open('floats.bin', 'rb')floats2.fromfile(fp, 10**7) # 把1000万个浮点数从二进制文件中读取出来fp.close()print(floats2[-1]) # 0.39453872600664874, 查看最后一个元素print(floats == floats2) # True 检查两个数组的内容是否完全一样"""小试验告诉我,用 array.fromfile 从一个二进制文件里读出 1000 万个双精度浮点数只需要 0.1 秒,这比从文本文件里读取的速度要快 60 倍,因为后者会使用内置的 float 方法把每一行文字转换成浮点数。另外,使用 array.tofile 写入到二进制文件,比以每行一个浮点数 的方式把所有数字写入到文本文件要快 7 倍。另外,1000 万个这样的 数在二进制文件里只占用 80 000 000 个字节(每个浮点数占用8个字 节,不需要任何额外空间),如果是文本文件的话,我们需要 181 515 739 个字节。""" 数组功能总结]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-4切片/+*/序列增量赋值]]></title>
<url>%2F2019%2F03%2F13%2F2-4%E5%BA%8F%E5%88%97%E6%9E%84%E6%88%90%E7%9A%84%E6%95%B0%E7%BB%8404%2F</url>
<content type="text"><![CDATA[切片为什么切片和区间会忽略最后一个元素在切片和区间操作不包含区间范围的最后一个元素是Python的风格,这个习惯符合Python、C和其他语言里以0作为起始下标的传统。这样做带来的好处如下: 当只有最后一个位置信息时,我们也可以快速看出切片和区间里有几个元素:range(3)和my_list[:3]都返回 3 个元素。 当起止位置信息都可见时,我们可以快速计算出切片和区间的长度,用后一个数减去第一个下标(stop - start)即可。 这样做也让我们可以利用任意一个下标来把序列分割成不重叠的两部分,只要写成my_list[:x]和 my_list[x:]就可以了,如下所示: 12345>>>l = [10, 20, 30, 40, 50, 60]>>>l[:2] # 在下标为2的地方分割[10, 20]>>>l[2:][30, 40, 50, 60] 对字符串进行切片1234567>>>s = 'bicycle'>>>s[::3]'bye'>>>s[::-1]'elcycib'>>>s[::-2]'eccb' 给切片赋值12345678910111213141516>>> l = list(range(10))>>> l[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>>> l[2:5] = [20, 30]>>> l[0, 1, 20, 30, 5, 6, 7, 8, 9]>>> del l[5:7]>>> l[0, 1, 20, 30, 5, 8, 9]>>> l[2:5] = 100 # 必须是一个可迭代对象Traceback (most recent call last): File "<input>", line 1, in <module>TypeError: can only assign an iterable>>> l[2:5] = [100]>>> l[0, 1, 100, 8, 9] 对序列使用+和*123456789>>> l = [1, 2, 3]>>> l * 3[1, 2, 3, 1, 2, 3, 1, 2, 3]>>> 5 * 'abcd''abcdabcdabcdabcdabcd'>>> l1 = [1, 2]>>> l2 = [3, 4]>>> l1 + l2[1, 2, 3, 4] 此处有坑1234567# 示例一>>> board = [['-'] * 3 for i in range(3)]>>> board[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]>>> board[1][2] = 'X'>>> board[['-', '-', '-'], ['-', '-', 'X'], ['-', '-', '-']] 1234567# 示例二>>> weird_board = [['-'] * 3] * 3>>> weird_board[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]>>> weird_board[1][2] = 'X'>>> weird_board[['-', '-', 'X'], ['-', '-', 'X'], ['-', '-', 'X']] 1234567891011121314示例二中外面的列表其实包好了3个指向同一个列表的引用。类似例子如下:```python# 与上述示例一相同>>> board = []>>> for i in range(3):... row = ['-'] * 3... board.append(row)... >>> board[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]>>> board[1][2] = 'X'>>> board[['-', '-', '-'], ['-', '-', 'X'], ['-', '-', '-']] 1234567891011# 与上述示例二类同>>> row = ['-'] * 3>>> board = []>>> for i in range(3):... board.append(row)... >>> board[['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']]>>> board[1][2] = 'X'>>> board[['-', '-', 'X'], ['-', '-', 'X'], ['-', '-', 'X']] 序列的增量赋值+=背后的特殊方法是__iadd__(用于“就地加法”)。但是如果一个类没有实现这个方法的话,Python会退一步调用__add__。考虑下面这个简单的表达式:1a += b 如果a实现了__iadd__方法,就会调用这个方法。同时对可变序列(例如list、bytearray和array.array)来说,a会就地改动,就像调用了a.extend(b) 一样。但是如果a没有实现__iadd__的话,a += b这个表达式的效果就变得跟a = a + b一样了:首先计算a + b,得到一个新的对象,然后赋值给a。就是说,在这个表达式中,变量名会不会被关联到新的对象,完全取决于这个类型有没有实现 __iadd__这个方法。 总体来讲,可变序列一般都实现了__iadd__方法,因此+= 是就地加法。而不可变序列根本就不支持这个操作,对这个方法的实现也就无从谈起。1234567891011121314>>> l = [1, 2, 3]>>> id(l)4350343496 # 刚开始时列表的ID>>> l *= 2>>> id(l)4350343496 # 运用增量乘法,列表的ID不变,新元素追加到列表>>> t = (1, 2, 3)>>> id(t) # 刚开始时元组的ID4472300384>>> t *= 2>>> t(1, 2, 3, 1, 2, 3)>>> id(t)4469680744 # 运用增量乘法后,新的元组被创建 一个谜题1234567>>> t = (1, 2, [30, 40])>>> t[2] += [50, 60]Traceback (most recent call last): File "<input>", line 1, in <module>TypeError: 'tuple' object does not support item assignment>>> t(1, 2, [30, 40, 50, 60]) 解释: t[2] += [50, 60]能完成是因为指向了一个可变对象; 抛出异常是因为元组不可变,赋值时报错;教训: 不要把可变对象放在元组中; 增量赋值不是一个原子操作,虽然抛出了异常,但是还是完成了操作。]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-3 元组]]></title>
<url>%2F2019%2F03%2F11%2F2-3%E5%85%83%E7%BB%84%2F</url>
<content type="text"><![CDATA[文中源码来源于《流畅的python》, 仅用来学习,特此说明。 用生成器表达式计算笛卡尔积用生成器表达式内存中不会留下一个有6个组合的列表,因为生成器会在每次for循环运行时,才会生成一 个组合。1234567891011121314colors = ['black', 'white']sizes = ['S', 'M', 'L']for shirt in ('%s %s' % (c, s) for c in colors for s in sizes): print(shirt)"""result:black Sblack Mblack Lwhite Swhite Mwhite L""" 元组和记录元组其实是对数据的记录:元组中的每个元素都存放了记录中一个字段的数据,外加这个字段的位置。如果把元组理解为不可变的列表,那么它所含有的元素的总数和位置信息就变得可有可无。如果把元组当作字段的集合,那么位置和数量就变得非常重要。123456789101112131415161718192021lax_coordinates = (33.9425, -118.408056) # 洛杉矶国际机场的经纬度city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014) # 东京的市民/年份/人口(百万)/人口变化/面积traveler_ids = [('USA', '31195855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]for passport in sorted(traveler_ids): print('%s/%s' % passport)"""country_code/passport_numberBRA/CE342567ESP/XDA205856USA/31195855"""for country, _ in traveler_ids: print(country)"""拆包:元组第二个元素对于我们没有用,用'_'作为占位符USABRAESP""" 元组拆包元组拆包可以运用到任何可迭代对象上,唯一的硬性要求就是被可迭代对象中的元素的数量必须要和接受这些元素的元组的空档数一致。 平行赋值12345# 平行赋值lax_coordinates = (33.9425, -118.408056)latitude, longitude = lax_coordinatesprint(latitude) # 33.9425print(longitude) # -118.408056 12# 不使用中间变量交换两个变量的值b, a = a, b 123456# 用*运算符把一个可迭代对象拆开作为函数的参数print(divmod(20, 8)) # (2, 4)t = (20, 8)print(divmod(*t)) # (2, 4)quotient, remainder = divmod(*t)print(quotient, remainder) # 2 4 1234567# os.path.split()函数返回路径和最后一个文件名组成的元组(path, last_part)import os_, filename = os.path.split('/home/local/test.py')print(filename) # test.pyprint(_) # /home/local 用*来处理剩下的元素经典写法12345678a, b, *rest = range(5)print(a, b, rest) # 0 1 [2, 3, 4]a, b, *rest = range(3)print(a, b, rest) # 0 1 [2]a, b, *rest = range(2)print(a, b, rest) # 0, 1, [] 在平行赋值中,*只能作用于一个变量名的前面,但是这个变量可以出现在赋值表达式的任何位置。12345a, *body, c, d = range(5)print(a, body, c, d) # 0 [1, 2] 3 4*head, b, c, d = range(5)print(head, b, c, d) # [0, 1] 2 3 4 嵌套元组拆包1234567891011121314151617181920metro_areas = [ ('Tokyo', 'JP', 36.933, (35.6876, 139.2343)), ('Delhi Ncy', 'IN', 21.936, (28.1324, 77.2324)), ('New York-Newark', 'US', 20.104, (40.808611, -74.022433)), ('Sao Paulo', 'BR', 19.649, (-23.54778, -46.3424))]print('{:15} | {:^9} | {:^9}'.format('', 'lat.', 'long.'))""" | lat. | long."""fmt = '{:15} | {:9.4f} | {:9.4f}'for name, cc, pop, (latitude, longitude) in metro_areas: if longitude <= 0: print(fmt.format(name, latitude, longitude))"""New York-Newark | 40.8086 | -74.0224Sao Paulo | -23.5478 | -46.3424""" 具名元组12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152# 定义和使用具名元组from collections import namedtupleCity = namedtuple('City', 'name country population coordinates')"""namedtuple需要两个参数,一个是类名,另一个是类各个字段的名字。后者可以是有数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。City = namedtuple('City', ['name', 'country', 'population', 'coordinates'])"""tokyo = City('Tokyo', 'JP', 36.933, (35.687433, 139.691737))"""存放在对应字段中的数据要以一串参数的形式传入到构造函数中元组的传入只接受单一的可迭代对象"""print(tokyo)"""tokyo = City(name='Tokyo', country='JP', population=36.933, coordinates=(35.687433, 139.691737))"""print(tokyo.population) # 36.933print(tokyo.coordinates) # (35.687433, 139.691737)print(tokyo[1]) # JP# 具名元组的属性和方法print(City._fields) # ('name', 'country', 'population', 'coordinates')LatLong = namedtuple('LatLong', ['lat', 'long'])delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.623722, 77.234242))delhi = City._make(delhi_data)"""_make通过接受一个可迭代对象来生成这个类的一个实例,它的作用和City(*delhi_data)是一样的。"""print(delhi._asdict())"""_asdict()把具名元组以collections.OrderedDict的形式返回,可以友好的呈现信息。""""""OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935),('coordinates', LatLong(lat=28.623722, long=77.234242))])"""for key, value in delhi._asdict().items(): print(key + ':', value)"""name: Delhi NCRcountry: INpopulation: 21.935coordinates: LatLong(lat=28.623722, long=77.234242)""" 作为不可变列表的元组]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-2 内置序列和列表推导式]]></title>
<url>%2F2019%2F03%2F10%2F%E5%86%85%E7%BD%AE%E5%BA%8F%E5%88%97%E5%92%8C%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E5%BC%8F%2F</url>
<content type="text"><![CDATA[内置序列分类 按照是否可以存放多种类型分类 容器序列 list、tuple、collections.deque这些序列可以存放不同的数据类型。 扁平序列 str、bytes、bytearray、memoryview和array.array,这些序列只能容纳一种类型。 按照序列类型能否被修改分类 可变序列 list、bytearray、array.array、collections.deque和memory view。 不可变序列 tuple、str、bytes。 列表推导式12345678910111213141516# ---------------列表推导式----------------"""把一个字符串变成Unicode码位的列表"""# 方式一:常规写法symbols = '$&@#^*'codes = []for symbol in symbols: codes.append(ord(symbol))print(codes)# 方式二:列表推导式codes = [ord(symbol) for symbol in symbols]print(codes) 在python2.x中,在列表推导中for关键字之后的赋值操作可能会影响列表推导上下文中的同名变量。下述例子中,x原来的值被取代了,在python3中不会出现这样的情况。 1234# 在python2.7中x = 'my precious'dummy = [x for x in 'ABC']print(x) # 'C' 12345# 在python3中x = 'ABC'dummy = [ord(x) for x in x]print(x) # 'ABC'print(dummy) # [65, 66, 67] 列表推导式、生成器表达式以及集合推导式和字典推导式,在python3中有个自己的局部作用域,就像函数似的。表达式内部的变量和赋值只在局部起作用,表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到它们。]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part2:2-1 列表推导式和生成器推导式]]></title>
<url>%2F2019%2F03%2F10%2F2-1%20%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E5%BC%8F%E5%92%8C%E7%94%9F%E6%88%90%E5%99%A8%E6%8E%A8%E5%AF%BC%E5%BC%8F%2F</url>
<content type="text"><![CDATA[使用列表推导式做过滤12345678# 用列表推导式做过滤symbols = '$&@#^*'beyond_ascii = [ord(s) for s in symbols if ord(s) > 50]print(beyond_ascii)# 用map/filter组合做过滤beyond_ascii = list(filter(lambda c: c > 50, map(ord, symbols)))print(beyond_ascii) 使用列表推导式计算笛卡尔积1234567891011121314151617# 使用列表推导计算笛卡尔积colors = ['black', 'white']sizes = ['S', 'M', "L"]tshirts = [(color, size) for color in colors for size in sizes]print(tshirts)"""result:[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]"""# 等价于tshirts = []for color in colors: for size in sizes: tshirts.append((color, size))print(tshirts) 生成器表达式1234567891011"""生成器表达式背后遵守迭代器协议,可以逐个产出元素,而不是先建立一个完整的列表然后再把这个列表传递到某个构造函数中。相比列表推导式,能够节省内存。"""# 用生成器表达式初始化元组和数组symbols = '$&@#^*'beyond_ascii = tuple(ord(s) for s in symbols)print(beyond_ascii)import arrayprint(array.array('I', (ord(symbol) for symbol in symbols)))]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Part1:python数据模型]]></title>
<url>%2F2019%2F03%2F09%2Fpython%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B%2F</url>
<content type="text"><![CDATA[纸牌 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-02-22"""Fluent Python by Luciano Ramalho(O'Reilly). Copyright 2015 Luciano Ramalho, 978-1-491-94600-8."""import collectionsimport randomCard = 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: """ return len(self._cards) def __getitem__(self, position): """ 抽取某张牌 :param position: :return: """ return self._cards[position]beer_card = Card('7', 'diamonds')print(beer_card, type(beer_card))deck = FrenchDeck()print(len(deck)) # 调用__len___方法print(deck[0]) # 调用__getitem__方法print(deck[-1])print(random.choice(deck)) # 随机抽一张牌print(deck[:3]) # 取前三张牌print(deck[12::13]) # 取四张Aprint("Card('Q', 'hearts')是否在牌中:", Card('Q', 'hearts') in deck)print("Card('7', 'beasts')是否在牌中:", Card('7', 'beasts') in deck)for card in deck: # 循环牌组 print(card)print('-' * 100)for card in reversed(deck): # 反向循环牌组 print(card)suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)def spades_high(card): rank_value = FrenchDeck.ranks.index(card.rank) return rank_value * len(suit_values) + suit_values[card.suit]print('-' * 100)for card in sorted(deck, key=spades_high): # 按照2最小,A最大, 同点数:黑桃>红桃>方块>梅花排序 print(card)print(spades_high(card=deck[1])) 简单的二维向量1234567891011121314151617181920212223242526272829303132333435#! /usr/bin/env python# -*- coding: utf-8 -*-# __author__ = "David"# Date: 2019-03-01from math import hypotclass Vector: def __init__(self, x=0, y=0): self.x = x self.y = y def __repr__(self): return 'Vector(%r, %r)' % (self.x, self.y) def __abs__(self): return hypot(self.x, self.y) def __bool__(self): return bool(abs(self)) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Vector(x, y) def __mul__(self, scalar): return Vector(self.x * scalar, self.y * scalar)v = Vector(3, 4)print(v)print(abs(v))print(abs(v * 3)) __str__与__repr__的区别 __repr__ 这个特殊方法用来得到一个对象的字符串表现形式。 交互式控制台和调试程序debugger用repr函数来获取字符串的表现形式。 在老的使用%符号的字符串格式中,这个函数返回的结果用来代替%r所代表的对象;同样,str.format函数所用到的新式字符串格式化语法也是利用repr,才把!r字段变为字符串。 __str__ 这个特殊方法是在str()函数被使用,或者是在print函数打印一个对象的时候才被调用的,并且它返回的字符串对于终端用户更加友好。 如果只想实现这两个特殊方法中的一个,__repr__是更好的选择,因为一个对象没有__str__函数,而python又需要调用它的时候,解释器会用__repr__ 作为替代。]]></content>
<categories>
<category>Fluent Python</category>
</categories>
<tags>
<tag>Fluent Python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Rabbitmq]]></title>
<url>%2F2018%2F12%2F10%2Frabbitmq%2F</url>
<content type="text"><![CDATA[简单模式123456789101112131415# producerimport pika# 获取控制rabbitmq的channel对象connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost'))channel = connection.channel()# 在rabbitmq中生成一个名为队列channel.queue_declare(queue='hello')# 向rabbitmq中名为hello的队列插入一个消息: 'Hello World!'channel.basic_publish(exchange='', routing_key='hello', body='5')print(" [x] has Sent")connection.close() 12345678910111213141516171819202122232425262728# consumerimport pika# 获取控制rabbitmq的channel对象connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))channel = connection.channel()# 在rabbitmq中生成一个名hello为队列,无则创建,有则pass# 在无法明确生产者、消费者谁先执行去,因此再次声明创建队列channel.queue_declare(queue='hello')def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time time.sleep(int(body)) # 做出应答:该删则删 ch.basic_ack(delivery_tag=method.delivery_tag)channel.basic_qos(prefetch_count=1) # 不再按照平均分配,按照资源处理的速度channel.basic_consume(callback, queue='hello', no_ack=False # 应答模式 )print(' [*] Waiting for messages. To exit press CTRL+C')channel.start_consuming() # 去队列中取值 分发模式1234567891011121314151617# producerimport pikaimport sysconnection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost'))channel = connection.channel()channel.exchange_declare(exchange='logs', exchange_type="fanout")message = "info: Hello World!"channel.basic_publish(exchange='logs', routing_key='', body=message)print(" [x] Sent %r" % message)connection.close() 12345678910111213141516171819202122232425# consumerimport pikaconnection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost'))channel = connection.channel()channel.exchange_declare(exchange='logs', exchange_type="fanout")result = channel.queue_declare(exclusive=True)queue_name = result.method.queueprint("queue_name", queue_name)channel.queue_bind(exchange='logs', queue=queue_name) # 交换机和队列绑定,每个生产者都会创建自己的队列print(' [*] Waiting for logs. To exit press CTRL+C')def callback(ch, method, properties, body): print(" [x] %r" % body)channel.basic_consume(callback, queue=queue_name, no_ack=True)channel.start_consuming() 关键字模式1234567891011121314151617# producerimport pikaimport sysconnection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost'))channel = connection.channel()channel.exchange_declare(exchange='direct_logs', exchange_type="direct")message = "info: Hello World!"channel.basic_publish(exchange='direct_logs', routing_key='info', body=message)print(" [x] Sent %r" % message)connection.close() 12345678910111213141516171819202122232425262728293031# consumerimport pikaimport sysconnection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost'))channel = connection.channel()channel.exchange_declare(exchange='direct_logs', exchange_type="direct")result = channel.queue_declare(exclusive=True)queue_name = result.method.queuechannel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key="info")print(' [*] Waiting for logs. To exit press CTRL+C')def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body))channel.basic_consume(callback, queue=queue_name, no_ack=True)channel.start_consuming()]]></content>
<categories>
<category>消息队列</category>
</categories>
<tags>
<tag>rabbitmq</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hello World]]></title>
<url>%2F2018%2F12%2F02%2Fhello-world%2F</url>
<content type="text"><![CDATA[Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new "My New Post" More info: Writing Run server 1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment]]></content>
</entry>
</search>