资讯详情

Python 基础知识笔记,没事翻一翻

基础

  1. 布尔值:

    • None
    • False
    • 所有值为0的数字(0,0.0,0L,0.0 0.0j)
    • 空字符串 “”
    • 空列表
    • 空元祖
    • 空字典
  2. a is b 实际调用是 id(a) == id(b)

浮点数

浮点数,也就是小数,之所以叫浮点数,是因为一个浮点数的小数点位置是可变的,比如1.23x109和12.3x108完全相等

python 文件开头

  1. 第一行告诉mac/linux 文件为可执行文件
  2. 第二行指定编码为utf8
#!/usr/bin/env python3 # -*- coding: utf-8 -*- 

python 没有 i j 这种语法, 只能 j =1 j=j 1

  1. 在为对象设置属性时, 尽量使用set get 设置方法可以拦截非法设置和取值, 不建议直接赋值属性。
  2. 私有方法 : 在类中, def __mehtond(): 是私有的方法, 例如,没有私有方法, 调用私有方法会报错。私有属性相似。
  3. 私有方法可以在类中的共同方法和私有方法中调用
  4. 方法:当实例数为时 0 当引用计数为0时,该方法将自动调用。
class Dog():  def __del__():   print(1)  d1 = Dog() d2 = Dog() # 即使不手动删除以下两个变量, __del__ 代码运行完成后仍将执行 # del d1 # del d2 
  1. 即使不手动删除实例对象, 程序执行完成后, 所有未引用的对象都会自动删除, 该方法仍将执行

  2. import sys sys.getrefCount(variable) 测量变量引用的数量, 比实际数量大1

  3. 父类基类, 子类派生: class Dog(Animal) ,让Dog 类继承Animal 类

  4. 重写:在子类中定义与父类同名的方法, 调用子类实例时, 会调用子类的方法

  5. 调用被重写的父类的方法, 只需在子类重写方法中添加以下代码之一:

    1. Parent.mehtond(self)
    2. super().mehtond()
  6. 不会继承私有方法和私有属性。

  7. 集成多个类 class C(A, B )

  8. 实例属性不能在实例间共享, 实例间共享类属性。

  9. 静态方法用于处理逻辑和功能,这些逻辑和功能与。

  10. 创建对象的过程 :

    1. 默认执行 __new__ 、__init__ 方法 2. __new__ 若在类上定义, 最后一定 return object.__new__(cls) 返回实例 3. 执行完 __new__ 方法, 返回实例对象, 此时将调用 __init__ 初始化对象的方法 4. 如果不定义 __new__ 和 __init__ 方法, 会执行默认方法 
  11. 子类方法A调用父类的私有属性和私有方法,如果A是继承自父类的方法, 可调用父类的方法和属性, 若实现A时子类的方法, 父类的私有方法和私有属性不能调用。

  12. 避免多继承的方法相同, 可以使用多继承的调用顺序 className. 去查看

  13. 导出部分功能, 而不是导出整个文件的全局对象 , 注意 每个项目都是字符串的形式

      __all__ = ['test1', 'test2']  def test1() :   print('test1')   def test2():   print('test2')   def test3() :   print(3)   
             
              def 
              test4
              (
              )
              : 
              print
              (
              4
              ) 
             
  14. 所有标准对象均可以用于布尔测试,同类型的对象之间可以比较大小,每个对象天生具有布尔值 True 或者 False。

  15. 下列对象的布尔值为 False, 除了下列对象的值, 其他任何对象的值都是True

    • None
    • False
    • 0
    • 0.0 浮点型 0
    • 0L 长整形 0
    • 0.0+0.0j 复数 0
    • “” 空字符串
    • [] 列表
    • () 元祖
    • {} 字典
  16. 值的比较

