Python开发的10个小贴士
传值传参数笔试题
def extendList(val,list=[]):
list.append(val)
return list
list1=extendList(10)
list2=extendList(123,['a','b','c'])
list3=extendList('a')
print(list1)
print(list2)
print(list3)
#---------------------------------
[10, 'a']
['a', 'b', 'c', 123]
[10, 'a']
list2调用时,初始化并传入了2列表参数,list1和list3list2调用时没有参数,使用了extentdList默认初始化的list,(是同一地址,且列表可变)所以两次分别把10和a添加到list,得到[10,'a']。返回给list1和list3的都是extendList初始化的list的地址,所以返回的值相同
A.import math
B.from 模块名 import 函数名1,函数名2....
C.from modname import name1[, name2[, ... nameN]]
from fib import fibonacci
注意,不会把整个fib模块导入到当前的命名空间中,它只会将fib里的fibonacci单个引入
D.as 取别名
import time as tt
每个Python文件都可以作为一个模块,模块的名字就是文件的名字。 xxx.py
包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为包,__init__.py 控制着包的导入行为
object是顶级基类
type也是一个类,同时type也是一个对象
字符串表示:
__repr__:开发模式下调用
__str__:print调用
集合序列相关:
__len__
__getitem__
__setitem__
__delitem__
__containes__
迭代相关:
__iter__
__next__
可调用:
__call__
上下文管理器:
__enter__
__exit__
数值转换:
__abs__
__bool__
__int__
__float__
__hash__
__index__
元类相关:
__new__
__init__
属性相关:
__getattr__、__setattr__
__getattribute__、setattribute__
__dir__
属性描述:
__get__、__set__、__delete__
…………
#函数类似
class Cat(object):
def say(self):
print('I am a cat')
class Dog(object):
def say(self):
print('I am a dog')
animals = [Dog,Cat]
for animal in animals:
animal().say()
'''
sinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。
'''
class A(object):
pass
class B(A):
pass
b = B()
print(isinstance(b, B)) # True
print(isinstance(b, A)) # True
print(type(b)) #
print(type(b) is B) # True
print(type(b) is A) # False
+=本质会调用MutableSequence类下的魔法函数__iadd__方法,该方法有调用了extend方法。
a = [1, 2, 3]
c = a + (4, 5, 6)
print(c) # TypeError: can only concatenate list (not "tuple") to list
a = [1, 2, 3]
a += (4, 5, 6)
print(a) # [1, 2, 3, 4, 5, 6]
ge = (i for i in range(1, 21) if i % 2 == 1)
print(ge) # at 0x000001F09B0EEFC0>
print(type(ge)) #
print(list(ge)) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
1、 要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
L = [ x*2 for x in range(5)]
L
[0, 2, 4, 6, 8]
In [17]: G = ( x*2 for x in range(5))
G
Out[18]: at 0x7f626c132db0>
要打印出来, for 循环来迭代它
2、创建生成器,generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。
In [30]: def fib(times):
....: n = 0
....: a,b = 0,1
....: while n
生成器的特点:
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
L = ['Adam', 'Lisa', 'Bart', 'Paul']
for index, name in enumerate(L):
print index+1, '-', name
以直接作用于 for 循环的数据类型有以下几种:
一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
一类是 generator ,包括生成器和带 yield 的generator function。
这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。
内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。
def line_conf(a, b):
def line(x):
return a*x + b
return line
line1 = line_conf(1, 1) #默认赋值,第一次参数被锁住了
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
line1 = line_conf(1, 1) #默认赋值,第一次参数被锁住了
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))
由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
装饰器 如何理解Python装饰器?
https://zhuanlan.zhihu.com/p/21696291
概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
def w1(func):
def inner():
# 验证1
# 验证2
# 验证3
func()
return inner
@w1
def f1():
print('f1')
python解释器就会从上到下解释代码,步骤如下:
没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。
以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在新f1 函数内部先执行验证,再执行原来的f1函数,然后将原来f1 函数的返回值返回给了业务调用者。
模块修改,要重新加载reload
避免循环导入,鸡生蛋,蛋生鸡
浅拷贝:拷贝引用,没有拷贝内容,地址给了,指向同一地址。
深拷贝:对一个对象所有层次的拷贝,借助copy.deepcopy模块。内容复制到新内存。
列表拷贝可变,新内存。元祖不可变,copy.copy()指向同一位置(内存)。
进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
线程,能够完成多任务,比如 一个QQ中的多个聊天窗口
实现方式都是两种
多任务,时间片轮转,优先级调用。 并发:有处理多任务能力,不一定同时。并行:同时处理多任务。
fork返回值特殊,生出多进程。fork()调用一次,返回两次,2返回值。
子进程永远返回0,而父进程返回子进程的ID。,父进程大于0;
多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响
多进程如果是对齐,符合2的n,每人都要fork一次
服务器进程很多,pid类似身份证,不会同多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响,父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法。总进程:2*n 次,一般不超过8次。
multiprocessing模块提供了一个Process类来代表一个进程对象,子进程可以用类来实现
while true 慎用
超级多任务,Pool进程池 缓存 apply堵塞式
使用多线程并发的操作,节约时间,执行顺序无关
线程共享全局变量,数据共享容易,列表传参也共享。进程不能(诞生进程通信)
os模块创建文件夹,os.mkdir(),print调试
Queue可以用来解决百分比问题
进程池:
from multiprocessing import Pool
import os,time,random
def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
#random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))
po=Pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
#Pool.apply_async(要调用的目标,(传递给目标的参数元祖,))
#每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print("----start----")
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
线程:
多线程并发的操作,花费时间要短很多
创建好的线程,需要调用start()方法来启动
线程创建好了一起执行
在多线程开发中,全局变量是多个线程都共享的数据,而局部变量等是各自线程的,是非共享的
同步(上锁,有规律):同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。 如进程、线程同步,可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
异步:无约定
同步调用就是你 喊 你朋友吃饭 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你们一起去
异步调用就是你 喊 你朋友吃饭 ,你朋友说知道了 ,待会忙完去找你 ,你就去做别的了。
重构:重写
一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
对于全局变量,在多线程中要格外小心,否则容易造成数据错乱的情况发生
TCP/IP协议族,现实4层,实现不同系统,机器通信
网际层也称为:网络层
网络接口层也称为:链路层
一台拥有IP地址的主机可以提供许多服务,比如HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)等,这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。
端口,标记进程的东西(同台电脑用pid),不同电脑通信标识
ip地址:用来在网络中标记一台电脑的一串数字,比如192.168.1.1;在本地局域网上是惟一的。
IP地址127.0.0.1~127.255.255.255用于回路测试 网络号+多播号不能用(多播,有些能看有些不能,视频会议)
联网设备都有ip
利用ip地址,协议,端口就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互
socket ip+端口+协议
循环尽可能代码少,节约
UDP通信过程
TFTP客户端
下载:创建文件—写数据—关闭
上传:
Packet Tracer 是由Cisco(著名网络公司,思科)公司发布的一个辅助学习工具,
为学习思科网络课程的初学者去设计、配置、排除网络故障提供了网络模拟环境。
掩码:二进制的掩码与ip按位与,得到网络号,(c类最后位255.255.255.0),3个255表示网络号,0表示主机号
网线只能连2台电脑(网络多台数据电信号错乱),多台交换机淘汰了集线器(USB拓展)
路由器(Router)又称网关设备(Gateway)是用于连接多个逻辑上分开的网络
网卡:物理地址,实际地址
默认网关:
不在同一网段的pc,需要设置默认网关才能把数据传送过去 通常情况下,都会把路由器默认网关
集线器:广播,交换机:更智能
tcp规定跨网不能直接通信,路由器双网卡双ip,左手右手,可以连接不同网段,
ip地址通信不会变化,mac地址会变化
ping TTL=128,经过一次路由器减一
cdn分发,各地放置服务器
arp三方造假
nat:ip 内网和外网能上,路由表地址转换,只能向外才能映射,自己搭建服务器不能外网访问,借助花生壳。
逻辑地址转换后共用一个路由器,路由器访问dns,服务器
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。(不过可以指定起始位置)
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
>>>import re
>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配
>>> print (m)
日期替换
>>> s = '2017-11-27'
>>> import re
>>> print(re.sub('(\d{4})-(\d{2})-(\d{2})',r'\2/\3/\1', s))
11/27/2017
\b 是指匹配一个单词边界,也就是指单词和空格间的位置。
>>> import re
>>> ret = re.findall(r'o\b','hello nano$')
>>> print(ret)
['o', 'o']
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。
import json
# Python 字典类型转换为 JSON 对象
data = {
'no': 1,
'name': 'Runoob',
'url': 'http://www.runoob.com'
}
json_str = json.dumps(data)
print("Python 原始数据:", repr(data))
print("JSON 对象:", json_str)
#------------------------------------
Python 原始数据: {'no': 1, 'name': 'Runoob', 'url': 'http://www.runoob.com'}
JSON 对象: {"no": 1, "name": "Runoob", "url": "http://www.runoob.com"}
# 写入 JSON 数据
with open('data.json', 'w') as f:
json.dump(data, f)
# 读取数据
with open('data.json', 'r') as f:
data = json.load(f)
获取时间
import time
localtime = time.asctime( time.localtime(time.time()) )
print ("本地时间为 :", localtime)
了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:
浏览器发送一个HTTP请求;
服务器收到请求,生成一个HTML文档;
服务器把HTML文档作为HTTP响应的Body发送给浏览器;
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。
这个接口就是WSGI:Web Server Gateway Interface。
复杂的Web应用程序,光靠一个WSGI函数来处理还是太底层了,我们需要在WSGI之上再抽象出Web框架,进一步简化Web开发。