Python3学习笔记
注意:这个笔记只是用于我自己以后的复习使用,本人没有对其进行通用的整理,并且使用的编辑器是vim,所以没有使用Markdown的格式。
因为简书有时候会出现吞内容的情况,所以在这里添加我的GitHub。
https://github.com/shanghj01/Coding.git
#在download源代码的时候要适当选择较低的版本,因为语言的源码版本越低越能看出作者的意图
切片中[起始位置:结束位置:步长(默认是1)]
###############################################
字符串
查找:find,index,rfind,rindex(相同都返回下标,不同,-1,异常)
replace(原,现):替换
split(切割符) :切割
capitalize:单个首字母大写
title:全部首字母大写
endswith(str):判断结尾
startswith(str):判断开头
rjust(int),ljust(int),center(int):在int个字符中右左中对齐
strip():去掉str两边空格,\n
partition(str):以左起第一个str分割为元组
split(str):以str分割
isalpha():是否纯字母
isalnum():是否数字字母组合
isdigit():是否纯数字
str.join(a,b):以str连接a,b
#####################################################
列表
增加
append():追加(整体添加)
insert(位置,内容):添加
extend(list):追加list(合并list)
删除
pop():默认最后一个
remove(str):删除str内容
del:删除指定
修改
下标赋值
查找
in:布尔值
index:下标,异常
###########################################
字典
增加
dict["key"] = "value"
删除
del
修改
赋值
查询
get(key)
字典操作
len(dict):键值对个数
dict.keys():dict的所有键
dict.values():dict的所有值
#################################################
元组
死的list
#######################################################
函数
def function():
不定长参数
def function(*obj):(存储为元组形式)
def function(**obj):(存储为dict形式)此时的传入格式为key=value
注意不定长参数放在参数列表的最后
拆包
要传给*obj(元组),变量前添加*
同样传给**obj(字典),添加**
匿名函数
lambda
匿名函数也是函数,同样要传参进入
##########################################################
文件
open("file","option(w,r,a)",encoding="utf-8"(可选))
close
flush
read()
write()
readlines()
readline()
seek(字节,pos(0开头,1中间,2结尾))
tell() 返回地址
OS
import os
os.rename("old","new") #重命名
os.mkdir("name") #创建dir
os.getcwd() #获取当前路径
os.chdir("newpath") #改变默认目录
os. listdir("./") #获取目录
#######################################################
面向对象
class ClassName:
#属性
注意,这里的属性可以通过下面的__init__方法里设置,而不必刻意写出
#方法
def func(self):
pass
注意这里的self相当于java中的this,在这里是建议方法中写上self
魔法方法(就是实例属性)
1
__init__方法
#用于初始化的方法
def __init__(self,name,age):
self.name = name
self.age= age
这里的name,age由 调用类时直接写入
class(name_value,age_value)用于传入__init__方法中的name,age
2.
__str__方法
#用于获取描述信息的方法
def __str__(self):
return "this is {},and age is {}".format(self.name,self.age).center(50,"+")
注意:这里return是必须的
###############################################################
#这里是一个例子
class Home:
def __init__(self,size,info):
self.size = size
self.usize = self.size
self.info = info
self.addObj = {}
def __str__(self):
msg = "the home initSize is {0},the useableSize is {1},and the home info is {2},the obj is {3}".format(self.size,self.usize,self.info,str(self.addObj))
return msg
def add_obj(self,obj):
self.usize -= obj.get_size()
self.addObj[obj.get_name()] = obj.get_size()
class Obj:
def __init__(self,name,size):
self.name = name
self.size = size
def __str__(self):
msg = "the obj hava {0},and it size is {1}".format(self.name,self.size)
return msg
def get_size(self):
return self.size
def get_name(self):
return self.name
home = Home(200,"这是一个房子")
bed = Obj("床",6)
print(home)
print("".center(50,"*"))
print(bed)
print("".center(50,"*"))
home.add_obj(bed)
print("".center(50,"*"))
print(home)
print("".center(50,"*"))
safa = Obj("沙发",50)
print(safa)
print("".center(50,"*"))
home.add_obj(safa)
print(home)
#到此例子结束
####################################################################
隐藏属性
私有属性属性前加__
私有方法
私有方法同样在方法名前加__ (此时表面在外部无法调用)
在类内部(且只能在内部)调用私有方法要self.__funName()
__del__方法
引用计数
在硬链接的obj完全删除时自动调用此方法
可以理解为死前的善后工作
sys模块中的getrefcount()方法
sys.getrefcount() :用于查看一个对象被引用的次数
返回的值是引用次数+1(次数=返回值-1)
继承以及单继承
sonClass(FatherClass):
子类继承父类(基类)同样子类也可以继承父类的父类(连级继承)
重写
子类重写父类同名方法(同java)
调用被重写的方法1. fatherClass.funcName() 2. super().funcName()
私有方法、私有属性的继承
私有方法和私有属性不能被继承
但是调用的公有方法中包含有私有方法或是私有属性,这个公有方法可以被继承
多继承
object类是所有class的父类
建议类的定义中写上(object)
class C(A,B): 表示C类可以继承A类和B类
注意:在多继承中,子类继承的方法在多个父类中出现,子类会取就近优先原则,优先调用最左边的。
这里有className.__mro__属性,可以用来打印出这个类可调用的类。
多态
定义的方法或函数根据传递进的方法的不同而得到不同的结果
################################################
# 一个多态的小例子
class A(object):
def __str__(self):
return ("this is a ".center(20,"*"))
class B(object):
def __str__(self):
return ("this is b".center(20,"-"))
def func(temp):
print(temp)
a = A()
b = B()
func(a)
print("".center(30,"-"))
func(b)
# 例子结束
#################################################
类属性、实例属性
定义在class内部,但是在方法外部的变量称为类的属性
实例属性:和具体的某个实例对象有关,并且实例对象不共享
类属性属于类,并且类属性在实例之间共享
和对象有关的是实例属性
类方法、实例方法、静态方法
实例方法:类中定义的方法没有特殊标注都是实例方法
类方法:需要在方法前添加 @classmethod
静态方法:在类中,方法前添加@staticmethod
静态方法可以不定义参数,也可以定义参数(self在静态方法中没啥意义)
###################################################
# 小例子
class A(object):
#类属性
num = 0
#实例方法
def __init__(self):
self.name = "fp"
#类方法
@classmethod
def cFun(cls):
cls.num = 666
#静态方法
@staticmethod
def staFun():
print("这是一个静态方法")
a =A()
A.cFun() #类方法可以通过类的名称调用
#a.cFun() #类方法还可以通过类的对象调用
print(A.num)
A.staFun() #静态方法通过类名或对象名调用
print("".center(20,"*"))
a.staFun()
# 例子结束
####################################################
解耦合
对于两个类有交互的时候,可以通过中间件(函数或其他方式)来解决耦合
但是在开发中,尽量使用一个类型,即用类尽量都用类,用方法尽量用方法
使用类完成解耦合-简单的工厂模式
##################################
#小例子
class A(object):
def __int__(self):
self.factory = Factory()
def useB(self):
return use_b
class Factory(object):
def factFun(self):
return fac
class B(object):
def theBFun(self):
return theB
#例子结束
####################################
__new__方法
__new__(cls):这个方法在类被引用时会被执行(自动的,如果不被创建,类会调用默认的__new__方法)这里的cls此时指向的是类的名字[其实类是通过父类object.__new__(cls)来生成的]
__new__方法只负责创建,__init__方法只负责初始化
在此比较java和c++中的构造方法,构造方法其实包含了Python中的这两个方法
创建单例对象
不管创建多少只有一个对象
class A(object):
pass
d = A()
e = A()
print(id(a))
print(id(b))
#注意,这里的两个print的输出值并不相同
#这里不是单例模式
单例模式可以通过类变量来实现
class A(object):
__num == None
def __new__(cls):
if cls. __num = None:
cls.__num = object.__new__(cls)
return cls.__num
else :
#返回上面生成的cls.__num
return cls.__num
a = A()
b = A()
print(id(a))
print(id(b))
#此时打印的a、b的id是相同的
#也就是表明此时是单例模式
注意,在创建对象时最先调用__new__方法,这时像类中添加参数会报错,所以这时需要在__new__方法中设置虚参,只是一个样子,不需要用到
###################################################
异常处理
try:
可能包含异常的代码片
except errName(异常的名字):#这里如果名字和异常不对应,则异常按照系统默认的方式处理
输出信息
在这里,try中的语句,如果有异常,则,异常后的语句停止,try外的语句继续运行
一个try后可以跟多个except,一个except后可以有多个异常名,不过需要添加到元组中(python3中,Python2中不需要括号)
except Exception(这是一个异常的总称,可以捕获所有异常) as tmp(只是一个变量名)
#################################################
# 小例子
try:
1/0
open("sss0")
print(123eee)
except(NameError,FileNotFindError):
print("try中出现详细的异常")
except Exception as result:
print("这里出现一个笼统的异常,{}".format(result))
else:
print("try中没有异常时打印")
finally:
print("不管try中是否有异常,都会执行finally")
print("异常测试结束")
# 例子结束
##################################################
自定义异常
raise
#########################################
class UserError(Exception):
def __init__(self):
print("这里是用户自定义的异常")
try:
raise UserError
except UserError:
print("抛出自定义异常")
else:
print("没有异常")
##########################################
异常处理中抛出异常
try:
Error
except exception as result:
if (条件):
#开启捕获异常
print(result)
else:
#重写抛出异常,此时的异常不会被捕获,交由系统处理
raise
#############################################
if的各种真假判断
"",None,[],{},数字0,都表示假
#############################
模块
os.__file__
import os
xxx-cpython-35.pyc 表示c语言编写的Python编译器3.5版本的字节码
import Name
from name import defName,defName2
from name import * 注意:这里尽量不要使用这种方法导入
import Name as sName
模块中的函数或其他方法不希望在调用时重复执行,可以通过__name__变量来实现
这样,在被当做模块调用时,不会重复调用,在测试模块功能时,函数或其他方法会根据设置执行
模块中的__all__
__all__[] :在模块中希望用*导入模块被时调用的操作,可以放入这个变量的列表中,如果不在这里,则不会被调用
包、__init__的作用
在一个文件夹下有py文件,有__init__.py文件称为包(Python3中可以不写__init__.py文件)
包中__init__.py文件的内容应含有__all__,以及from . import xxxName : 这里是对from * (all)以及 import 的导包方法的使用声明
如果__init__文件为空,导包会失败
模块的发布、安装
模块的发布
包外部同文件夹建立setup.py
######文件内容
from distutils.core import setup
setup(name = "moduleName",version = "VerDis",discription = "disInfo",author = "User",py_modules = ["modulesList"])
############################内容结束
###linux 命令中执行
python3 setup.py build
python3 setup.py sdist
##############至此,包打包结束
模块的安装################################
python3 setup.py install
#此时就把发布的包安装到Linux上了
给程序传参################################
import sys
print(sys.argv) #这里sys.argv是一个列表,0表示程序名,1:表示传入的参数
列表生成器####################################
[x for x in range(0,10,2)]
集合###########################
set 表示集合
集合中没有重复值,(集合会自动去重)
list、tuple可以有重复值,不会自动去重
字典中,当键重复时,会保留最后的那个,其他的去重(不论值是否相同)
强制类型转换得到的变量恢复到原类型用eval()
########################################################################
for循环中删除元素的坑:在循环的过程中删除元素可能出现漏删的情况。
##########例子###########
a = [1,2,3,4,5,6,7]
for i in a:
print(i, end = ",")
if i == 2 or i == 3:
a.remove(i)
print("a = {0}".format(a))
#这时输出分别为1,2,4,5,6,7,和a = [1,3,4,5,6,7]
#从这里的结果可以看出在循环中漏删了3
##########################
这里可以使用“缓存”的方法
用另一个变量临时存储要删除的变量,待循环结束后在删除
#############小例子#################
a = [1,2,3,4,5,6,7]
b = []
for i in a:
print(i, end = ",")
if i == 2 or i == 3:
b.append(i)
for i in b:
a.remove(i)
print("a = {0}".format(a))
#此时得到的a的结果就是完全删除的结果 a = [1,4,5,6,7]
#######################################
对代码基本相同的类抽取基类:当不同类中的方法基本相同时,可以抽取出一个基类,用来简化代码
########################################
#################Python高级################
##########################
模块重新导入
向导入模块中添加新的路径:sys.path.append("yourPath")
重新导入模块
from imp import *
reload("old_Model") # 这里的参数是要重新导入的模块
模块的循环导入问题
a模块中导入了b模块,然而在b模块中又导入了a模块(这样就出现了一个模块导入的死递归)
解决方法:再建立一个新的模块,让这两个递归的模块成为子模块,让那个新的模块调用这两个模块
==和is的区别
==是用来判断值是否相等
is是用来判断两者之间是否存在引用关系
##############################
深拷贝、浅拷贝
这里的深浅指的是拷贝的程度
浅拷贝:只是对同一个变量的地址引用(地址的拷贝),这里的拷贝只是用引用指向
深拷贝:这里需要导入模块【import copy ;new = copy.deepcopy(old)】这里的拷贝是新建了内存的拷贝
copy模块中的copy和deepcopy的区别:copy只copy第一层,而deepcopy是完全copy
copy拷贝的特点:自动判断>>>当copy的对象是不可变类型时,浅拷贝,当是可变类型时,copy第一层
#################
进制转换 :转二进制:bin(),八进制:oct(),16进制:hex(),转10进制:int()
位运算
左移:<< 右移:>> 作用,用在快速乘法
& 按位与 | 按位或 ^ 按位异或(相同为0,相异为1)~ 取反
##############################
私有化
name:公有
_name:私有,from XX improt * 禁止导入,类和子类可以访问
__name:私有,避免和子类发生冲突,在外部无法访问
__name__:私有,特有的魔法方法或属性,个人最好不要创建
name_:用于区别与关键字重复
只要开头有_,基本from xx import * 就无法导入,但是只是导入模块,还是可以用的
name mangLing(名字重整)为了防止对私有属性或方法的使用(访问时可以_ClassName.__name)
property的使用
这里需要建立像Java中的setter和getter方法
###########例子################
class Test(object):
def __init__(self):
self.__num == 100
def setNum(self,newNum):
print("setter".center(20,"*"))
self.__num = newNum
def getNum(self):
print("getter".center(20,"*"))
return self.__num
new = property(setNum, getNum)
t = Test()
t.new = 666
#此时打印的结果是
#********setter**********
#********getter**********
#666
#也就是property通过setter方法和getter方法,将本不可在外部通过 对象.属性 的调用方式成功实现了
#################例子结束###################
这里也就是相当于用property对函数进行了一次简单的封装
#注意:这里property中的方法应先写getter方法,后写setter方法,并且方法不写括号
property也可以用装饰器的方法调用
##########例子###########
@property
def num(self):
print("getter")
return self.__num
@num.setter
def num(self,newNum):
self.__num = newNum
# 这里就不用写property(getter,setter)方法了
##########################
#这样的使用和上面的使用都可以
##########################################
生成器:generator:对于要用到的变量,一边执行一边得到结果
前边提到的列表生成器只是最简单的生成器,也是最直接的
而一边操作一边得到结果的生成器是用next()进行下一步操作的,但是这里next()执行完最后一次还调用会报错。
一个函数中加了yield就表面这个函数是一个生成器了,此时按照原来的函数调用方法就不行了,返回的是一个对象。此时需要用一个变量来指向这个生成器。
此时用next()来执行生成器时,会在yield处停止,并返回yield后的参数,这个返回的参数就是生成器生成的值,在下一次调用生成器时,会在yield停止的地方接着执行。
########例子,用生成器来生成斐波那契数列###########
def fib():
a,b = 0,1
for i in range(10):
yield b
a,b = b,a+b
a = fib()
next(a)
#最后的结果应该是:55
####################################################
这里next(generator)和a.__next__()是一样的
还有一个更高级的方法:a.send(value)
###############例子##########
def fib():
a,b = 0,1
for i in range(10):
temp = yield b
a,b = b,a+b
print(temp)
a = fib()
next(a) #这里print()的结果是None,因为生成器在yield处停止,不会对temp赋值
a.send("yeyeye") # 这里print()的结果是yeyeye,因为send()将这个值传入了temp
##############例子结束##################
注意:这里send()必须要有参数,可以是None,但是不能不写
一个生成器中可以有多个yield
协程多任务:运行一下,停一下
这里就可以用生成器的来实现多任务
######################################################
迭代器
可迭代对象:list,tuple,dict,set,str,generator,生成器,带yield的generator function
判断是否是可迭代对象:isinstance:from collections import Iterator isinstance(ifOk,Iterator),或者是使用for循环来判断
iter()函数用来将非迭代器转换为迭代器
#############################################################
闭包
在一个函数内部定义一个函数,并且内部的函数调用了外部函数的参数,此时,内部函数和用到的参数就叫做闭包。
######################例子################
def test(name):
def prt():
print(name += 100)
return prt
ret = test
ret(1)
#############例子结束############################
用一个变量名指向一个函数名,这样变量就相当于这个函数
对闭包的应用
###############例子###########
def test(a, b):
def test_in(x):
print(a*x+b)
return test_in
tmp = test(2, 3)
tmp(0)
#这样的好处是相当与存在一个内部存储机制,在外部函数中永久存在一个参数
#######################例子结束################
#############################################
装饰器
在一个Python文件中,定义重名的函数不会报错,但是会使用最后的一个函数
写代码的开放封闭原则
开放:对代码进行扩展开发
封闭:对代码已实现的功能,最好不要随意修改
语法糖:写一个函数,用@符号加在其他功能前,达到一个想要的结果
#####################装饰器例子##################
def zsq(func):
def prt():
print("这是装饰器".center(10,"*"))
func()
return prt
@zsq
def f1():
print("这是一个函数".center(10,"*"))
# 这里的f1 = zsq(f1) 就相当与前边的@zsq
f1 = zsq(f1) # 这里将f1()作为参数,传入zsq()
f1() # 这里的f1已经不是原来的函数了,而是zsq()中封装的prt函数
# 得到的结果是
#*****这是装饰器*****
#*****这是一个函数*****
# 这里就达到了开放封闭原则
######################例子结束###############
多个装饰器
###############多个装饰器例子#############
def zsq1(f):
def prt1():
print("装饰器1".center(10, "*"))
return "***" + f() + "***"
return prt1
def zsq2(f):
def prt2():
print("装饰器2".center(10, "*"))
return "---"+ f() + "---"
return prt2
@zsq1
@zsq2
def test():
print("test".center(10, "*"))
return "hello world"
tmp = test()
print(tmp)
"""
这里得到的结果为:
***装饰器1***
***装饰器2***
***test***
***---hello world---***
"""
# 得到这样的结果是因为程序顺序执行,当在@zsq1时,其下部紧接着的是zsq2,这时,先将test装入了zsq2,然后返回到test'这之后才返回到zsq1,这时得到的结果就会出现上面的现象
##############################例子结束#################
装饰器执行的时间
Python解释器执行到@处时,就已经开始装饰了
装饰器对有参数,无参数函数进行装饰
当无参时,不必特别处理,当有参数时,对闭包中的函数进行设置形参,这里就可以进行有参数的函数进行装饰了
这里需要特别注意:在有参数时,可以用不定长参数的方式,*args和**kwargs,在调用装饰的函数时,需要用同样的不定长参数进行解包
装饰器对带有返回值的函数进行装饰
在闭包的函数中设置一个return 在调用被装饰的函数时,赋值,这样就可以输出
###############小例子##########
def zsq(func):
def bb():
re = func()
return re # 这里是注意点
return bb
@zsq
def test():
print("this is a test def !".center(20,"*"))
return 666
ret = test()
# 注意这里的return
通用装饰器
####################例子##################
def zsq(func):
def bb(*args, **kwargs):
print("this is a bibao")
tmp = func(*args, **kwargs)
return tmp
#注意,在Python中,如果return 返回的是None,那么不算是错误,所以,在这里一直写上return 是不算错的
return bb
@zsq
def test(a,b):
print("this is a test")
return c
ret = test(a,c)
#这是一个通用装饰器
#####################例子结束##########
带有参数的装饰器
装饰器带参数,在原有的装饰器的基础上,设置外部变量
这里的设置外部变量就是在原有的装饰器的基础上,在外部再加一个带参数的函数
####################例子####################
def func_arg(tmp):
print("the value is {}".format(tmp))
def zsq(func):
print("zsq")
def bb():
print("bb")
func()
return bb
return zsq
#注意:这里写的是外部的函数,而这个函数返回的是装饰器,所以等价于:test = zsq(test)
@func_arg(6666)
def test():
print("this is test")
##########################例子结束##############
带有参数的装饰器能起到在运行时使用不同的功能
#############################################################
作用域
命名空间:起名字的空间
globals():查看当前空间下所有的全局变量
lobals():查看当前空间下所有的局部变量
LEGB规则
变量的查找顺序:lobal,enclosing(外部嵌套的命名空间),global,__builtin__(内建)
#############################################################
Python动态添加属性以及方法
添加属性就是简单的"."操作,但是添加方法时,需要用到模块,types
instanceName.method = types.MethodType(nethodName, instance)
##################例子#####################
class Demo(object):
def __init__(self, name):
self.name = name
def tmp(self):
print("this is a test function for {}".format(self.name))
d = Demo("666")
import types
d.tmp = types.MethodType(tmp, d)
d.tmp()
#这样就添加了一个方法
#这个方法的输出结果为:this is a test function for 666
###################例子结束###############################
types.MethodType的作用:将对象和要添加的方法绑定
这里需要特别注意:用到types.MethodType时,只是用来添加实例对象的方法,对静态方法(staticmethod)和类方法(classmethod)只是需要用className.p = p这种方式就可以直接添加
#############例子##############
@staticmethod
def d1():
print("static method")
@classmethod
def d2():
pritn("class method")
#添加静态方法
d.d1 = d1
#添加类方法
d.d2 = d2
################例子结束###########
###########################################
__slots__的作用
通过在类中用__slots__来限制该类实例能添加的属性
#########################例子################
class demo(object):
__slots__ = ("nim", "qqqq") #这里就限制了实例添加属性时只可以添加nim和qqqq这两个属性
#####################例子结束#########################
这里需要注意的是:__slots__只对当前类的属性有限制作用,对子类并没有作用
##############################################
类做装饰器
用类做装饰器需要在类中定义一个__call__()方法
#############例子##################
class Demo(object):
def __init__(self, func):
print("初始化{}".format(func.__name__))
self.__func = func
def __call__(self):
print("这是类装饰器")
self.__func()
@Demo
def test():
print("test".center(20,"*"))
test()
##################例子结束############
元类
类也是对象,所以也可以在运行时动态的创建
还可以用type来创建类
type除了可以用来查看一个变量的属性,同样也可以用来创建类
type("classname", 由父类名组成的tuple(), 由属性组成的dict{})#注意:这里这种方法只是用来保证版本的兼容性,不建议用
注意:这里的type就相当于一个元类
__metaclass__属性
用于指定创建class的类
__metaclass__ = FatherName(这里也可以是一坨代码)#这里是用于定义类的生成方式这里系统默认会指定,但是自己写过后会自动调用自己的
__metaclass__用到的class自己定的话需要如下操作:#########################例子###############################
def DiyClass(class_name, class_parents, class_attribute): newAtr = {} for name, value in class_attribute.items(): if not name.startSwitch("__"): newAtr[name.upper()] = value return type(class_name, class_partents, class_attribute)在Python2中用如下操作:class NewClass(object): __metaclass__ = DiyClass pass在Python3中用如下操作:class NewClass(object, metaclass = DiyClass): pass
########################例子结束#######################################
垃圾回收
1.小整数对象池
Python中-5~256之间的整数是提前建好的,不会被垃圾回收机制回收,当用id()查看地址时,在这个范围内的整数都是相同的地址
2.大整数对象池
与小整数对象池相反
3.intern机制
字符串完全相同的引用自一个地址
单个字符共用内存
#############分隔###############
引用计数
Python中以引用计数为主
引用计数的优点:简单,实时性
引用计数的缺点:维护时占用内存,循环引用,造成内存泄露
引用计数减一不止是del,还可以通过None的赋值
隔代回收
Ruby中的垃圾回收是标记清除,对内存的申请是一次申请多个,当内存不够用时再清理,而Python中的内存申请是用一个申请一个。
隔代回收为辅
零代链表中检测到相互循环引用的减一,得到是否是垃圾(引用计数为0),需要回收,否则不会减一
GC模块
gc.get_count():返回(x,y,z) x表示内存占用,y表示零代清理次数,z同理表示1代gc.get_threshold():返回(x,y,z) x表示清理上限,y表示每清理零代链表10次,清理一次一代链表。z同理是1,2代 这里的x,y,z默认值为(700,10,10)
查看一个对象的引用记数
sys.getrefcount()
通过gc.disable()来关Python的gc,同样也可以通过gc.enable()开启,用gc.isenabled()来判断是否是开启gc的
通过gc.collect()来显示的执行垃圾回收机制(手动执行)
这里需要注意:尽量不要手动重写对象的__del__方法,因为这样会使删除时不会自动调用gc来删除,此时需要调用父类的__del__()方法来删除
###################分隔#################################
内建属性
__init__:初始化
__new__:新建
__str__:print()如果没有,使用repr结果,美化版repr
__repr__:类实例 回车 或者print(类实例),打印的结果是程序的表达方式__class__:实例.__class__
__del__:删除
__dict__:vars(实例.__dict__)
__doc__:help
__bases__:类名.__bases__
__getattribute__:访问实例属性时
__getattribute__:属性拦截器,会在所有属性使用之前调用
################
def __getattribute__(self, obj): pass
###############
#######################例子#################
class Demo(object):
def __init__(self, tmp1):
self.tmp1 = tmp1
self.tmp2 = "shj"
def __getattribute__(self, obj):
print("this obj is {}".format(obj).center(20, "*"))
if obj == "":
print("the input is {}".format(self.obj))
else:
tmp = object.__getattribute__(self, obj)
print("this is not if %s" %tmp)
return tmp
def test(self):
print("this is the function named test")
s = Demo("666")
print(s.tmp1)
print(s.tmp2)
s.test()
'''这是运行结果:**this obj is tmp1**this is not if 666666**this obj is tmp2**this is not if shjshj**this obj is test**#注意这里:这里调用的test方法是显示的一个绑定this is not if>
#这里说明,类中的方法同样作为一个属性
this is the function named test
#通过这两个注意可以看到,类中的方法其实是不存在的,而是通过创建一个属性,通过对属性绑定方法来达到创建方法的操作
'''
__getattribute__的坑
################代码############
class Demo(object):
def __getattribute__(self, obj):
print("这是一个关于attribute属性的坑")
if obj.startswith("a"):
return "666"
else:
return self.test
def test(self):
print("this is the function test")
d = Demo()
print(d.a)
print(d.b)
'''
这是一个关于attribute属性的坑
666
这是一个关于attribute属性的坑
这是一个关于attribute属性的坑
这是一个关于attribute属性的坑
这是一个关于attribute属性的坑
......
File "test.py", line 7, in __getattribute__
return self.test
File "test.py", line 7, in __getattribute__
return self.test
......
RecursionError: maximum recursion depth exceeded while calling a Python object
#这里报了一个错误
#这是因为:else里的self.test出现了死循环的调用getattribute
#所以,这种调用方式是不可取的,在实际操作中要注意避免
'''
#########################代码结束#####################
内建方法
range(start, stop, step)
在Python2中是直接生成,在Python3中生成器的生成方式
xrange():功能和range()一样,但是是生成器形式的,需要用next()调用
map(function, sequence[,sequence]) 返回list 这里:function是一个函数,sequence是一个或多个序列,取决于function需要几个参数
这里参数序列中的每一个元素分别调用function,返回包含每次function的函数返回值的list
##############例子##############
a = map(lambda x:x+x, [y for y in range(1,5,1)])
for i in a :
print(i)
################例子结束###############
filter()函数:对指定序列进行过滤
filter(function, sequence):这里的function 返回值为True或False,返回的值的类型和sequence的类型相同
reduce()函数:对序列中的数据进行累积
reduce(function, sequence, initial):这里的initial是初始值
注意:在Python3 reduce()函数不在全局命名空间中,需要先导入functools模块,from functools import reduce
sorted()函数:排序
########################################
集合set
集合中的操作还可以有求交集,并集,补集。
交集:A&B 并集:A|B 补集: 差集:A-B
对称差集:A^B
##################################
functools模块
这个模块中放置相对常用的一些方法
partial()(偏函数):把一个函数的某些参数设置成默认值,返回一个新的函数,调用这个新的函数更简单
############例子###############
import functools
def test(*args, **kwargs):#注意这里的可变长参数,如果设置定长参数,会出现参数多给报错
print(args)
print(kwargs)
q = functools.partial(test, 1,2)
q()
q(666, 2333)
################例子结束##########################
wraps函数
用于消除装饰器在装饰函数时改变了被装饰函数的说明文档这一缺点
#############例子################
import functools
def zsq(func):
"这是一个装饰器"
@functools.wraps(func)
def a():
print("这里添加了一个装饰器")
return a
@zsq
def test():
"这里是一个测试函数"
print("this is a test")
test()
print(test.__doc__)
"""
得到的结果是:
这里添加了一个装饰器
这里是一个测试函数
"""
#这里就解决了说明文档被装饰器替代的问题
###################例子结束################
常用模块
用到的时候再查看就好
hashlib模块
用于生成hash(哈希)码等操作
####################代码#####################
import hashlib
m = hashlib.md5() #创建hash对象
print(m)
m.update(b"str") # 更新哈希对象以字符串参数,注意,这里需要先编码,不然只是字符串会报错
m.hexditest() # 返回16进制数字字符串
#############代码结束########################
Linux系统编程
pdb调试
1、运行代码时调试
python3 -m pdb fileName.py # 这里直接在Linux控制台中输入即可
l:显示当前调试的代码
n:继续向下走一步
c:继续执行代码,相当于一步到位
b num:在代码中添加断点,num代表添加断点的所在行数
b:可以查看代码中的所有断点
clear num:删除断点,num表示断点在断点存储中的序号,不是添加断点的行号,这里的clear也可以是cl
p name:打印一个变量的值,name表示变量名
a:打印所有形参的数据
s:进入一个函数
q:退出pdb调试
r:快速执行到函数的最后一行
2、交互调试
import pdb
pdb.run(funcName(attribute)) # 这里需要在pdb中先按s,然后才可以l,不然不会显示代码
3、程序里埋点
import pdb
pdb.set_trace() # 当程序遇到这句话时才进入调试
4、日志调试
print()大法好 # 在程序不停止的情况下,通过log日志热修复程序
#############################################################
pep8规则
pep8 官网规范地址
https://www.python.org/dev/peps/pep-0008/
每级缩进 4个空格
函数中的形参过长,换行时建议对齐
类间隔两个空行
方法间隔一个空行
导库:标准库,第三方,本地(个人)
类名,驼峰命名,模块,全程小写,可以用下划线
######################################################
多任务
#这里的fork只是用于Linux(unix)仅作为了解
fork()函数,在os模块中,这个函数可以创建一个新的进程
###################例子#######################
import os
import time
ret = os.fork()
# 当程序执行到这句话,程序会新建一个进程,这时,会出现一个全新的进程来执行后边的代码
if ret == 0:
while True:
print("the one")
time.sleep(1)
else:
while True:
print("the two")
time.sleep(1)
########################例子结束#####################
# 注意,fork在windows不存在,这个只是在linux(unix)中的函数
getpid、getppid
getpid()获得当前进程的pid,getppid()获得当前进程的父进程
在新建进程之后子进程和父进程执行的基本一样(这里只是不执行父进程专有的代码,其他的代码子进程同样会执行)
全局变量在多个进程中不共享
#################例子#########################
import os, time
g_num = 666
tmp = os.fork()
if tmp == 0:
print("*"*20)
print(g_num)
g_num +=111
time.sleep(2)
print("this is son pid = {0}, ppid = {1}, g_num_id = {2}, g_num = {3}".format(os.getpid(), os.getppid(), id(g_num), g_num))
else:
print("*"*20)
print(g_num)
print("this is father pid = {0}, ppid = {1}, g_num_id = {2}, g_num = {3}".format(os.getpid(), os.getppid(), id(g_num), g_num))
##################例子结束################
多个fork()同时出现
#########代码################
import os, time
ret = os.fork()
if ret ==0:
print("1".center(10, "*"))
else:
print("2".center(10,"*"))
ret = os.fork()
if ret ==0:
print("11".center(10,"-"))
else:
print(print("22".center(10,"+")))
"""
注意:这里的结果中,包含来两个11,22
这里和前边说的在fork()处分开后,代码都会分别执行,也就是后边的fork()是在单个进程中的再一次分进程了
"""
######################代码结束################################
Process创建子进程
from multiprocessing import Process
############例子####################
from multiprocessing import Process
import time
def test():
while True:
print("*"*20)
time.sleep(1)
p = Process(target = test) # 在此开始一个新的进程
p.start() # 在此运行test中的代码
while True:
print("666")
time.sleep(1)
##################例子结束####################
主进程等待子进程结束后才停止
name.join():这里表示堵塞 等待name执行完毕之后才继续执行join()后的代码
join([timeout]):这里表示的是超时时间,等待的最长时间,timeout不是必须参数
##############################################################
Process子类
用Process子类来进行进程的控制可以达到简化的效果
###############例子####################################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from multiprocessing import Process
import time
class Test(Process):
def run(self):
while True:
print("这里是用来测试Process的子类的一个方法")
time.sleep(1)
p = Test()
p.start()
while True:
print("this is main")
time.sleep(1)
"""
得到的运算结果是:
this is main
这里是用来测试Process的子类的一个方法
this is main
这里是用来测试Process的子类的一个方法
this is main
这里是用来测试Process的子类的一个方法
this is main
这里是用来测试Process的子类的一个方法
......
"""
#####################例子结束######################
进程池(Pool)
推荐使用这种方法创建进程
#############例子######################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from multiprocessing import Pool
import os, time, random
def test(num):
for i in range(10):
print("the pid is {}, the num is {}".format(os.getpid(), num))
time.sleep(1)
p = Pool(3) # 这里表示设置的最大执行数
for i in range(10):
print("this is {}".format(i))
# 向Test中添加参数(i,),并运行test
p.apply_async(test, (i,))
time.sleep(1)
print("*"*10)
# 添加进程后关闭进程池
p.close()
# 进程阻塞,如果不添加这句话会出现主进程执行结束后直接关闭,子进程无法执行
p.join()
"""
this is 0
the pid is 16699, the num is 0
this is 1
the pid is 16699, the num is 0
the pid is 16700, the num is 1
the pid is 16699, the num is 0
this is 2
the pid is 16700, the num is 1
the pid is 16701, the num is 2
the pid is 16699, the num is 0
the pid is 16700, the num is 1
this is 3
the pid is 16701, the num is 2
the pid is 16700, the num is 1
the pid is 16699, the num is 0
the pid is 16701, the num is 2
this is 4
the pid is 16700, the num is 1
the pid is 16699, the num is 0
this is 5
the pid is 16701, the num is 2
the pid is 16700, the num is 1
the pid is 16699, the num is 0
the pid is 16701, the num is 2
this is 6
the pid is 16700, the num is 1
the pid is 16699, the num is 0
the pid is 16701, the num is 2
this is 7
the pid is 16700, the num is 1
the pid is 16699, the num is 0
the pid is 16701, the num is 2
this is 8
the pid is 16700, the num is 1
the pid is 16699, the num is 0
the pid is 16701, the num is 2
this is 9
"""
##################例子结束########################
# 注意:Pool进程池并不是设置的越大越好
# 这里还有一个堵塞式添加方法(apply()),添加的方式是上一个添加的进程执行完毕后才会添加新的进程。
################################################################
进程间的通信Queue
from multiprocessing import Queue
q = Queue()
q.put(),q.get(),q.empty(),q.full(),q.get_nowait(),q.put_nowait()
# 这里注意:py文件名一定不能和Python中的保留名相同,不然会报错
################例子#######################
from multiprocessing import Process
from multiprocessing import Queue
import os, time
def write(num):
for i in range(10):
print("the num_in is {}".format(i))
num.put(i)
time.sleep(1)
def read(num):
while True:
if not num.empty():
tmp = num.get(True)
print("the tmp is {}".format(tmp))
time.sleep(1)
else:
break
if __name__ =="__main__":
num = Queue()
qw = Process(target = write, args = (num, ))
qr = Process(target = read, args = (num, ))
qw.start()
qr.start()
qw.join()
qr.join()
#################例子结束####################
进程池中的Queue
from multiprocessing import Manager, Pool
q = Manager().Queue()
#其他创建的方式相同
##########################################################
多进程拷贝文件
###################例子#############################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from multiprocessing import Pool, Manager
import os
def cpFile(name, oldFolderName, newFolderName, queue):
fr = open(oldFolderName + "/" + name)
fw = open(newFolderName + "/" + name , "w")# 注意,这里的fr.read()只是用于现在的小测试,不用于大文件的读写
content = fr.read()
fw.write(content)
fr.close()
fw.close()
queue.put(name)
def cpMain(): # 获取文件夹名字
oldFolderName = input("请输入文件夹的名字:") # 创建新文件夹
newFolderName = oldFolderName + "-复件"
os.mkdir(newFolderName)
fileName = os.listdir(oldFolderName)
pool = Pool(5)
queue = Manager().Queue()
for name in fileName:
pool.apply_async(cpFile, args = (name, oldFolderName, newFolderName, queue))
num = 0
allNum = len(fileName)
while num
> 僵尸进程,父进程死了,子进程没死>> 孤儿进程
##############################################################
线程的执行顺序
线程的执行顺序由操作系统的调度算法决定
#################例子###########################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import threading
import time
class Test(threading.Thread):
def run(self):
for i in range(5):
time.sleep(1)
print("{} is a test by pid = {}".format(i, self.name))
def test():
for i in range(3):
t = Test()
t.start()
if __name__ =="__main__":
test()
"""
运行结果:
0 is a test by pid = Thread-1
0 is a test by pid = Thread-2
0 is a test by pid = Thread-3
1 is a test by pid = Thread-1
1 is a test by pid = Thread-2
1 is a test by pid = Thread-3
2 is a test by pid = Thread-1
2 is a test by pid = Thread-3
2 is a test by pid = Thread-2
3 is a test by pid = Thread-1
3 is a test by pid = Thread-2
3 is a test by pid = Thread-3
4 is a test by pid = Thread-1
4 is a test by pid = Thread-2
4 is a test by pid = Thread-3
#注意:这样的结果说明线程同时运行,所以o开头的三个并排
"""
###########################例子结束####################
线程共享全局变量
这里注意:线程间虽然可以共享全局变量,但是多个线程同时对同一个全局变量进行操作时有出现同时操作导致数据出错的危险。
避免全局变量被修改的方式
这里可以用轮询方法来避免,但是这个方式用的是循环,相比很占资源
轮询:用一个死循环来判断所要执行的代码是否符合条件,不符合就一直判断,直到判断成功
这里推荐的方式是 互斥锁
threading 模块中的Lock类,用于锁定
# 创建锁,默认是未上锁的状态
mutex = Lock() # 调用锁
# 上锁,这里如果有多个上锁,则会发生抢占,一方上锁
#则另一方发生阻塞,等待上锁方的结束后在上锁或执行
mutex.acquire()
#解锁,用于对metex上锁的进程解锁,解锁后,阻塞的线程会再次抢占上锁
mutex.release() #解锁
###############例子#######################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from threading import Thread, Lock
g_num = 0
def test1():
global g_num
metux.acquire()
for i in range(10000000):
g_num += 1
print("the test1's g_num is {}".format(g_num))
metux.release()
def test2():
global g_num
metux.acquire()
for i in range(10000000):
g_num += 1
print("the test2's g_num = {}".format(g_num))
# metux.release()
metux = Lock()
def main():
t1 = Thread(target = test1)
t1.start()
t2 = Thread(target = test2)
t2.start()
if __name__ == "__main__":
main()
"""
运行结果:
the test1's g_num is 10000000
the test2's g_num = 20000000
"""
#这里特别注意:互斥锁中的后一个不必写解锁代码,不然报错RunTimeError错误,提示解锁了未锁定的线程
###############例子结束###################
添加锁的原则是:在保证程序正确的前提下,尽可能的少锁住代码。(这样锁死的时间就越
少)
###########################################
死锁
两者之间相互有限制对方的条件,造成死循环,这就是死锁
acquire()中有参数:blocking = True,timeout = -1,其中blocking = True表明默认是阻
塞的,timeout = -1 表示超时时间默认是无限的。如果设置为False则是非阻塞锁
可以通过acquire()中的参数来解决思索问题
###########################################################
同步
同步就是协同步调,按预定的先后次序运行。
可以通过多个互斥锁来实现同步
###################例子#########################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from threading import Thread, Lock
from time import sleep
class Task1(Thread):
def run(self):
while True:
if lock1.acquire():
print("task1".center(20,"*"))
sleep(0.5)
lock2.release()
class Task2(Thread):
def run(self):
while True:
if lock2.acquire():
print("task2".center(20,"*"))
sleep(0.5)
lock3.release()
class Task3(Thread):
def run(self):
while True:
if lock3.acquire():
print("task3".center(20,"*"))
sleep(0.5)
lock1.release()
lock1 = Lock()
lock2 = Lock()
lock2.acquire()
lock3 = Lock()
lock3.acquire()
t1 = Task1()
t2 = Task2()
t3 = Task3()
t1.start()
t2.start()
t3.start()
'''
运行结果:
*******task1********
*******task2********
*******task3********
*******task1********
*******task2********
*******task3********
*******task1********
*******task2********
*******task3********
*******task1********
'''
############################例子结束#################
生产者与消费者模式解决耦合问题
实现的原理是通过在生产者和消费者之间添加缓冲,来解决代码执行之间的产出与消耗不平
衡的问题(多个进程间数据的处理)
先进先出(fifo)队列,先进后出(filo)栈
################例子#########################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from threading import Thread
from queue import Queue
from time import sleep
class Producer(Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() < 1000:
for i in range(100):
count += 1
msg = "产品" + str(count)
print("产出"+msg)
sleep(0.5)
class Consumer(Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() >100:
for i in range(5):
msg = self.name + "消费:" + queue.get()
print(msg)
sleep(1)
if __name__ == "__main__":
queue = Queue()
for i in range(500):
queue.put("初始产品" + str(i))
for i in range(2):
p = Producer()
p.start()
for i in range(5):
c = Consumer()
c.start()
#########################例子结束######################
ThreadLocal对象在线程中的使用
threadlocal是用于解决多线程之间的共享数据的参数紊乱问题
obj = threading.local()
此时可以用obj来替换原来的全局变量
####################################################
异步
#####################例子##############################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from multiprocessing import Pool
from time import sleep
import os
def test1():
print("this is test1>>>{}, ppid = {}".format(os.getpid(), os.getppid()))
for i in range(5):
print("test1>>>>>{}".format(i))
sleep(0.5)
return "test1"
sleep(1)
def test2(args):
print("this is test2>>>pid = {}, ppid = {}".format(os.getpid(),os.getppid()))
print("the args = {}".format(args))
if __name__ == "__main__":
pool = Pool()
#注意这里的callback函数中的args是test1传入的return
pool.apply_async(func = test1, callback = test2)
while True:
sleep(7)
print("主进程,pid = {}".format(os.getpid()))
#运行结果
this is test1>>>4383, ppid = 4382
test1>>>>>0
test1>>>>>1
test1>>>>>2
test1>>>>>3
test1>>>>>4
this is test2>>>pid = 4382, ppid = 4090
the args = test1
主进程,pid = 4382
##################例子结束#####################
GIL(全局解释锁)
这里特别注意:在python中多进程比多线程的效率要高
from ctypes import *
#加载动态库
lib = cdll.LoadLibrary("loadName")
#这里是用于导入库
####################分隔########################################
网络编程
tcp/ip协议层次
应用层:应用层,表示层,会话层
传输层:传输层
网络层:网络层
链路层:数据链路层,物理层
#####################
端口
端口号是唯一的
端口号0~65535其中,0-1023是国定的端口号,其他的是动态端口号
IP
socket
本地的进程间通信(IPC)可以是队列,同步
网络中的进程通信:socket(套接字)
创建一个tcp socket(tcp 套接字)
##########################
import socket
s.socket.socket(socket.AF_INET, socket.SOCK_STREAM)
########################
创建一个udp socket
####################
import socket
#tcp和udp之间的区别就在于第二个参数socket.SOCK_STREAM(DGRAM)
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
##############
注意:udp比tcp快,但是不稳地,容易丢数据
####################例子##################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from socket import *
#这是一个关于upd发送信息的小demo
def test():
udpsend = socket(AF_INET, SOCK_DGRAM)
recAddr = ("127.0.0.1", 8080)
sendData = input("请输入要发送的信息:")
#下边的bytes是为了发送的编码正确,还可以用sendData.encode("utf-8")代替
udpsend.sendto(bytes(sendData, encoding = "utf-8"), recAddr)
udpsend.close()
if __name__ == "__main__":
test()
#注意:这里这样的发送方式在电脑中会无法正常的显示,电脑及时接收到了信息也不会显示
#############例子结束###########################
绑定端口
请求方一般不绑定,服务方才绑定
udpSocket.bind(("",自己的端口)) # 这里""代表自己,所以可以是空的
接收数据
#################例子##################3
from socket import *
udpSocket = socket(AF_INET, SOCK_DGRAM)
udpSocket.bind("", 6666) # 这里是端口绑定
recvData = udpSocket.recvfrom(1024) #接收端口
print(recvDate)
######################例子结束##################
单工:只能接收,半双工:同一时刻只能接收或是发送,全双工:可接可发
socket(套接字)是全双工的
编码:encode("utf-8")
解码:decode("utf-8")
echo服务器:将收到的信息原封不动的返回
简易的全双工信息收发器:
#########################代码#############################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from threading import Thread
from socket import *
# 接收数据,然后打印
def recvData():
while True:
recvInfo = udpSocket.recvfrom(1024)
print(">:{}:{}".format(str(recvInfo[1]), recvInfo[0]))
# 发送数据
def sendData():
while True:
sendInfo = input("\r<:")
print(">:")
udpSocket.sendto(sendInfo.encode("utf-8"), (whichIp, whichPort))
udpSocket = None
whichIp = ""
whichPort = 0
def main():
global udpSocket
global whichIp
global whichPort
whichIp = input("对方的IP:\t")
whichPort = int(input("对方的Port:\t"))
udpSocket = socket(AF_INET, SOCK_DGRAM)
udpSocket.bind(("", 6666))
tr = Thread(target = recvData)
ts = Thread(target = sendData)
tr.start()
ts.start()
tr.join()
ts.join()
if __name__ == "__main__":
main()
#########################代码结束############################
####################################################################
linux下安装wireshark抓包软件并解决问题
sudo apt-get install -y wireshark
打开时提示权限不足
解决方法:
注意:本解决方法参考于CSDN论坛_Rocky_作者
网址为:http://blog.csdn.net/wilsonpeng3/article/details/47209915
sudo apt-get install libcap2-bin # 这里提示已经安装(或是最新)
# 添加组,wireshark,但是安装软件时已经创建,这里可以省略
sudo groupadd wireshark
# 将自己添加到wireshark组
sudo usermod -a -G wireshark 'username'
newgrp wireshark
#更改组别
sudo chgrp wireshark /usr/bin/dumpcap
# 添加权限(1-x, 2-w, 4-r)
sudo chmod 754 /usr/bin/dumpcap
# 这里原作者有两个方法,我选择一个简单的
sudo setcap cap_net_raw,cap_netadmin=eip /usr/bin/dumpcap
sudo reboot now
# 至此,问题解决
###################################################################
pack和unpack的使用
小端:低地址存低位,高地址存高位
大端:低地址存高位,高地址存低位
读写请求:操作码(1【rd】,2[wr])文件名 0(1b) 模式 0(1b)
数据包:操作码(3【data】)块编号(2byte) 数据(512byte)
ACK:操作码(4【ACK】) 块编号(2byte)
ERROR:操作码(5 【ERR】)差错码(2byte)差错信息(n byte String) 0 (1 b)
#######################示例代码###################
import struct
from socket import *
# 这里对下面的!H8sb5sb解释:!H占两个,表示操作码,8s是文件名的占位长度,b是0的占
# 位长度,5sb同理
sendData = struct.pack("!H8sb5sb", 1, "test.txt", 0, "octet", 0)
udpsocket = Socket(AF_INET, SOCK_DGRAM)
udpsocket.sendto(sendData, ("ip",port)) # 发送
result = struct.unpack("!H", sendData[:2])
print(result) # 这里打印的是1 其实这里就是对pack的解包
udpsocket.close() # 关闭socket
#######################代码结束#################
###############tftp下载代码##################
# -*- coding:utf-8 -*-
import struct
from socket import *
import time
import os
def main():
#0. 获取要下载的文件名字:
downloadFileName = raw_input("请输入要下载的文件名:")
#1.创建socket
udpSocket = socket(AF_INET, SOCK_DGRAM)
requestFileData = struct.pack("!H%dsb5sb"%len(downloadFileName), 1, downloadFileName, 0, "octet", 0)
#2. 发送下载文件的请求
udpSocket.sendto(requestFileData, ("192.168.119.215", 69))
flag = True #表示能够下载数据,即不擅长,如果是false那么就删除
num = 0
f = open(downloadFileName, "w")
while True:
#3. 接收服务发送回来的应答数据
responseData = udpSocket.recvfrom(1024)
# print(responseData)
recvData, serverInfo = responseData
opNum = struct.unpack("!H", recvData[:2])
packetNum = struct.unpack("!H", recvData[2:4])
print(packetNum[0])
# print("opNum=%d"%opNum)
# print(opNum)
# if 如果服务器发送过来的是文件的内容的话:
if opNum[0] == 3: #因为opNum此时是一个元组(3,),所以需要使用下标来提取某个数据
#计算出这次应该接收到的文件的序号值,应该是上一次接收到的值的基础上+1
num = num + 1
# 如果一个下载的文件特别大,即接收到的数据包编号超过了2个字节的大小
# 那么会从0继续开始,所以这里需要判断,如果超过了65535 那么就改为0
if num==65536:
num = 0
# 判断这次接收到的数据的包编号是否是 上一次的包编号的下一个
# 如果是才会写入到文件中,否则不能写入(因为会重复)
if num == packetNum[0]:
# 把收到的数据写入到文件中
f.write(recvData[4:])
num = packetNum[0]
#整理ACK的数据包
ackData = struct.pack("!HH", 4, packetNum[0])
udpSocket.sendto(ackData, serverInfo)
elif opNum[0] == 5:
print("sorry,没有这个文件....")
flag = False
# time.sleep(0.1)
if len(recvData)<516:
break
if flag == True:
f.close()
else:
os.unlink(downloadFileName)#如果没有要下载的文件,那么就需要把刚刚创建的文件进行删除
if __name__ == '__main__':
main()
##########################代码结束################################
udp广播
广播只能在udp中使用,tcp中无法使用广播。
####################代码#########################
import socket, sys
# 下边的是广播地址,这里这样写更好,程序会自动查找当前的广播地址
dest = ("", port)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOLSOCKET, socket.SO_BROADCAST, 1) # 设置广播
s.sendto("hi",dest)
print("wait")
######################结束##########################
tcp 服务器代码
tcp:传输控制协议;稳定 udp:用户数据包协议;不稳定
tcp服务器流程:socket(),bind(), lisent(), accept(), read(), write(), close()
tcp客户端:socket(), connect(), write(), read(), close()
######################代码#############################
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind("", 1024) # 绑定端口
# 设置连接上限,这里最多可以连接5个客户端,多余的则拒绝服务,并且,只服务最前的那
# 个客户端
serverSocket.listen(5)
# accpt() 函数返回值是一个tuple,0表示新的客户端socket,1表示新的客户端的ip和
# port
clientSocket, clientInfo = serverSocket.accpt()
recvData = clientSocket.recv(1066)
print("%s:%s" %(str(clientInfo), recvData))
# 关闭连接,先关闭客户端,再关闭server
clientSocket.close()
serverSocket.close()
###########################代码结束######################
tcp客户端
##################代码######################
from socket import *
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect("serverIp", port) # 这里的代码只是一个提示
clientSocket.send("test".encode("utf-8"))
recvData = clientSocket.recv(1024)
print("recvData:%s" %(recvData))
clientSocket.close()
########################代码结束#######################
一般情况下bind服务器,listen绝大部分是服务器
#######################分隔#######################################
Ciso 的packet tracer
hub集线器现在基本已经废弃,现在一般用交换机
路由器:链接不同网段的网络,使不同网段的设备可以通讯
mac地址在通信传输中,是动态的,在两个设备之间会发生变话
IP地址在通信传输中,是静态的,在整个传输中不会发生变化
########################分隔####################
tcp三次握手、四次挥手
client connect()方法到server accept()方法,accept()方法返回,client发起请求
syn>>>> syn+ack<<<<<<<<<<<< ack>>>>>>>>>>>>>>>
tcp传输前会发送ack包确认,但是udp不会进行确认,所以有tcp比udp稳定
client close()方法,会通知到server,server会回复通知信息,然后client回复,挥手完
###################分隔##################
长连接、短连接
长连接:在连接不断的情况下不停的发送数据(不挥手)
短连接:资源相对很短暂的情况下,传输完就挥手
ping的时候TTl用来确定经过的路由器个数,每经过一个路由器,ttl = 128-1
MSL是一个数据包在网络上的存活时间
#######################分隔########################
listen参数问题
listen()中的参数表示最大的链接数,当客户端的请求数大于服务端的链接数时,链接阻塞
注意:listen()的参数在Linux中不管用,linux会自动根据自己的配置来计算listen的参数
################分隔#######################
常见网络攻击
tcp半连接:三次握手的最后一步client返回信息不发送,这样syn信息会在server中保存很
久
dns攻击
通过劫持主机的dns,更改你的解析请求,达到欺骗的效果
Python使用原始套接字
#######################分隔##########################
# 单进程服务器
#!/usr/bin/env python3
#-*- coding:utf- -*-
from socket import *
setSocket = socket(AF_INET, SOCK_STREAM)
# 重复使用绑定的信息
setSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
localAddr = ("", 1024)
setSocket.bind(localAddr)
setSocket.listen(5)
while True:
print("主进程,等待新用户的到来".center(30,"-"))
newSocket, destAddr = setSocket.accept()
print("主进程,即将处理[%s]" %str(destAddr))
try:
while True:
recvData = newSocket.recv(1024)
if len(recvData) > 0:
print("recv[%s]:%s" %(str(destAddr), recvData))
else:
print("客户已关闭连接".center(30, "*"))
break
finally:
newSocket.close()
serSocket.close()
########################分隔######################
# 多线程(进程)服务器
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from socket import *
from multiprocessing import *
from time import sleep
def dealwithClient(newSocket, destAddr):
while True:
recvData = newSocket.recv(1024)
if len(recvData) > 0:
print("recv[%s]:%s" %(str(destAddr), recvData))
else:
print("客户已关闭连接".center(30, "*"))
break
newSocket.close()
def main():
serSocket = socket(AF_INET, SOCK_STREAM)
serSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
localAddr = ("", 1024)
serSocket.bind(localAddr)
serSocket.listen(5)
try:
while True:
print("主进程等待新用户的到来".center(20, "*"))
newSocket, destAddr = serSocket.accept()
print("主程序,即将进行处理[%s]" %str(destAddr))
# 这里的进程创建改为线程创建就是多线程服务器了
client = Process(target = dealwithClient, args=(newSocket, destAddr))
client.start()
# 这里因为已经cp了一个子进程,所以父进程的socket可以关闭
# 注意:当这里是线程的调用时不可以关闭,因为线程共享数据,关闭了这个
# ,那么其他新创建的线程也一并关闭了
newSocket.close()
finally:
serSocket.close()
if __name__ == "__main__":
main()
##############################分隔######################
# 单进程非阻塞服务器
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from socket import *
serSocket = socket(AF_INET, SOCK_STREAM)
localAddr = ("", 1024)
serSocket.bind(localAddr)
serSocket.setblocking(False)
serSocket.listen(100)
# 这里创建一个list用来存储client
clientList = []
while True:
# 这里是用来接收客户端传输过来的数据
# 这里需要特别注意:如果客户端没有传输数据过来,那么这里会报错,所以用try
try:
clientSocket, clientAddr= serSocket.accept()
except:
pass
else:
print("there are a new client:%s !" %str(clientAddr).center(30,"*"))
clientSocket.setblocking(False)
clientList.append((clientSocket, clientAddr))
for clientSocket, clientAddr in clientList:
# 这里同样会出现上边的传输数据报错的问题,所以用try
try:
recvData = clientSocket.recv(1024)
except:
pass
else:
if len(recvData)>0:
print("客户端【%s】发送的数据是:%s" %(str(clientAddr),
recvData.decode("utf-8")))
else:
clientSocket.close()
clientList.remove((clientSocket, clientAddr))
print("客户端已经下线")
##########################代码结束###########################
select服务器(了解)
# select可以跨平台
# 注意:select最多监听1024个套接字,也就是最多服务1023个客户端,并且由于select的
# 遍历方式是轮询,大大限制了服务器,所以基本不用
#######################代码############################
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
from select import select
from socket import *
import sys
serSocket = socet(AF_INET, SOCK_STREAM)
serSocket,bind("",1024)
serSocket.listen(5)
# 这里定义一个list用来存起始server和一个sys的输入判断
inputs = [serSocket, sys.stdin]
running = True
while True:
# 这里的select的三个参数是:判断是否是可接收数据的集合,可发送的,判断异常的
readable, writeable, execptable = select(inputs, [], [])
for sock in readable:
# 监听到新的端口
if sock == serSocket:
conn, addr = serSocket.accept()
inputs.append(conn)
elif sock == sys.stdin:
cmd = sys.stdin.readline()
running = False
else:
# 读取客户端发送的数据
data = sock.recv(1024)
if data:
sock.send()
else:
inputs.remove(sock)
sock.close()
##########################结束######################################
epoll版服务器
io多路复用服务器中,只有poll解决了套接字上限问题
poll用的遍历方式不是轮询,而是事件通知机制
from select import *
epoll = epoll()
epoll.register(事件,EPOLLIN(可读)|EPOLLLOUT(可写)| EPOLLET(ET模式))
总的来说总共分为三步:
1、创建套接字;2、建立监听;3、处理监听
#####################分隔###########################
协程
又称为微线程,纤程
计算密集型:需要大量的CPU资源,此时不应用多线程(gil,只占用一个核心),用多进程
io密集型:需要网络资源,此时用多线程
###############################分隔##########################
http请求方式
GET:获取数据
POST:修改数据
PUT:保存数据
DELETE:删除数据
OPTION:询问服务器的某种支持特性
HEAD:返回报文头
url :位置,urn:名字
######################################分隔#################
django
虚拟环境
安装虚拟环境:
Python3 :pip3 install python3-venv
python2 :pip install python-virtualenvs
创建虚拟环境:
python3 -m venv DirName(这个可以自定义名称)
python -m virtualenv DirName
启动虚拟环境:
cd /home/DirName/bin/;source activate
关闭虚拟环境:
deactivate
安装django
pip install django==1.8 # 这里的==1.8表示的是要安装的版本号,可以不写
创建一个新的项目
django-admin startproject Demo # 这里的Demo是django的项目名
启动项目
python3 manage.py startapp Demo
运行服务
python3 manage.py runserver 8080 # 这里的8080是端口号,可以随意更改(>1023)
设置迁移
python3 manage.py makemigrations
应用迁移
python3 manage.py migrate
进入shell
python3 manage.py shell
视图view:接受请求,逻辑处理,调用数据,输出响应
配置url:在自己的应用中配置正则url(正则表达式,视图的名称)
DIRS:定义目录
APP_DIRS:在项目的根目录创建模板目录
建的项目不打算移植,可以用DIRS,希望以后移植,用APP_DIRS更好一些。
django模板处理
1.加载模板内容
2.根据模板内容渲染
加载渲染的完整代码:
####################例子#################
from django.tmplate import loader, RequestContext
from django.http import HttpResponse
def index(request):
tmp = loader.get_tmplate("Demo/demo.html")
context = RequestContext(request, {})
return HttpResponse(tmp.render(context))
####################例子结束###################
简化代码:
################例子##########################
from django.shortcuts import render
def index(request):
return render(request, "Demo/demo.html")
# 这里的简化代码中render_to_string("")返回一个字符串
# render(request, "模板", context)
######################例子结束####################
DTL语言
变量
{{ var }}:字典,属性或方法,数字索引,空字符串,
注意:模板中调用方法不能传递参数,因为不能有()出现在模板中
标签
{% 代码 %}
{%for%}
{{forloop.counter}} # 返回一个当前是第几次返回的数字
{%empty%} # 当for in 的list不存在或空时,执行这个标签
{%endfor%}
{%if%}
{%elif%}
{%else%}
{%endif%}
{%comment%}
这里是一个多行注释
{%endcomment%}
反向解析:
{%url "namespace:name" "参数1" "参数2" %} # 反向解析
{%crsf_token%} # 用于跨站请求伪造保护
过滤器
{{变量|过滤器}} # “|” 符合是管道符号,用来应用过滤器
这里用“:”来传递参数
{{name|length>10}} 选出长度大于10 的name
注释
{# 注释 #}
模板的继承
####################代码###################3
# 这是用在父模板的,base.html
{%block my_name%} # 这里的my_name只是用做变量的区分
这里是要填充的内容
{%endblock my_name%}
# 父模板中可以用很多的{%block%}
# 这是用在子模板的,demo.html
{%extends "要继承的父模板的位置"%} # 这个语句要写在子模板的首行
{%block my_name%}
这里来填充父模板的block
{%endblock my_name%}
注意:一旦使用了继承,那么要显示的内容只能写在block中,写在外边的无法显示
html转义:
1 用过滤器:
{{value|escape}} # 这里是转义,默认是转义
{{value|safe}} # 这里是不转义
2 用标签
{%autoescape off%} # 这里是关闭自动转义
{{value}} # 这里是不希望转义的后台传输过来的内容
{%endautoescape%}
#####################分隔###################3
django高级
静态文件
static
STATIC_URL = "url"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
# 注意这里的static是项目下的一个文件夹的名字,这里必须相同
]
在网页中首行添加
{%load static from staticfiles %}
在img标签中的src使用{%static "fileName"%}
########################分隔#######################
中间件
MIDDLEWARE_CLASS
是一个轻量级、底层的插件系统
__init__方法:第一次访问
process_request:url匹配前
process_view:视图前
process_tmplate_response:视图后,html前,在请求上调用
process_response:HTML后,返回到浏览器之前
process_exception:视图中出错,到次方法,转到process_response
######################分隔######################