- 3 < 4 < 5 合法, 等同于 3 < 4 and 4 < 5
  1. == 与 is 的区别

    • == 只能判断值相等 - is 判断两个对象指向同一个内存, id 相同 (python中所有的数据类型都是对象)
  2. 深拷贝 浅拷贝,

    	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]
    	```
    
    
  3. 原码、反码、补码

    • 原码 : 转换成二进制时的代码

        	比如 1, 2, 分别转换成 0000 0001 , 0000 0010
      
    • 反码:对原码二进制的每一位取相反的 数

        	比如 1的原码是 0000 0001 ,反码是 1111 1110
      
    • 补码 : 在反码的基础上 + 1, 便是补码

        	比如 1的原码是 0000 0001 ,反码是 1111 1110, 补码是 1111 1111
      
  4. 为什么会有 原码、反码、补码?

    因为计算机的数据是通过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 终于实现了。
    
  5. 位运算 : 按照比特位运算, 即把数字转换成二进制的形式进行运算

    • 按位左移:所有二进制位向左移动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

  6. 私有属性 : __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())
  1. 在 from a import b 的时候, a 中以 "" 开头的变量是无法导入到当前文件当中去的
  2. 但是直接 import a 的时候, a 模块中的变量都是直接可以导入到当前文件的
  3. 切换下载源 pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
  4. property 类似 js 的getter 和 setter , 读取property 的时候, 调用 getter 函数, 给property 赋值的时候 调用 setter 函数。
  5. 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

  1. 可迭代对象 : str, list, tuple, set, dict, 生成器 : (x for x in range(1,10))
  2. 闭包: 和 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

  1. 装饰器/装饰器原理:

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))
  1. 多个装饰器装饰同一个函数 :

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 已经被执行, 已经生成了装饰完成后的函数, 不是再调用的时候才开始装饰。 多个装饰器的执行流程,以下面代码为例:

  1. 解释器从上到下执行代码, 读到 @div 时, 需要装饰下边的函数, 结果下边是个装饰器
  2. 然后解析@h1 , 此时 执行 h1 函数, 打印 ‘h1’ , aLink 指向了 h1 内部的 inner 函数
  3. 这时候 @div 下方是一个函数 , 即被 h1 函数装饰过的 aLink
  4. 执行 div 函数, 打印 ‘div’ , aLink 指向了div 函数内部的 inner 函数
  5. 解析到 res = aLink() 是, aLink 已经被 h1 和 div 装饰完成
  6. 开始执行 aLink , 此时aLink 仍然指向 div 内部的 inner 函数
  7. 打印 ‘1’,div 内部的 inner 函数内部 的 fn 指向 h1 的 inner 函数
  8. 执行h1 内部的inner 函数, 打印 ‘2’, 此时 h1 内部的 fn 函数指向 aLink 函数
  9. 执行 aLink 函数, 打印 ‘3’ , 返回 hello-world
  10. 参考图片 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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>
  1. 装饰有参数的函数, 装饰器中的 inner 函数的形参的个数和类型要与被装饰的函数保持一致。inner 函数调用被装饰的函数的时候, 也要传递相同数量和类型的参数给inner 内部的被装饰函数。这与 JS 的高阶函数/闭包的用法是一致的。
  2. 装饰不定长参数的函数, 类似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

  1. 装饰器是装饰者模式的一种实现, 采用的是面向切面(AOP)的编程手法
  2. 带参数的装饰器:多了一层函数, @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())
  1. 命名空间:
  • globals() 以字典的形式返回当前作用域所有全局变量名
  • locals() 以字典的形式返回当前作用域所有的局部变量
  1. 变量在作用域中的查找规则: legb local -> enclosing -> global -> builtins 局部=》闭包=》全局=》内建
  2. 给对象动态添加方法 : 类似 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()
  1. : 指定一个类的实例对象可以动态添加的属性的名称的集合,添加不在这个集合内的属性会报错, 示例如下:
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'
  1. 生成器
  • 不会立即生成列表, 在使用的时候会根据使用情况依次生成列表中的元素,节约内存
  • 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'))
  1. 直接写在类的内部的代码, 在解释器解析代码的时候将会被执行

垃圾回收 Garbage Collection (GC) :引用计数为主,隔代回收为辅

  1. 小整数对象池 : [-5, 256] 之间的相同的数字使用同一个内存空间, 内存 id 相同

  2. 大整数对象池 :

  3. 相同的字符串在不包含特殊字符和空格时,使用同一个内存空间

  4. 引用计数:

     - 优点 : 实时性, 简单
     - 缺点: 循环引用无法清除,如果恰巧有循环操作, 可能会占用极大内存而被操作系统杀死
    
  5. 消除引用计数中的循环引用变量: n1, n2 互相引用, n1 = None, n2= None, n1, n2都指向了新的引用, 则旧引用计数为0, 会被清楚。

  6. 隔代回收

  7. Ruby 标记清除的方式垃圾回收

内建属性

  1. : 访问属性拦截器, 类似于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)

主进程和子进程的执行顺序是不确定的, 进程里边的变量是互不影响的, 不会因为其他进程改变了全局变量而导致该进程中的变量发生变化。相当于每个进程中的全局变量、局部变量都是独立的, 互不干扰。

进程之间的通信 :

  1. 多个进程在一台电脑上 : 文件
  2. 多个进程不在同一台电脑上 :网络

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 : 不稳定

  1. udp 用户数据报协议, tftp 基于 udp 实现。
  2. 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

ping IP 走的时 icmp 协议,想要 ping 一个 ip , 必须先经过 arp 协议获取电脑的mac 地址, arp 是通过 广播的形式把客户端ping 的ip 地址广播到网络, 当目标ip 接收到广播消息后, 会返回给源ip 一个消息, 此时交换机会记住 两个通信机器的mac 地址 和 ip

arp 协议 : 根据 ip 寻找 mac 地址

rarp 协议 : 根据 mac 地址寻找 ip

icmp : ping ip 的时候, 使用的是 icmp协议

ip在同一个网段的电脑可以直接通信, 不在同一个网段的电脑不能直接通讯

路由器: 解决不同网段之间的通信问题, 把两个交换机连接起来, 一个路由器上有两个网卡,

交换机 : 链接同一个网段的设备, 同一网段可以通过交换机直接通信,不同网段的交换机连接到路由器上, 两个网段就可以通信了。

两个相似的网段, 网段1(198.168.1.0) 与 网段2(198.168.2.0) , 两个网段的交换机中间有 n 个路由器, 网段1 的电脑 198.168.1.1 向 网段2 的电脑 198.168.2.1 发送数据,在整个过程中, 目标电脑的 IP 198.168.2.1 是不会变的,会沿着每个路由器向下发送, 而 目标mac地址是一直变化的, 每一次都指向下个网卡的硬件地址。 即 ip 是固定不变的, 而 mac 地址确是动态改变的。这就是必须有 mac 的原因 : 不能直接找到 ip 的时候, 会根据 mac 地址一直往下查找, 直到 找到目标 ip。

ip 是在逻辑上标记一台电脑, 而 mac 是在物理硬件上标记一台电脑。netmask 和 ip 一起确定网络号。

默认网关 : 如果通信的ip 不在同一个网段内, 则会发送

标签: 连接器axk736145j

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台