基础
-
布尔值:
- None
- False
- 所有值为0的数字(0,0.0,0L,0.0 0.0j)
- 空字符串 “”
- 空列表
- 空元祖
- 空字典
-
a is b 实际调用是 id(a) == id(b)
浮点数
浮点数,也就是小数,之所以叫浮点数,是因为一个浮点数的小数点位置是可变的,比如1.23x109和12.3x108完全相等
python 文件开头
- 第一行告诉mac/linux 文件为可执行文件
- 第二行指定编码为utf8
#!/usr/bin/env python3 # -*- coding: utf-8 -*-
python 没有 i j 这种语法, 只能 j =1 j=j 1
- 在为对象设置属性时, 尽量使用set get 设置方法可以拦截非法设置和取值, 不建议直接赋值属性。
- 私有方法 : 在类中, def __mehtond(): 是私有的方法, 例如,没有私有方法, 调用私有方法会报错。私有属性相似。
- 私有方法可以在类中的共同方法和私有方法中调用
- 方法:当实例数为时 0 当引用计数为0时,该方法将自动调用。
class Dog(): def __del__(): print(1) d1 = Dog() d2 = Dog() # 即使不手动删除以下两个变量, __del__ 代码运行完成后仍将执行 # del d1 # del d2
-
即使不手动删除实例对象, 程序执行完成后, 所有未引用的对象都会自动删除, 该方法仍将执行
-
import sys sys.getrefCount(variable) 测量变量引用的数量, 比实际数量大1
-
父类基类, 子类派生: class Dog(Animal) ,让Dog 类继承Animal 类
-
重写:在子类中定义与父类同名的方法, 调用子类实例时, 会调用子类的方法
-
调用被重写的父类的方法, 只需在子类重写方法中添加以下代码之一:
- Parent.mehtond(self)
- super().mehtond()
-
不会继承私有方法和私有属性。
-
集成多个类 class C(A, B )
-
实例属性不能在实例间共享, 实例间共享类属性。
-
静态方法用于处理逻辑和功能,这些逻辑和功能与。
-
创建对象的过程 :
1. 默认执行 __new__ 、__init__ 方法 2. __new__ 若在类上定义, 最后一定 return object.__new__(cls) 返回实例 3. 执行完 __new__ 方法, 返回实例对象, 此时将调用 __init__ 初始化对象的方法 4. 如果不定义 __new__ 和 __init__ 方法, 会执行默认方法
-
子类方法A调用父类的私有属性和私有方法,如果A是继承自父类的方法, 可调用父类的方法和属性, 若实现A时子类的方法, 父类的私有方法和私有属性不能调用。
-
避免多继承的方法相同, 可以使用多继承的调用顺序 className. 去查看
-
导出部分功能, 而不是导出整个文件的全局对象 , 注意 每个项目都是字符串的形式
__all__ = ['test1', 'test2'] def test1() : print('test1') def test2(): print('test2') def test3() : print(3)
def test4 ( ) : print ( 4 ) -
所有标准对象均可以用于布尔测试,同类型的对象之间可以比较大小,每个对象天生具有布尔值 True 或者 False。
-
下列对象的布尔值为 False, 除了下列对象的值, 其他任何对象的值都是True
- None
- False
- 0
- 0.0 浮点型 0
- 0L 长整形 0
- 0.0+0.0j 复数 0
- “” 空字符串
- [] 列表
- () 元祖
- {} 字典
-
值的比较
- 3 < 4 < 5 合法, 等同于 3 < 4 and 4 < 5
-
== 与 is 的区别
- == 只能判断值相等 - is 判断两个对象指向同一个内存, id 相同 (python中所有的数据类型都是对象)
-
深拷贝 浅拷贝,
import copy a = [1,2,3] b = copy.deepcopy(a) print(id(a)) print(id(b)) # 2439347758080 # 2439347705280 c = [a,b] d = copy.deepcopy(c) a.append(4) print(a) print(d[0]) # [1, 2, 3, 4] # [1, 2, 3] ```
-
原码、反码、补码
-
原码 : 转换成二进制时的代码
比如 1, 2, 分别转换成 0000 0001 , 0000 0010
-
反码:对原码二进制的每一位取相反的 数
比如 1的原码是 0000 0001 ,反码是 1111 1110
-
补码 : 在反码的基础上 + 1, 便是补码
比如 1的原码是 0000 0001 ,反码是 1111 1110, 补码是 1111 1111
-
-
为什么会有 原码、反码、补码?
因为计算机的数据是通过0 和 1 保存的, 无法保存负数, 所以便规定首个比特位用来表示数字的正负,0000 0001 表示 正1, 1000 0001 表示 -1.此时便引发了新的问题。0000 0001 + 1000 0001 = 1000 0010 , 即 1 + (-1) = -2. 因此产生了反码和补码来弥补新的问题。 1 + (-1) 即演变成了 1原码 + (-1补码)= 0000 0001 + 1111 1111 = 1 0000 0000 , 因为两个字节, 一个字节只能存 8 个位, 去掉首位, 变成了 0000 0000 , 即 1+ (-1) = 0 终于实现了。
-
位运算 : 按照比特位运算, 即把数字转换成二进制的形式进行运算
- 按位左移:所有二进制位向左移动n位, 低位补0,8 << 1, 8 按位移动1 位, 等于原来的 2倍 。 0000 0100 => 0000 1000
-
按位右移:所有二进制位向右移动n位, 高位补0,8 >> 1, 等于原来的一半, 0000 0100 => 0000 0010
-
按位与: 两个数字转换成二进制以后, 按位比较, 同一个位都为1, 则该位为1, 否则, 该位为0:0110 0101 & 0001 1110 = 0000 0100
0110 0101 0001 1110 0000 0100
-
按位或 : 两个数字转换成二进制以后, 按位比较, 同一个位上有一个为1,该位为1,否则为0 : 0110 0101 & 0001 1110 = 0111 1111
0110 0101 0001 1110 0111 1111
-
按位异或 : 同一个不相同为1 , 相同为0 : 0110 0101 ^ 0001 1110 = 0111 1011
0110 0101 0001 1110 0111 1011
-
取反 :返回二进制的补码的反码, 值的规律是改变正负号后再减一 : ~8 = -9, ~1 = -2
-
- 按位左移:所有二进制位向左移动n位, 低位补0,8 << 1, 8 按位移动1 位, 等于原来的 2倍 。 0000 0100 => 0000 1000
-
私有属性 : __num , 类似于Java 的 private, 在内部被转换成了 _className__num 属性了,通过 _className__num 仍然可以访问。
私有方法和私有属性是子类无法继承的, 实例也无法直接读取或者调用, 必须通过非私有的属性和方法去读取和调用.
class Dog() :
def __init__ (self) :
self.__num = 100
# # case1 : 直接调用私有属性, 得不到返回值, 并且报错
# d = Dog()
# print(d.__num)
# # 'Dog' object has no attribute '__num'
# # case 2 : 给私有属性赋值, 其实是给实例的属性赋值, 并不是给私有属性赋值
# d = Dog()
# d.__num = 300
# print(d.__num)
# # 300
# 推荐的方法
class Dog(object) :
def __init__(self):
self.__num = 100
def setNum(self,num):
self.__num = num
def getNum(self):
return self.__num
d = Dog()
print(d.getNum())
d.setNum(200)
print(d.getNum())
- 在 from a import b 的时候, a 中以 "" 开头的变量是无法导入到当前文件当中去的
- 但是直接 import a 的时候, a 模块中的变量都是直接可以导入到当前文件的
- 切换下载源 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
- property 类似 js 的getter 和 setter , 读取property 的时候, 调用 getter 函数, 给property 赋值的时候 调用 setter 函数。
- property : leg = property(getLeg, setLeg) , 使用 leg 来读写 __leg 属性, 读时候调用setLeg,写的时候调用 setLeg
class Dog(object) :
def __init__(self):
self.__leg = 4
self.__eye = 2
def setLeg(self, num):
print('setLeg')
self.__leg = num
def getLeg(self):
print('getLeg')
return self.__leg
leg = property(getLeg, setLeg)
@property
def eye(self):
print('get-eys')
return self.__eye
@eye.setter
def eye(self, num):
print('set-eys')
self.__eye = num
d = Dog()
print(d.leg)
d.leg = 3
print(d.leg)
e = Dog()
print(e.eye)
e.eye = 3
print(e.eye)getLeg
# 4
# setLeg
# getLeg
# 3
# get-eys
# 2
# set-eys
# get-eys
# 3
- 可迭代对象 : str, list, tuple, set, dict, 生成器 : (x for x in range(1,10))
- 闭包: 和 Js 的闭包是一样的
// c 和 d 开辟的是两个内存空间,互不影响
// 在定义c 时调用了a, 然后在定义d 时调用了a
// 因为函数外部对 c 仍有引用, 所以c 不会销毁,原先函数c仍然保存在内存中, c 仍然指向 a的返回值
// python 也是一样的
const a = (n)=> {
const b = (m)=> {
return n + m
}
return b
}
const c = a(100)
console.log(c(100))
console.log(c(100))
console.log(c(100))
// 200
// 200
// 200
const d = a(50)
console.log(d(100))
console.log(d(100))
console.log(d(100))
// 150
// 150
// 150
console.log(c(100))
// 200
- 装饰器/装饰器原理:
def outer(func):
def inner(a,b):
if True:
return func(a,b)
else :
print('123')
return inner
@outer
def sum(a,b):
return a + b
# @outer指定了outer 作为sum的装饰器,
# 把 sum 作为参数传递给一个高阶函数 outer,
# outer 返回一个闭包函数, 该闭包函数会在特定条件下执行 sum函数
# 其实装饰器的相当于做了下面一件事情:
# sum = outer(sum)
print(sum(1,2))
- 多个装饰器装饰同一个函数 :
aLink 执行的时候, 先执行装饰器。 装饰器执行的顺序是从上向下执行的。以下面为例,会先执行 div, 执行 div 的时候, div 是 h1 的装饰器, 所以会去将 h1 作为参数传递给 div, 此时的结果为一个函数, fn =>
<div>
+ h1() +</div>
。 然后执行 h1 函数, h1 函数执行的时候, 因为他是 aLink的装饰器, 此时的结果为 fn =><div>
+<h1>
+ aLink() +<h1/>
+</div>
, 继续执行 aLink 得到最终结果 :<div><h1>hello-world</a><h1/></div>
装饰器执行的时机: 在解释器执行到 @div @h1 的时候, div 和 h1 已经被执行, 已经生成了装饰完成后的函数, 不是再调用的时候才开始装饰。 多个装饰器的执行流程,以下面代码为例:
- 解释器从上到下执行代码, 读到 @div 时, 需要装饰下边的函数, 结果下边是个装饰器
- 然后解析@h1 , 此时 执行 h1 函数, 打印 ‘h1’ , aLink 指向了 h1 内部的 inner 函数
- 这时候 @div 下方是一个函数 , 即被 h1 函数装饰过的 aLink
- 执行 div 函数, 打印 ‘div’ , aLink 指向了div 函数内部的 inner 函数
- 解析到 res = aLink() 是, aLink 已经被 h1 和 div 装饰完成
- 开始执行 aLink , 此时aLink 仍然指向 div 内部的 inner 函数
- 打印 ‘1’,div 内部的 inner 函数内部 的 fn 指向 h1 的 inner 函数
- 执行h1 内部的inner 函数, 打印 ‘2’, 此时 h1 内部的 fn 函数指向 aLink 函数
- 执行 aLink 函数, 打印 ‘3’ , 返回 hello-world
- 参考图片 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4mII06C9-1626947663200)(./images/1.装饰器原理与执行顺序.png)]
def div(fn):
print('div')
def inner():
print('1')
return '<div>' + fn() + '</div>'
return inner
def h1(fn):
print('h1')
def inner():
print('2')
return '<h1>' + fn() + '<h1/>'
return inner
@div
@h1
def aLink():
print(3)
return '<a>hello-world</a>'
res = aLink()
print(res)
# h1
# div
# 1
# 2
# 3
# <div><h1>hello-world</a><h1/></div>
- 装饰有参数的函数, 装饰器中的 inner 函数的形参的个数和类型要与被装饰的函数保持一致。inner 函数调用被装饰的函数的时候, 也要传递相同数量和类型的参数给inner 内部的被装饰函数。这与 JS 的高阶函数/闭包的用法是一致的。
- 装饰不定长参数的函数, 类似js 的 剩余参数和 arguments:
# 使用 *args, **kwargs, 来传递
def outer(f):
def inner(*agrs, **kwargs):
return f(*agrs, **kwargs)
return inner
@outer
def sum(a,b):
return a+b
# def sum(a,b,c):
# return a+b+c # 6
r = sum(1,3)
print(r) # 4
- 装饰器是装饰者模式的一种实现, 采用的是面向切面(AOP)的编程手法
- 带参数的装饰器:多了一层函数, @outer(‘100’) 会执行 outer 函数, 将并将实参 ’100‘ 传递给 outer 的形参 arg, 并且返回了 mid 函数,mid 函数会继续对 f 函数进行装饰, 直至返回inner 函数。
def outer(arg):
def mid(f):
def inner():
if '100' == arg:
print('get 100')
return f()
return inner
return mid
@outer('100')
def f():
return 'f'
print(f())
- 命名空间:
- globals() 以字典的形式返回当前作用域所有全局变量名
- locals() 以字典的形式返回当前作用域所有的局部变量
- 变量在作用域中的查找规则: legb local -> enclosing -> global -> builtins 局部=》闭包=》全局=》内建
- 给对象动态添加方法 : 类似 js 的bind 功能 就是将run 函数的参数self绑定到实例对象
import types
class Dog() :
def __init__ (self,name):
self.name = name
def run (self):
print(self.name + ' is runnning')
d = Dog('ala')
d.run = types.MethodType(run, d)
d.run()
- : 指定一个类的实例对象可以动态添加的属性的名称的集合,添加不在这个集合内的属性会报错, 示例如下:
class Dog(object):
__slots__ = ("legs","eyes")
d = Dog()
d.eyes = 2
d.legs = 4
print(d.eyes) # 2
print(d.legs) # 4
d.ears = 2
print(d.ears)
# AttributeError: 'Dog' object has no attribute 'ears'
- 生成器
- 不会立即生成列表, 在使用的时候会根据使用情况依次生成列表中的元素,节约内存
- for 循环循环迭代器, 不会越界
- a = yield b , a 的值仍然是 None , 因为 yield 语句没有返回值, 这点和 js 不一样
- send 给生成器传递参数的时候, 如果第一次迭代不传递 None会报错, JS 不会报错, 只是忽略第一次给next 传递的参数
50 . 元类:type 创建类, type 创建type, metaclass 可控制类的定义方式
#-*- coding:utf-8 -*-
# 依次传入的参数是, 类名,父类,类的属性
def upper_attr(future_class_name, future_class_parents, future_class_attr):
#遍历属性字典,把不是__开头的属性名字变为大写
newAttr = {
}
for name,value in future_class_attr.items():
if not name.startswith("__"):
newAttr[name.upper()] = value
#调用type来创建一个类
return type(future_class_name, future_class_parents, newAttr)
# python 3 的写法
class Foo(object, metaclass = upper_attr):
# python2 的写法
# __metaclass__ = upper_attr #设置Foo类的元类为upper_attr
bar = 'bip'
print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))
- 直接写在类的内部的代码, 在解释器解析代码的时候将会被执行
垃圾回收 Garbage Collection (GC) :引用计数为主,隔代回收为辅
-
小整数对象池 : [-5, 256] 之间的相同的数字使用同一个内存空间, 内存 id 相同
-
大整数对象池 :
-
相同的字符串在不包含特殊字符和空格时,使用同一个内存空间
-
引用计数:
- 优点 : 实时性, 简单 - 缺点: 循环引用无法清除,如果恰巧有循环操作, 可能会占用极大内存而被操作系统杀死
-
消除引用计数中的循环引用变量: n1, n2 互相引用, n1 = None, n2= None, n1, n2都指向了新的引用, 则旧引用计数为0, 会被清楚。
-
隔代回收
-
Ruby 标记清除的方式垃圾回收
内建属性
- : 访问属性拦截器, 类似于js 的属性访问器的 get 函数. 在该属性内部, 禁止再调用 self的属性和方法, 否则会一直循环调用下去
class Dog(object):
def __init__(self,name):
self.name = name
self.legs = 4
def __getattribute__(self, propName):
# 要劫持的属性
if 'name' == propName:
return 'wangcai'
# 不需要劫持的属性, 还是按照原来的方式读取
else:
return object.__getattribute__(self, propName)
d = Dog("哮天犬")
print(d.name)
print(d.legs)
集合的运算
a = {
1,2,3,4,5,6,7,8}
b = {
5,6,7,8,9,10,11,12}
# 交集
print(a&b)
# 并集
print(a|b)
# 差集
print(a-b)
# 对称差集 : 只能出现在a或者只能出现在b的元素, a|b - a&b , 并集减去交集
print(a^b)
多任务:任务数量多于CPU核数的时候,是通过时间片轮转的方式实现多任务同时进行的
- 并发 : 任务数量多于CPU核数, 至少有一个CPU处理一个以上的任务
- 并行 : 任务数量不多多于CPU核数, 每个 CPU 处理一个任务
程序 进程
- 程序 : 开发完的代码没有运行, 是一个程序
- 进程 : 运行中的程序, 会占用系统资源,需要运行环境
主进程 子进程
# 此代码要在 linux 上运行, windows 上没有os.fork
import os
import time
# from multiprocessing import Process
# 创建一个新的进程
# 对主进程而言, ret > 0
# 对子进程而言, ret == 0
# 从这行代码开始, 子进程与父进程同时开启
ret = os.fork()
if ret == 0:
while True:
print('1')
time.sleep(1)
else :
while True:
print('2')
time.sleep(1)
主进程和子进程的执行顺序是不确定的, 进程里边的变量是互不影响的, 不会因为其他进程改变了全局变量而导致该进程中的变量发生变化。相当于每个进程中的全局变量、局部变量都是独立的, 互不干扰。
进程之间的通信 :
- 多个进程在一台电脑上 : 文件
- 多个进程不在同一台电脑上 :网络
Process 创建子进程, 主进程会等待所有子进程结束才会结束。 而 fork 不会。
线程之间的全局变量是共享的, 进程之间的全局变量不是共享的。
线程和线程之间的局部变量是不共享的。不同的线程执行相同的函数,该函数内部的局部变量对每个线程而言都是独立的, 不会在线程之间共享。
import threading
import time
def test1():
num = 100
name = threading.current_thread().name
print(name)
if 'Thread-1' == name:
num += 100
else:
time.sleep(2)
print(num)
t1 = threading.Thread(target=test1)
t1.start()
t2 = threading.Thread(target=test1)
t2.start()
# Thread-1
# 200
# Thread-2
# 100
所以,只有在不同的进程修改全局变量的时候加上互斥锁就可以了。
生产者、消费者模式: 解决处理生产、消费速度不一样的问题
异步:
子进程开始一个异步任务并且传递了回调函数, 主进程会继续执行主进程的代码。当子进程任务完成后, 会将子进程任务的结果以参数的形式传递给回调函数, 此时主线程立即开始执行回调函数, 当回调函数执行完成后,再继续执行主线程中的代码。
网络编程
udp : 不稳定
- udp 用户数据报协议, tftp 基于 udp 实现。
- udp 发送消息可以绑定ip和端口, 一般不用绑定。
tcp 传输控制协议 : 稳定,web 服务器都使用tcp
== packet tracer 5.0
网络号 : 网络掩码(子网掩码)和ip按位与操作得到的 , 网络掩码 255.255.255.0, ip 198.168.1.32 ,装换成 二进制后分别为 :
按位与操作 0&0=0; 0&1=0; 1&0=0; 1&1=1
11111111 11111111 11111111 00000000
11000110 10101000 00000001 00100000
& -------- -------- -------- --------
11000110 10101000 00000001 00000000
198 168 1 0
经过以上计算, 网络掩码 255.255.255.0, ip 198.168.1.32 的网络号是 198.168.1.0
物理地址 = 硬件地址 = MAC 地址 , 格式 02-01-30-56-30-5C , 一个有6个字节, 用 十六进制表示, 前三个字节表示厂商编号,后三个字节表示网卡编号。所以理论上讲,世界上每一块网卡的编号都是唯一的, 即 MAC 地址唯一。
** 网络信息 **
IPv6 地址: 2409:8900:3d00:480:d48e:44fc:7cae:dfdb
本地链接 IPv6 地址: fe80::d48e:44fc:7cae:dfdb%53
IPv6 DNS 服务器: 2409:8900:3d00:480::85
IPv4 地址: 192.168.42.61
IPv4 DNS 服务器: 192.168.42.129
制造商: Microsoft
描述: Remote NDIS based Internet Sharing Device
驱动程序版本: 10.0.18362.1
物理地址(MAC): 02-01-30-56-30-5C