浏览器访问服务器的过程:
1 先解析域名 将域名发送到DNS服务器 服务器将域名解析出的对应的IP地址发送给源主机
2 向http服务器发送tcp的三次握手
3 发送http的请求数据以及等待服务器的应答
4 发送tcp的四次挥手
Mac地址:在设备与设备之间数据通信时用来标记收发双方(网卡的序列号)
网络掩码:用来区分ip地址的网络号和主机号
GIL全局解释器锁
真正实现多并发的只有多进程,而多线程是个假的,实际上是一个在做,另一个在休息,只是看起来像是完成了并发的过程,因为python里面有GIL(C语言解释器遗留的问题),GIL让你的多线程的程序保证同一时刻只有一个线程在执行。
深拷贝和浅拷贝
浅拷贝:就是拷贝了引用 并没有拷贝内容。
#当一个变量==xxx的时候 约定为 这个指向了这个xxx(引用)
#浅拷贝 copy.copy()
#深拷贝 copy.deepcopy()
import copy
a = [11,22]
b = [33,44]
c = [a,b]
d = c
e = copy.copy(c)#只是把c中数据拷贝 指向不变
print(id(c))
print(id(e))
print(id(c[0]))
print(id(e[0]))
c[0].append(55)
print(c)
print(e)
结果:
4308789312
4308717632
4307619136
4307619136
[[11, 22, 55], [33, 44]]
[[11, 22, 55], [33, 44]]
copy.deepcopy()就是把所有东西都拷贝 拷贝的东西会分配新的地址 之前的数据改变也不会影响现在的数据。
import copy
a = [11,22]
b = [33,44]
c = [a,b]
d = copy.copy(c)
e = copy.deepcopy(c)
c.append([55,66])
print(c)
print(d)#d是将c中的a和b拷贝了 改变a和b的数据 d中的数据会改变
print(e)
结果:
[[11, 22], [33, 44], [55, 66]]
[[11, 22], [33, 44]]
[[11, 22], [33, 44]]
如果用copy.copy拷贝元组 id是不变的 因为元祖是不可变类型,数据不能修改。而deepcopy只要有可变类型就会拷贝,不可变类型也只是引用指向。
列表的切片也属于浅拷贝。
私有化
xx:公有变量
_x:单前置下划线 私有化属性和方法 类对象和子类可以访问
__x:双前置下划线 避免和子类中的属性命名冲突 无法在外部直接访问
__xx__:双前后下划线 魔法方法 如:__init__
xx_:单后置下划线 用于避免与python关键词的冲突
通过_Class__object机制就可以访问private。
导入模块的时候 如果是from xx import yy 应该注意变量指向的问题。
为什么要封装:
在使用面向过程编程时,当需要对数据处理时,需要考虑用哪个模板中哪个函数来进行操作,但当时用面向对象编程时,因为已经将数据存储到独立的空间中,这个独立的空间(即对象)中通过特殊的变量(__class__)能够获取到类(模板)。简单来说封装成类可以将代码划分更清晰,更有层次。
为什么要继承:
能够提升代码的重用率,开发一个类,可以在多个子功能中直接使用。继承能够有效的进行代码的管理。
怎么理解多态:子类重写方法 就调用子类的方法 子类没重写 就调用父类的
多继承以及MRO顺序
多继承中super调父类的被重写的方法
print("****多继承中super().__init__发生的状态*****")
class Parent(object):
def __init__(self,name,*args,**kwargs):#为避免多继承报错 使用不定长参数 接受参数
print('parent的init开始调用')
self.name = name
print('parent的init结束调用')
class Son1(Parent):
def __init__(self,name,age,*args,**kwargs):
print('Son1的init被调用')
self.age = age
super().__init__(name,*args,**kwargs)
print('Son1init结束调用')
class Son2(Parent):
def __init__(self,name,gender,*args,**kwargs):
print('Son2的init被调用')
self.gender = gender
super().__init__(name,*args,**kwargs)
print('Son2的init结束调用')
class Grandson(Son1,Son2):
def __init__(self,name,gender):
print('Grandson的init被调用')
#多继承时 如果使用类名.init()方法 有多个子类继承的时候 要把父类全部写一遍
#而super只用一句话 执行了全部父类的方法 这也是为何多继承需要全部传参的一个原因
super().__init__(name,age,gender)
print('Grandson的init结束调用')
print(Grandson.__mro__)
gs = Grandson('grandson',12,'男')
print(gs.name)
print(gs.age)
print(gs.gender)
__mro__结果:
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
类里面有一个mro属性 属性的值不是自己确定的 是python解释器里面有一个自己的算法(C3算法) --->用来重新规划 根据特殊的计算方式来得到一个通过super调用父类的时候 调用的顺序
如果用super(Son2,self).__init__(name,age,gender) 会拿着Son2在mro的结果中寻找顺序
super().__init__(name,age,gender) 什么都不写 默认是grandson
继承面试题:
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x,Child1.x,Child2.x)
Child1.x = 2
print(Parent.x,Child1.x,Child2.x)
Parent.x = 3
print(Parent.x,Child1.x,Child2.x)
结果:
1 1 1
1 2 1
3 2 3
类对象 实例对象 类方法 实例方法 类属性 实例属性:
类属性在内存只保存一份
实例属性在每个实例对象中都要保存一份
通过类创建实例对象时 如果每个对象需要具有相同名字的属性 那么就使用类属性 用一份即可。
为了修改类属性和实例属性 就会有类方法和实例方法:
方法包括:实例方法 类方法和静态方法 三种方法在内存中都属于类 区别在于调用方式不同。
实例方法:由对象调用 至少有一个self参数 执行实例方法时 自动将调用该方法的对象赋值给self。
类方法:由类调用 至少一个cls参数 执行类方法时 自动调用该方法的类赋值给cls。@classmethod
静态方法:由类调用 无默认参数。@staticmethod
实例对象可以调用类方法 实例方法 静态方法
类对象只能调用类方法和静态方法
property属性
一种用起来像是使用的实例属性一样的特殊属性 可以对应于某个方法。
class Foo:
def func(self):
pass
@property
def prop(self):
pass
foo = Foo()
foo.func()#调用实例方法
foo.prop#调用property属性(仅有一个self参数) 不用写括号
比如列表页面采用分页的功能显示 所以在向数据库中请求数据就要显示的指定获取从第m条道第n条的所有数据。分页的功能包括:
- 根据用户请求的当前页和总数据条数计算出m和n
- 根据m和n去数据库中请求数据
class Pager:
def __init__(self,current_page):
#用户当前请求的页码
self.current_page = current_page
self.per_items = 10#每页默认显示10 条数据
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
def end(self):
val = self.current_page * self.per_items
return val
p = Pager(3)
p.start #就是起始值 就是m
p.end #就是结束值 即n
python的property属性的功能是:property属性内部进行一系列的逻辑计算 最终将计算结果返回。
如果p.start写上括号 就相当于普通函数 需要考虑传不传参数 不加括号 就相当于是个属性。
property属性的两种方式:
- 装饰器 即:在方法上应用装饰器
- 类属性 即:在类中定义值为property对象的类属性
python分 经典类(python2)和新式类(继承object) python3默认继承object
新式类 具有三种实现@property装饰器:
class Goods(object):
def __init__(self):
self.original_price = 100
self.discount = 0.8
@property
def price(self):
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self,vaule):
self.original_price = vaule
@price.deleter
def price(self):
del self.original_price
pri = Goods()
val = pri.price#获取商品价格
print(val)
pri.price = 200#修改商品价格
del pri.price#删除商品价格
类属性方式:创建值为property对象的类属性。 有四个参数
class Foo():
def get_bar(self):
print("getter..")
return 'laownag'
def set_bar(self,vaule):
#必须两个参数
print('setter..')
return 'set vaule' + vaule
def del_bar(self):
print('deleter..')
return 'laownag'
BAR = property(get_bar,set_bar,del_bar,'description')
obj = Foo()
obj.BAR#自动调用第一个参数定义的方法 get_bar
obj.BAR = 'alex'#自动调用第二个参数定义的方法 并将alex作为参数传入
desc = Foo.BAR.__doc__ #自动获取第四个参数设置的值:description
print(desc)
del obj.BAR#自动调用第三个参数定义的方法 del_bar
通过使用property属性 能够简化调用者在获取数据的流程。
私有属性添加getter和setter方法:
class Money():
def __init__(self):
self.__money = 0#私有属性只能在类中调用 外界无法修改
def getmoney(self):
return self.__money
def setmoney(self,vaule):
if isinstance(vaule,int):
self.__money = vaule
else:
print('error:不是整形数字')
#设置一个属性 当对这个money设置值时调用setmoney 获取值时调用getmoney
mon = property(getmoney,setmoney)
m = Money()
m.money = 100#调用setmoney方法
print(m.money)#调用getmoney
with与上下文(context)管理器
对于系统资源如文件 数据库连接 socket而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。
任何实现了__enter__()和 __exit__() 方法的对象可称之为上下文管理器 上下文管理器对象可以使用with关键字 文件file对象也实现了上下文管理器。
# with open('out.txt','w') as f:
# f.write('hello')
#将以上代码写成enter exit方法(上下文管理器)
class File():
def __init__(self,filename,mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print('entering')
self.f = open(self.filename,self.mode)
return self.f
def __exit__(self, *args):
print('will exit')
self.f.close()
with File('out.txt','w') as f:
print('writing')
f.write('hello')
__enter__()方法返回资源对象 这里就是你将要打开的那个文件对象 __exit__()方法处理一些清除工作 因为File类实现了上下文管理器 接下来就可以使用with语句了
使用with语句 就无需显示的调用close方法了 由系统自动调用 哪怕中间遇到异常 close方法也会被调用 把资源释放。
实现上下文管理器的另外方式
python提供了一个contextmanager的装饰器 简化了上下文管理器的实现方法 通过yield将函数分成两部分 yield之前的语句在__enter__方法中执行 之后的语句在__exit__方法中执行 紧跟在yield后面的值是函数的返回值
from contextlib import contextmanager
@contextmanager
def my_open(path,mode):
f = open(path,mode)
yield f
f.close()
with my_open('out.txt','w') as f:
f.write('hello')
python提供了with语法用于简化资源操作的后续清除操作 是try/finally的替代方法 实现原理建立在上下文管理器之上 还提供了contextmanager装饰器 进一步简化上下文管理器的实现方式。