# 这3种数组内的字典去重方式 你会几种？

```test = [{"a": 1}, {"a": 1}, {"a": 3}, {"b": 4}]
test = list(set(test))
>>>TypeError: unhashable type: 'dict'```

## 1.使用reduce方法

reduce() 函数会对参数序列中元素进行累积。

```from functools import reduce
>>>def add(x, y) :            # 两数相加
...    return x + y
...
15```

```from functools import reduce
>>> reduce(lambda x, y: x+y, [1,2,3,4,5])  # 使用 lambda 匿名函数
15```

```from functools import reduce

data = [{"a": 1}, {"a": 1}, {"a": 3}, {"b": 4}]
result = []
def unduplicate(result, data):
if data not in result:
result = result + [data]
return result

for i in data:
result = unduplicate(result, i)

>>> result
>>> [{'a': 1}, {'a': 3}, {'b': 4}]```

```def delete_duplicate(data):
func = lambda x, y: x + [y] if y not in x else x
data = reduce(func, [[], ] + data)
return data

>>> delete_duplicate(data)
>>> [{'a': 1}, {'a': 3}, {'b': 4}]```

`data = reduce(lambda x, y: x + [y] if y not in x else x, [[], ] + data)`

## 2.奇怪的技巧

```data = [{"a": 1}, {"a": 1}, {"a": 3}, {"b": 4}]
def delete_duplicate(data):
immutable_dict = set([str(item) for item in data])
data = [eval(i) for i in immutable_dict]
return data
>>> delete_duplicate(data)
>>> [{'a': 1}, {'a': 3}, {'b': 4}]```

1.遍历字典，将每个子项变成字符串存放到数组中，再通过set函数去重。

2.通过eval函数，将去重后的数组里的每个子项重新转化回字典。

## 3.高效的方式

```data = [dict(t) for t in set([tuple(d.items()) for d in data])]
>>>data
>>>[{'a': 1}, {'b': 2}]```

`data2 = [{"a": {"b": "c"}}, {"a": {"b": "c"}}]`

```data2 = [{"a": {"b": "c"}}, {"a": {"b": "c"}}]
def delete_duplicate_str(data):
immutable_dict = set([str(item) for item in data])
data = [eval(i) for i in immutable_dict]
return data
print(delete_duplicate_str(data2))

>>> [{'a': {'b': 'c'}}]```

¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )

# Python 小坑之字符串驻留

```# example1:
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True

# example2:
>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False

# example3:
>>> a, b = "wtf!", "wtf!"
>>> a is b
True # 3.7 版本返回结果为 False. ```
```# example4:
>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
True
>>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
False # 3.7 版本返回结果为 True  ```

https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19

1.所有长度为0和1的字符串都会被驻留

2.字符串在编译时被实现的会被驻留（如’wtf’会被驻留，但是 ”.join([‘w’, ‘t’, ‘f’]) 不会）

3.字符串中只包含ASCII下的字母、数字和下划线时会被驻留. 所以’wtf!’由于包含!不会被驻留。

a和b都为wtf!时：

```>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False
>>> a == b
True
>>> id(a)
2272774097864
>>> id(b)
2272774097024  ```

```# a和b都为wtf
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True
>>> a == b
True
>>> id(a)
2272774096744
>>> id(b)
2272774096744 ```

example4中，发生了常量折叠，这其实也是一种优化技术。编译时表达式 ‘a’*20 会被替换成 ‘aaaaaaaaaaaaaaaaaaaa’ （不要数了，20个），不过只有长度小于20的字符串才会发生常量替换，这就是为什么 ‘a’*21并不等于 ‘aaaaaaaaaaaaaaaaaaaaa’ （不要数了，21个） 。

```>>> a = 10
>>> b = 10
>>> a is b
True
>>> a = 256
>>> b = 256
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False ```

​Python实用宝典 (pythondict.com)

# Python 重载与重写 及 泛型函数

1.一个类里面

2.方法名字相同

3.参数不同

## 重写：

1.参数列表与原函数一致。

2.返回类型与原函数一致。

Python其实不需要重载这个概念。为什么呢？重载主要是针对参数而言的，一个是改变参数的类型，一个是改变参数的个数。而Python不需要限定参数类型，又 可以接受可变参数，因此函数重载就显得非常鸡肋了。

```from functools import singledispatch

@singledispatch
def fun(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg) ```

```@fun.register(int)
def _(arg: int, verbose=False):
if verbose:
print("Strength in numbers, eh?", end=" ")
print(arg)

@fun.register(list)
def _(arg: list, verbose=False):
if verbose:
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem) ```

```>>> fun(42, verbose=True)
Strength in numbers, eh? 42

>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
Enumerate this:
0 spam
1 spam
2 eggs
3 spam ```

