pytho的if,for等代码块是没有单独的block作用域的:Python循环语句中的索引变量作用域
若要在循环内部修改正在遍历的序列(例如复制某些元素),建议您首先制作副本。在序列上循环不会隐式地创建副本。切片表示法使这尤其方便:
>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
类似的,如果需要循环删除list元素时,正序遍历删除remove时容易发生越界、漏删的等问题,此时需要使用切片制作副本,但需要额外空间,不如倒序遍历pop删除,
a
[1, 2, 3]
b
[4, 5, 6]
zipped = zip(a, b)
zip(*zipped)
<zip object at 0x0000000003643DC8>
list(zip(*zipped))
[]
zipped = list(zip(a, b))
zip(*zipped)
<zip object at 0x00000000036434C8>
list(zip(*zipped))
[(1, 2, 3), (4, 5, 6)]
装饰器不影响被装饰函数传参,或改变传入参数(第一个):
def hello(f):
def name(*args, **kw):
*args, = ('hello ' + args[0] + '.',)
# 这里args由元组变成列表,(*args是字符串)但能实现功能
return f(*args, **kw)
return name
# 添加功能:say 'hello' to 'w', adding '.'
@hello
def f(w):
print(w)
运行结果:
f('world')
hello world.
# 如果是传递两个参数:
@hello
def g(person, content):
print(person, content)
g('world', content='ok')
hello world. ok
通过赋值给装饰器,wraps保存被装饰函数(或类)的属性,如__name__, __doc__属性
from functools import wraps
def hello(f):
@wraps(f)
def name(*args, **kw):
*args, = ('hello ' + args[0] + '.',)
return f(*args, **kw)
return name
@hello
def f(w):
print(w)
print(f.__name__)
装饰器带参数(多嵌套一层即可),实现计数器功能
import time
from functools import wraps
# 装饰器工厂
def timer(func=None):
# 装饰器
def deco(f):
@wraps(f)
# 装饰工具
def inner(*args, **kw):
start = time.time()
if f.__name__ == func:
f(*args, **kw)
print('%s cost %.2f s' % (func,float(time.time()-start)))
return f(*args, **kw)
return inner
return deco
@timer(func='fun1')
def fun1():
time.sleep(0.11)
@timer(func='fun2')
def fun2():
time.sleep(0.22)
fun1()
fun2()
导入模块__import__
>>> time = __import__('time')
>>> time
<module 'time' (built-in)>
为了暴露某些模块,方便使用,包的__intit__.py文件导入子包子模块(以及方法)
# from .子包 import 子包的模块
from 当前包.子包 import 子包的模块
# from .子包.子包的模块 import 子包的模块的方法
from 当前包.子包.子包的模块 import 子包的模块的方法
from 当前包 import 子模块
from 当前包.子模块 import 子模块的方法
子包导入大包的模块:
from 大包.大包的模块 import 大包的模块的方法
也可以相对导入,但是路径不能到大包之外:
from . .. ... import 模块
from . .. ...模块 import 方法
异常只能捕捉一次,被最近的except捕捉
def f():
try:
a = 2/0
finally:
pass
try:
f()
except:
print('return to normal')
return to normal
def f():
try:
a = 2 / 0
except Exception as e:
print(e)
finally:
pass
try:
f()
except:
print('return to normal')
division by zero
重写初始化方法
class A:
def __init__(self, x):
self.x = x+1
class B(A):
def __init__(self, x, y, z):
super().__init__(x)
# 或者是 A.__init__(self,x)
# self.x = x 这一句代表是否重写父类初始化方法
self.y = y
self.z = z
b = B(11, 22, 33)
print(b.x, b.y, b.z)
repr不改变(保护)原字符串内的对象
s = '1+1'
ss = repr(s)
ss
"'1+1'"
eval(ss)
'1+1'
eval(eval(ss))
2
ss = str(s)
ss
'1+1'
eval(ss)
2
__repr__在运算符重载中的应用
class N:
def __init__(self, v):
self.v = v
def __repr__(self):
return 'N(%s)' % self.v
def __sub__(self, other):
for i in other.v:
if i in self.v[:]:
self.v = self.v.replace(i, '')
return N(self.v)
n1 = N('113322')
n2 = N('21')
print(n1-n2)
N(33)
可迭代对象与迭代器的使用,参考《fluent Python 14.3 典型的迭代器》
class Fib:
def __init__(self, n):
self.n = n
# 可迭代对象的__iter__返回迭代器FibIter的实例
def __iter__(self):
return FibIter(self.n)
class FibIter:
def __init__(self, n):
self.n = n
self.a = 1
self.b = 0
self.i = 1
# 迭代器的__next__的return每次产出元素,最终StopIteration
def __next__(self):
if self.i > self.n:
raise StopIteration
self.a, self.b = self.a + self.b, self.a
self.i += 1
return self.b
# 迭代器的__iter__返回迭代器本身
# 迭代器的__iter__也可以是生成器函数(使用yield产出元素即可),此时迭代器是生成器对象
def __iter__(self):
return self
print(iter(FibIter(6)))
it = iter(Fib(6))
print(next(it))
for i in Fib(6):
print(i)
print([x for x in Fib(10)])
print(sum(Fib(10)))
旋转显示进度小动画
import sys
import time
ls = ['-','\\','|','/']
while True:
for i in ls:
sys.stdout.write(i)
sys.stdout.flush()
sys.stdout.write('\r')
sys.stdout.write(' ')
time.sleep(0.1)
Python在Window中使用multiprocessing模块
p = Process(target=test)
前面加上 if __name__=="__main__":
语句,才不会报错
ubuntu安装vim
这编辑器碉堡,当时看到dd,yy,p这些命令,卧槽简直惊为天人,好了不BB了,vi tab,可以看到目前系统中只安装了vi和vim.tiny,那么
安装sudo apt-get install vim-gtk
配置sudo vim /etc/vim/vimrc
Vim入门教程
set nu
set tabstop=4
set shiftwidth=4
set nobackup
set ruler
set autoindent
inoremap ( ()<ESC>i
inoremap [ []<ESC>i
inoremap { {}<ESC>i
inoremap ' ''<ESC>i
inoremap " ""<ESC>i
创建进程类
#!/usr/bin/python3
import time
from multiprocessing import Process
class ClockProcess(Process):
def __init__(self, value):
Process.__init__(self)
# 或者写成super(ClockProcess,self).__init__()
# 或者写成super().__init__()
# 不能写成super().__init__(v),因为Process类的初始化不需要参数,__init__(self, group=None, target=None, name=None, args=(), kwargs={})
# 否则AssertionError: group argument must be None for now
self.value = value
def run(self):
for i in range(10):
print(time.ctime())
time.sleep(self.value)
p = ClockProcess(1)
p.start()
p.join()
共享内存字符串
from ctypes import c_char
arr = Array(c_char,b'ab c' )
或者直接:
arr = Array('c',b'ab c' )
进程锁Lock
#!/usr/bin/python3
import time
from random import random
from multiprocessing import Lock
lock = Lock()
def f():
for i in range(1, 8):
with lock:
print('f',i)
time.sleep(random())
def g():
for i in range(3, 12):
with lock:
print(' g',i)
time.sleep(random())
p1 = Process(target=f)
p2 = Process(target=g)
p1.start()
p2.start()
p1.join()
p2.join()
将脚本改成自定义命令运行
先改权限chmod 777 ~/PycharmProjects/PJT/hello.py
再加上解释器#!/usr/bin/python3
此时就可以./hello.py
直接运行文件了
然后cd /usr/bin/
做软连接sudo ln -s ~/PycharmProjects/PJT/hello.py hello
使用hello
命令就可以运行脚本,并使用命令行参数了
tcp server重用端口号(取消内核暂时保留)
tcp.setsocket(SOL_SOCKET, SO_REUSEADDR, 1)
此时tcp.getsocket(SOL_SOCKET, SO_REUSEADDR
即为1
关于多线程安全问题的考虑
对于作为全局变量的可变对象,作为Thread类的参数传入,在每个线程中是会产生修改的
from threading import Thread
def f(ls):
ls += [1]
print(ls, id(ls))
ls = [11]
for i in range(3):
thd = Thread(target=f, args=(ls,))
thd.start()
print(id(ls))
运行结果
[11, 1] 139882005725704
[11, 1, 1] 139882005725704
[11, 1, 1, 1] 139882005725704
139882005725704
对于数字,相对应的,是不会产生修改的,当然这个例子里数字11
和12
会产生驻留,但是不影响我的展示
from threading import Thread
def f(ls):
ls += 1
print(ls, id(ls))
ls = 11
for i in range(3):
thd = Thread(target=f, args=(ls,))
thd.start()
print(id(ls))
12 10914720
12 10914720
10914688
12 10914720
threading tcp server这篇文章中,主进程中创建多个子线程,对主进程循环里的每一次tcp.accept()
得到的新的套接字描述符cli
进行处理,运行结果似乎没问题,那可以说是安全的吗?
Terminator
Ctrl-Shift-o: 水平分割屏幕
Ctrl-Shift-e: 垂直分割屏幕
Ctrl-Shift-t: 打开新的终端窗口
Ctrl-Shift-w: 关闭当前终端窗口
Ctrl-Shift-q: 退出Terminator
vmware虚拟机突然断网,恢复默认网络设置,然后保留了nat模式。
ifconfig 发现没有eth0,于是:
进入root,ifconfig eth0 up
,于是有了eth0;
去网络配置文件/etc/network/interfaces
增加了
auto eth0 iface eth0 inet dhcp
然后ping百度,好了。
yield用法
def foo():
for i in range(10):
x = yield i
print("value:",x)
g = foo()
a = next(g)
print(a)
a = g.send('p')
print(a)
a = g.send('q')
print(a)
与C一样,python的sys.exit(0)和os._exit(0)对于缓冲区的刷新是不一样的,为此进行测试如下,你会发现不同,所以fork出来的进程,要根据需要选择exit方式。
要注意print必须加上end=’’,否则换行符会刷新缓冲区。# 标准输出设备在正常情况下是linux中的行缓存的设备(除出错),’\n’正是换行符,所以会换行时清空缓存,写入文件流则没有这个问题。
import os,sys
print('aaa',end='',flush=True)
print('bbb',end='',flush=False) # 要注意必须加上end='',否则换行符会刷新缓冲区
#sys.exit(0)
os._exit(0)
idea和vim的配置技巧:
idea vim 如何支持ctrl + c
解决Idea不能实时编译的问题
从一堆字符中匹配出有效的MAC地址:
python
re.findall(r"(([a-f0-9]{2}-){5}[a-f0-9]{2})", "fw%e*f3-e3-33-de-30-33hjs|w-fg.hb")
,可以实现[('f3-e3-33-de-30-', '30-')]
,可以看到:用search
方法调用group
和groups
的区别
re.search(r"(([a-f0-9]{2}-){5}[a-f0-9]{2})", "fwef3-e3-33-de-30-33hjswfghbds34rhs3 drh%df ftghsdf regfsfwea3-e3-33-de-20-3ehjswegfs").groups()
('f3-e3-33-de-30-33', '30-')
re.search(r"(([a-f0-9]{2}-){5}[a-f0-9]{2})", "fwef3-e3-33-de-30-33hjswfghbds34rhs3 drh%df ftghsdf regfsfwea3-e3-33-de-20-3ehjswegfs").group()
'f3-e3-33-de-30-33'
java版:
String s = "77-dl-f3-e3-33-de-30-33-sd-77-dl-f3-e3-33-de-30-33-sd";
String regex = "(([a-f0-9]{2}-){5}[a-f0-9]{2})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(s);
while(matcher.find()){
System.out.println(matcher.group());
}
f3-e3-33-de-30-33
f2-e3-33-de-30-33
python抽象类
import abc
class A(abc.ABC):
@abc.abstractmethod
def f(self):
pass
class B(A):
def f(self):
print("b.f()")
b = B()
b.f()
finally语句中返回(或者产生异常),则先执行这两种,而不执行except语句中的return(但是会执行其前面的语句)
def f():
try:
a=1
a/=0
except Exception as e:
print(e)
return 22
finally:
# return 11
raise Exception
print(f())
java也是
public class Hello {
public static void main(String[] args){
int n = f();
System.out.println(n);
}
private static int f() {
try {
int a = 1;
a /= 0;
} catch (Exception e) {
System.out.println(e);
return 22;
}
finally {
return 11;
// throw new RuntimeException();
}
}
}
反射,动态加载类
public class Main {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("Point");
// newInstance: 弱类型。低效率。只能调用无参构造。需要加载类到方法区
// new: 强类型。相对高效。能调用任何public构造。不需要类加载
Object obj = cls.newInstance();
System.out.println(obj);
System.out.println(new Point());
// Constructor newInstance有参构造
Constructor<?> cons = cls.getDeclaredConstructor(new Class[]{int.class, int.class});
cons.setAccessible(true);
System.out.println(cons.newInstance(new Object[]{2, 2}));
}
}
函数调用栈
import sys
def test():
def testdddd():
for i in range(3):
f = sys._getframe(i)
print(f)
def funcdddd():
testdddd()
def aaaaaaaa():
funcdddd()
aaaaaaaa()
if __name__ == '__main__':
test()
输出:
<frame object at 0x0000020C36EC5210>
<frame object at 0x0000020C352EECF8>
<frame object at 0x0000020C35284A48>
异常信息,写入日志
def haha(a):
return int(a)
def do():
try:
a = "11f"
b = haha(a)
except Exception as e:
with open("test.log", "a") as fp:
# 换行,并且写入日期和时间
fp.write(datetime.datetime.now().strftime("\n%Y-%m-%d %H:%M:%S "))
# sys.exc_info得到错误名etype,错误值value,还有调用栈tb,
# 由于tb包含了原生的调用栈信息,文件名,行号,方法名,所以不需要logging模块,或flask的日志记录
# limit不做设置,否则太浅了
traceback.print_exception(*sys.exc_info(), file=fp)
动态执行文件
先执行import, 再reload,
对于hello.py文件内容的修改, 会动态的执行/加载其中的代码
while True:
time.sleep(1)
exec("import hello")
exec("reload(hello)")
列表中有字典, 按照字典的键/值进行排序
ls = [{"11": "bb"}, {"22": "aa"}]
ls.sort(key=lambda x: list(x.items())[0][0])
ls.sort(key=lambda x: list(x.items())[0][1])
对字典按照键/值排序, 转为元组的列表
d = {'11': 'bb', '22': 'aa'}
sorted(d.items(), key=lambda d: d[0])
sorted(d.items(), key=lambda d: d[1])
闭包的作⽤就是让⼀个变量能够常驻内存. 供后⾯的程序使⽤.
如果你在内部函数中访问了外层函数中的变量. 那么这个变量将不会消亡.将会常驻在内存中.
__file__属性
包名.__file__ 指__init__.py所在路径
模块名.__file__ 指模块.py所在路径
join连接
SELECT * FROM t1 AS a JOIN (SELECT * FROM t2 WHERE company_id=102) AS b ON a.company_id=b.company_id
shell批量操作
for i in `find . -name "hello*"` ; do ls $i -alh;done;
文件单词统计
首先,我们要清楚 NLP 任务的基本步骤,也就是下面的四步:
读取文件;
去除所有标点符号和换行符,并把所有大写变成小写;
合并相同的词,统计每个词出现的频率,并按照词频从大到小排序;
将结果按行输出到文件 out.txt。
第一问:你能否把 NLP 例子中的 word count 实现一遍?不过这次,in.txt 可能非常非常大(意味着你不能一次读取到内存中),而 output.txt 不会很大(意味着重复的单词数量很多)。
提示:你可能需要每次读取一定长度的字符串,进行处理,然后再读取下一次的。但是如果单纯按照长度划分,你可能会把一个单词隔断开,所以需要细心处理这种边界情况。
展平列表的yield from做法
def getSmoothList(lst):
def gen_expand(_list):
for item in _list:
if isinstance(item, (list, tuple)):
yield from gen_expand(item)
else:
yield item
return list(gen_expand(lst))
ls = getSmoothList([(1, 2), [3, 4, [5, 6, (7,)]]])
两层dict的初始化
from collections import defaultdict
dic = defaultdict(dict)
dic[1][1] = 11
dic[1][1] = 12
print(dic[1][1])
print(dic[1])
print(dic[2])
Golang 1.13: 解决国内 go get 无法下载的问题
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct