1.深浅拷贝
在正式开始说深浅拷贝之前,我们先来看一个例子吧
import copy
a = [1, 2, 3, [4, 5]]
b = copy.copy(a)#浅拷贝
c = copy.deepcopy(a)#深拷贝
d = a
a.append(6)
a[3].append(6)
print("a =", a)
print("b = ", b)
print("c = ", c)
print("d = ", d)
输出结果是什么呢???
结果:
a = [1, 2, 3, [4, 5, 6], 6]
b = [1, 2, 3, [4, 5, 6]]
c = [1, 2, 3, [4, 5]]
d = [1, 2, 3, [4, 5, 6], 6]
Process finished with exit code 0
结合这个例子,我们再来看深浅拷贝,上面这个例子中,列表中套列表,最里层列表中的元素叫做子对象,外边的叫父对象,当你给最里层的列表中添加元素时,深拷贝不会跟着添加该元素,因为深拷贝是完全拷贝的,最里层的列表页独自占有一段自己的内存的,而浅拷贝是不完全拷贝的,拷贝出来的最里层列表跟a的最里层列表是共享一段id存储地址的,而用等号给一个变量重新赋值,前后两个变量的id存储地址是一样的
2.metaclass(元类)
其实,python中的类也是一个对象,元类就是用来创建这些类的,python中的类是type类的对象,下面我们来看一个例子
class MyType(type):
def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)
def __call__(self, *args, **kwargs):
obj = self.__new__(self, *args, **kwargs)
self.__init__(obj)
class Foo(object, metaclass=MyType):
def init(self):
pass
def new(cls, *args, **kwargs):
return object.new(cls, *args, **kwargs)
foo = Foo()
上面的例子中,Foo()创建一个对象时,其实不仅仅是执行了Foo类的__init__(self)方法,Foo本身就是一个对象,所以他创建的时候就默认执行了type的__init__(self)方法,Foo()就是对象再加(),这样就会调用Mytype的__call__方法,然后__call__方法再去调用Foo的__new__方法和__init__方法,这样便创建了一个Foo对象;metaclass=Mytype使得默认创建类的type改为使用Mytype来创建类
3.反射:通过字符串的形式来操作对象中的成员
hasattr(),getattr(),setattr(),delattr()
4.单例模式
单例模式就是只有一个实例的意思 实现单例模式的方法:
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kwargs)
return cls._instance
class MyClass(Singleton):
pass
5.python中的单下划线和双下划线
__foo__:一种约定,python内部的名字,用来区别其他用户自定义的命名,防止命名冲突;
_foo:一种约定,用来指定变量私有,程序员用来指定私有变量的一种方式。不能用from module import * 导入,其他方面和公有一样访问;
__foo:表示他是私有成员,我们不能访问,如果要访问可通过_class(类名)_foo的方式进行访问
6.列表生成式和生成器
把列表生成式的中括号改为小括号后就成了生成器
>>> L = [x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x0000019D90F285C8>
>>> next(g)
0
>>> next(g)
1
7.*args和**kwargs
当你不确定传入几个参数时,就可以使用*args,他可以传递任意数量的参数:
def foo1(*args):
for i in args:
print(i)
foo1(1, 2, 3)
def foo(**kwargs):
for key, value in kwargs.items():
print("{}--{}".format(key, value))
foo(fruit1 = "apple", frult2 = "banaba")
8.__new__和__init__的区别
-
__new__是一个静态方法,而__init__是一个实例方法
-
__new__方法会返回一个创建的实例对象,而__init__不返回东西
-
只有在__new__返回一个cls的实例时后面的__init__才能被调用
- 当创建一个新实例时调用__new__,初始化一个实例时用__init__
9.python中的·作用域
本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)
10.GIL线程全局锁
是python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。
11.线程/进程/协程
- 线程就是调用cpu的最小执行单位
- 进程是最小的资源管理单位,一个进程有一个主线程和多个子进程
- 协程是一种比线程更加轻量级的存在,一个线程可以有多个协程,python里最常见的yeild就是协程的思想
12.闭包
闭包(closure)是函数式编程的重要的语法结构。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。
当一个内嵌函数引用其外部作作用域的变量,我们就会得到一个闭包. 总结一下,创建一个闭包必须满足以下几点:
- 必须有一个内嵌函数
- 内嵌函数必须引用外部函数中的变量
- 外部函数的返回值必须是内嵌函数
例子:
def outer(x):
y = 10
def inner():
return x*y
return inner
result = outer(2)()#结果为20
13.lambda匿名函数
例子:
#一个求x的二次方的匿名函数
lambda x: x*x
14.python中的is
is是对比地址,==是对比值
15.socket
要想理解socket,就要先来理解TCP,UDP协议
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何再它们之间传输的标准,
从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族。不同于ISO模型的七个分层,TCP/IP协议参考模型把所有的TCP/IP系列协议归类到四个抽象层中
应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等
传输层:TCP,UDP
网络层:IP,ICMP,OSPF,EIGRP,IGMP
数据链路层:SLIP,CSLIP,PPP,MTU
每一抽象层建立在低一层提供的服务上,并且为高一层提供服务,看起来大概是这样子的
我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,我们经常把socket翻译为套接字,socket是在应用层和传输层(TCP/IP协议族通信)之间的一个抽象层,是一组接口,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
应用程序两端通过“套接字”向网络发出请求或者应答网络请求。可以把socket理解为通信的把手(hand)
socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。socket的英文原义是“插槽”或“插座”,就像我们家里座机一样,如果没有网线的那个插口,电话是无法通信的。Socket是实现TCP,UDP协议的接口,便于使用TCP,UDP。
例子:
#socket_server.py
import socket
sk = socket.socket()#创建一个socket
print(sk)
address = ('127.0.0.1', 8000)
sk.bind(address)#为socket绑定ip地址和端口
sk.listen(3)#最多允许三个客户端连接
print("waiting...")
#等待客户端的连接,没有客户端连接之前是阻塞状态
cone, addr = sk.accept()#conne就像是服务端与客户端的一条通道,有多个客户端,就有多条这样的通道
print(cone)
print(addr)
cone.send(bytes("hello, 靓仔", "utf8"))
#socket_client.py
import socket
sk = socket.socket()#创建一个socket
print(sk)
address = ('127.0.0.1', 8000)
sk.connect(address)#为sk绑定连接的服务端的地址和端口号
data = sk.recv(1024)#接受服务端发送过来的数据
print(str(data, "utf8")
16.字符串格式化:%和.format
.format在许多方面看起来更便利.对于%最烦人的是它无法同时传递一个变量和元组.你可能会想下面的代码不会有什么问题:
"hi there %s" % name
但是,如果name恰好是(1,2,3),它将会抛出一个TypeError异常.为了保证它总是正确的,你必须这样做:
"hi there %s" % (name,) # 提供一个单元素的数组而不是一个参数
但是有点丑..format就没有这些问题.你给的第二个问题也是这样,.format好看多了
.format的使用方式:
s = "{0} is {1}".format("luyi", "handsome")
print(s)
#结果:luyi is handsome
#注意:这里的{}里面的0和1是可以省略的
17.装饰器
作用:为已经存在的对象添加额外的功能
例如给一个程序加上运行时间的功能:
import time
def show_time(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print("spend {}s".format(end_time-start_time))
return inner
@show_time
def foo():
print("hello world")
time.sleep(2)
foo()
#输出结果为:
hello world
spend 2.0009796619415283s
18.cookie和session
- cookie是存储在客户端的,可以跟踪会话,也可以保存用户的偏好设置或者保存用户名密码等,安全性不高
- session是存储在服务端的,可以跟踪会话,出现session技术的原因就是为了安全,session技术是要用到cookie技术的