​Python实用宝典 (pythondict.com)

# 快来用Python制作只属于你和ta的聊天渠道吧

## 2.代码编写

### 2.1 服务器端

```import socket
import traceback
# 设定ip和端口号
host = ''
port = 51423
# 建立socket服务器
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
s.listen()
while True:
# 等待连接
try:
except KeyboardInterrupt:
raise
except:
traceback.print_exc()
continue ```

```# 建立接收线程

# 建立发送线程

clientsock就是我们得到的socket连接，processRecv和processSend分别用于处理接受信息和处理发送信息：

```import _thread
def processRecv(clientsock):
"""
接受消息
:param clientsock: 客户端的socket连接
"""
while True:
data = clientsock.recv(4096)
if not len(data):
break
print (data.decode('utf-8'))
clientsock.close()

def processSend(clientsock):
"""
发送消息
:param clientsock: 客户端的socket连接
"""
while True:
data = input("> ")
data = data
clientsock.sendall(data.encode('utf-8'))
clientsock.close() ```

### 2.2 客户端

```#-*-coding:utf-8-*-

import sys
from socket import *

def send_message(tcpCliSock):
"""
发送信息
:param tcpCliSock: 与服务端的socket连接
"""
while True:
message = input('> ')
if not message:
break
tcpCliSock.send(message.encode('utf-8'))

tcpCliSock.close()

if(len(sys.argv) < 3):
HOST = 'localhost'
PORT = 51423
else:
HOST = sys.argv[1]
PORT = int(sys.argv[2])

BUFSIZ = 1024

tcpCliSock = socket(AF_INET,SOCK_STREAM)

# 建立发送消息的线程

while True:
rdata = tcpCliSock.recv(BUFSIZ)
if not rdata:
break
print (rdata.decode('utf-8'))

tcpCliSock.close() ```

python client.py 127.0.0.1 51423

## 3. 改进

​Python实用宝典 (pythondict.com)

# Python生成器不该这么用

```In [66]: def f1(x):
....:     return sum(c in '02468' for c in str(x))
....:
In [68]: x = int('1234567890'*50)
In [69]: %timeit f1(x)
10000 loops, best of 5: 52.2 µs per loop```

```In [67]: def f2(x):
....:     return sum([c in '02468' for c in str(x)])
....:
In [70]: %timeit f2(x)
10000 loops, best of 5: 40.5 µs per loop ```

```In [71]: def f3(x):
....:     return sum([True for c in str(x) if c in '02468'])
....:
In [72]: %timeit f3(x)
10000 loops, best of 5: 34.9 µs per loop```

34.9微秒，Perfect! 不仅如此，还能继续加速！sum对于整数有一个快速路径，但是这个快速路径只激活类型为int的变量. bool不行，因此我们把True改成1，能再加一次速！

```In [73]: def f4(x):
....:     return sum([1 for c in str(x) if c in '02468'])
....:
In [74]: %timeit f4(x)
10000 loops, best of 5: 33.3 µs per loop```

​Python实用宝典 (pythondict.com)

# Python里Yield关键词的作用

## 迭代器

```>>> mylist = [1, 2, 3]
>>> for i in mylist:
...    print(i)
1
2
3```

mylist是一个可迭代的对象。当你使用列表解析式时，你创建了一个列表，因此也是一个迭代器:

```>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
...    print(i)
0
1
4```

## 生成器

```>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
...    print(i)
0
1
4```

## Yield

yield是一个与return类似的关键字，只是函数将返回一个生成器

```>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4```

for函数第一次调用从函数创建的生成器对象时，它将从头运行函数中的代码，直到达到yield，然后返回循环的第一个值。然后，彼此调用将再次运行您在函数中编写的循环，并返回下一个值，直到没有要返回的值为止，就如我们上面的例子所示。

​Python实用宝典 (pythondict.com)

# Vscode 设置中文

1. 首先打开vscode界面，点击View – Command Palette (或输入 Ctrl + shift + P)进入命令面板.

2. 然后输入 configure language, 选择Configure Display Language (配置显示语言)。

3. 然后查看有没有zh-cn的选项，如果有，直接选择zh-cn替换，然后按照提示重启vscode就能看到界面变回中文了。

VsCode系列文章：

Python 使用VS Code进行调试

VSCode 设置中文

Python 编程的最好搭档—VSCode 详细指南

​Python实用宝典 (pythondict.com)

# Python字符(ascii,unicode)与数字转化方法

Python中字符和数字的转换主要有两种形式：

ord() : 将字符转为数字

```ord('a')
# 97```

chr()：将数字转为字符

```char(97)
# a```

ord(): unicode转数字

```ord(u'\u1111')
# 4369```

hex(): 数字转unicode字符

```a = hex(4369)
# 0x1111
u = chr(a)
# ᄑ```