黑马程序员--python高级编程

第二部分:高级进阶

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的地址,所以返回的值相同

 

1、模块调用

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()

type和isinstance的区别

'''
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)) #<class '__main__.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)        # <generator object <genexpr> at 0x000001F09B0EEFC0>
print(type(ge))  # <class 'generator'>
print(list(ge))  # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

python核心编程

在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]: <generator object <genexpr> at 0x7f626c132db0>

要打印出来, for 循环来迭代它

2、创建生成器,generator非常强大。如果推算的算法比较复杂,用类似列表生成式的 for 循环无法实现的时候,还可以用函数来实现。

In [30]: def fib(times):
   ....:     n = 0
   ....:     a,b = 0,1
   ....:     while n<times:
   ....:         yield b
   ....:         a,b = b,a+b
   ....:         n+=1
   ....:     return 'done'
   ....: 

生成器的特点:

  1. 节约内存
  2. 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
  • 凡是可作用于 for 循环的对象都是 Iterable 类型;
  • 凡是可作用于 next() 函数的对象都是 Iterator 类型
  • 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。

迭代器

迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

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解释器就会从上到下解释代码,步骤如下:

  1. def w1(func): ==>将w1函数加载到内存
  2. @w1

没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。

以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在新f1 函数内部先执行验证,再执行原来的f1函数,然后将原来f1 函数的返回值返回给了业务调用者。

 

模块修改,要重新加载reload
避免循环导入,鸡生蛋,蛋生鸡

  • is 是比较两个引用是否指向了同一个对象(引用比较)。深拷贝就返回false
  • == 是比较两个对象是否相等。

浅拷贝:拷贝引用,没有拷贝内容,地址给了,指向同一地址。
深拷贝:对一个对象所有层次的拷贝,借助copy.deepcopy模块。内容复制到新内存

列表拷贝可变,新内存。元祖不可变,copy.copy()指向同一位置(内存)。

垃圾回收

  • 小整数[-5,257)共用对象,常驻内存
  • 单个字符共用对象,常驻内存
  • 单个单词,不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁

编码风格正确认知

  • 促进团队合作
  • 减少bug处理
  • 提高可读性,降低维护成本
  • 有助于代码审查
  • 养成习惯,有助于程序员自身的成长

 

系统编程:进程&&线程


进程,能够完成多任务,比如 在一台电脑上能够同时运行多个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(著名网络公司,思科)公司发布的一个辅助学习工具,

为学习思科网络课程的初学者去设计、配置、排除网络故障提供了网络模拟环境。

TCP通信的整个过程,如下图:

 

掩码:二进制的掩码与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?

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)

 

WSGI接口

了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:

  1. 浏览器发送一个HTTP请求;

  2. 服务器收到请求,生成一个HTML文档;

  3. 服务器把HTML文档作为HTTP响应的Body发送给浏览器;

  4. 浏览器收到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开发。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值