6 Python高级

本文详细阐述了浏览器访问服务器的步骤,涉及DNS解析、TCP连接,以及Python中的网络概念如MAC地址、网络掩码和GIL。同时讲解了多线程、深浅拷贝、对象属性、封装、继承、多态、MRO、super使用、property属性和上下文管理器等内容。
摘要由CSDN通过智能技术生成

浏览器访问服务器的过程:

 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装饰器 进一步简化上下文管理器的实现方式。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值