python 进阶学习笔记

函数

常用内置函数

计算函数

abs(-1)             # 绝对值
pow(2,5)            # 幂: 等效于 2**5
sum([2,3,4])        # 累加和
divmod(92, 10)      # 模: 返回为9, 2
round(3.1415926,3)  # 精确值: 返回为3.142 (自动四舍五入)

检测函数

max([1,4,5])        # 最大值
min([1,3,4])        # 最小值
all([1,2,39,0])     # 检查是否全为True,返回bool: 这里返回False
any([1,2,4,0])      # 检查是否存在True,返回bool: 这里返回True

进制转换函数

v1 = bin(55)                        # 十进制       ->      二进制
v2 = int('0b0100110', base = 2)     # 二进制(0b)   ->      十进制

v1 = oct(55)                        # 十进制       ->      八进制
v2 = int('0o173', base = 8)         # 八进制(0o)   ->      十进制

v1 = hex(55)                        # 十进制       ->      十六进制
v2 = int('0o9a3', base = 16)        # 十六进制(0x) ->      十进制

字符进制

v1 = ord('我')       # 获得字符 unicode 的十进制表示:字符->数字
v1 = chr(65)         # 由 unicode 十进制获取字符:数字->字符

排序

a = [1,3,2]
a.sort()             # 将列表排序  
b = sorted(a)        # 排序但不影响原列表,生成新列表返回


def func1(x):
    return int(x[:2])
b = sorted(a, key = func1)  # 自定义排序规则,以func1返回值排序

随机函数random

random.randint(1,10)        # 随机整数
random.uniform(0,5.5)       # 随机小数
random.choice([1,2,3,5])    # 列表中随机值
random.sample([1,2,3,4],2)  # 列表中随机取两个数,返回为列表形式

number_list = [1,2,66,8]
random.shuffle(number_list) # 将原列表打散

函数传参:默认值为可变类型格式

def  func(a = []):
    pass

函数创建的时候则生成了空列表,后续调用如果不传参的时候,都会使用这个空列表,类似于C语言中的static参数。所以默认为可变类型时建议:

def  func(a = None):
   if not a:
     a = []
   pass

传参中 * 的用法

  • 乘法运算

  • 收集列表中多余的值

a,b,*c = [1,2,3,4,5]
# a = 1, b = 2, c = [3, 4, 5]
  • 函数:以元组形式接受参数 ( *args )
def f(a,*args):
    print(args)
f(1, 2, 3, 4, 5, ['a', 'b'])
# a = 1, args = (2, 3, 4, 5, ['a', 'b'])
# 即将其后所有参数放入一个元组中
  • 函数:以关键字形式接受参数 ( **args )
def f(**args):
    print(args)
f(a = 1, b = 2)
# args为字典,{'a' = 1, 'b' = 2}

生成器函数:yield

def func():         # 生成器函数
    print(1)
    yield 1
    print('next')
    yield 'xx'

a = func()          # 生成器对象
a.__next__          # 调用生成器对象,并运行至下一个yield,并返回值
                    # 如果函数代码全部结束会返回None

for item in a:
  print item        # 可以使用循环遍历生成器对象

适用于大数据量情况下的操作,减少内存占用。range默认使用生成器函数创建

global关键字

global name
name = 'XXX'
# global 关键字可以在函数直接使用全局变量,并直接修改变量值

闭包(装饰器)

def func(n1):
    v1 = 111
    def inner():
      print(n1 + v1)
    return inner        # 返回函数名

a = func(2)             
b = func(33)
c = func(66)            # 先将数据封装在了包(作用域)中
                        
                        # 执行时再获取封装时的值
a()                     # 113
b()                     # 144
c()                     # 177

多用于线程池

用法: 装饰器

def func1(a1):
    def inner():
        print('test')
        a1()
    return inner
  
@fun1
def func2():
    print('inner')
    
# 相当于执行 func2 = func1(func2)

闭包应用: 装饰器不改动原函数的情况下,添加功能

多个返回值本质:元组

def  func():
    return 1,2

a, b = fuc()
# a = 1, b = 2
# 实际返回为(1,2),随后python会对其自动解包,按顺序赋值

邮件

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr

# 邮件内容
msg = MIMEText('hello', 'html', 'utf-8')    # 邮件内容
msg['Subject'] = 'my主题'                    # 主题
msg['From'] = formataddr(['ght', 'XXXX@136.com'])   # 名字和邮箱
msg['to'] = 'xxx@qq.com'        # 目标邮箱

# 发送邮件

server = smtplib.SMTP_SSL('smtp.163.com')   # SMTP服务器
server.login('XXXX@136.com', 'XXDDWWGSX')   # 账户、授权码
server.sendmail('XXXX@136.com', 'xxx@qq.com', 
                msg.as_string())            # 自己邮箱、目标邮箱、内容
server.quit()

类变量

class TestClass:
  # 变量:
  city = 'xian'                         # 类变量 
  def __init__(self, name):
    self.name = name                    # 实例变量
    
    
v1 = TestClass('shanghai')              
print(v1.name)                          # 上海
print(v1.city)                          # 西安
print(TestClass.city)                   # 西安

类方法

class TestClass:
  def print_str(self):                  # 绑定方法:需要self参数
    pass
  
  @staticmethod                         # 静态方法:不需要self参数
  def static_method():
    pass
    
  @classmethode                         # 类方法:需要cls参数
  def class_method(cls, a1):            
    pass                     

# 绑定方法需要实例化再调用,静态方法可以直接通过类调用,也可以实例化调用
v1.print_str()
v1.static_method()                      # 实例化两个都可以调用
TestClass.static_method()               # 静态方法直接通过类调用
TestClass.class_method()                # 类方法于静态方法类似

类属性

class TestClass:
  @property                             # 将方法伪造为变量,
  def d1(self):                         # 可以用v1.d1直接调用
    return self.name + 'add_info'       # 不能有self外其他参数
  
  @d1.setter                            # 将对象伪造为变量,可用=号
  def d1(self, val):                    # 调用v1.d1 = 'wuhan',相当于'wuhan'传入val
    self.name = val
    
  @d1.deleter                           # 调用del v1.d1时运行此方法
  def d1(self):
    pass
  
  
print(v1.d1)
v1.d1 = 'wuhan'
del v1.d1
class TestClass:
  x = property(get_x, set_x, del_x)     # 快速创建x属性
  
  def get_x(self):
    return 123
  
  def set_x(self, val):
    pass

  def get_x(self):
    pass
  
  
  obj = TestClass()
  print(obj.x)
  obj.x = 88
  del obj.x

特殊成员

__init__

def __init__(self, a1):                         # 初始化方法
  pass
### `__new__`
def __new__(self, *args, **kwargs):             # 构造方法(默认执行)
  # 创建空对象
  obj = object.__new__(self)
  return obj

__init__实际做了两件事:

  • 创建空对象 obj = 对象。(__new__创建对象)

  • 执行__init__方法。(__init__初始化)

__call__

def __call__(self, *args, **kwargs):            # 实例化对象直接调用
  pass

obj = EgClass(),则obj()意义为调用__call__

__dict__

print(obj.__dict__)                             # 得到字典形式的对象所有变量

class Foo:
  city = 'shanghai'
  
  def __init__(self, name):
    self.name = name
    self.age = 20

obj = Foo('xiaowang')

print(obj.__dict__)
# {'name':'xiaowang', 'age':  20}

print(Foo.__dict__)
# {拿到类中所有方法和变量的值}

__str__

class Foo:
    def __init__(self):
      pass
    
    def __str__(self):
      return 'qte'

obj = Foo()
print(obj)
# 输出 qte

__getitem__, __setitem__, __delitem__

class Foo:
  def __init__(self, name):
    self.name = name
    self.age = 20
    
  def __getitem__(self, item):
    return 999
  
  def __setitem__(self, key, val):
    pass
  
  def __delitem__(self, key):
    pass
  • obj[22]:将22item参数,传入__getitem__

  • obj[0] = 'test':将0key参数,'test'val参数,传入__setitem__

  • del obj[99]:将99key参数,传入__delitem__

__enter__, __exit__

class Foo:
  def __init__(self, name):
    self.name = name
    self.age = 20
  
  def __enter__(self):
    print('start')
    return "return_info"
  
  def __exit__(self):
    print('end')

obj = Foo('xiaowang')
with obj as o:
  print(123)
# start
# 123
# end
  • __enter__, __exit__需成对使用,with开始时调用__enter__, 结束时调用__exit__

  • __enter__中返回的值为with obj as o中的o

__add__

class Foo:
  def __init__(self, name):
    self.name = name
    self.age = 20
  
  def __add__(self, other):
    return self.age + other.age
    
f1 = Foo('root')
f2 = Foo('admin')
data = f1 + f2                  # 即:f1.__add__(f2) 

类似的加减乘除、大于小于不等于都可以使用类似方法

模块

文件操作

f = open('path', 'w')
content = f.read()      # 获取文件所有内容
content = f.read(N)     # 按N个字节逐次读取入内存
for i in f:             # 按行读取,内存占用小
f.flush()               # 将文件的内容直接存储的硬盘
__file__                            # 运行脚本的文件路径
os.path.abspath('path.txt')         # 获取绝对路径
os.path.join('a', 'b', 'c.txt')     # 连接字符为路径:a/b/c.txt
os.path.dirname('path.txt')         # 获取文件所在目录
os.path.exists('path.txt')          # 判断路径是否存在,返回True/False
os.path.isdir('./path')             # 判断是否为文件夹
os.remove('path.txt')               # 删除文件(没办法删除文件夹)
os.listdir('dir')                   # 获取文件夹一级目录中的所有的文件名

os.walk('dir')                      
''' 
获取文件夹中所有文件(包括嵌套)返回元组:
('a', [b], [c])
第一个 'a' 为当前迭代的目录,
第二个 [b] 为文件夹内的目录list,
第三个 [c] 为文件夹内的文件list。

使用for循环时,每次迭代[b]中的目录,直到遍历所有目录,
返回格式同上,即('a', [b], [c])格式

例:
for in_path, folder_list, name_list in os.walk('path')
'''

shutil.rmtree('path')               # 删除文件夹以及其内容
shutil.move('a.txt', 'b.txt')       # 将文件改名(文件夹也可以)
shutil.copytree('aa', 'bb')         # 将文件夹拷贝到目标位置
shutil.copy('aa/bb.txt', 'cc')      # 将文件拷贝到目标位置
shutil.make_archive(base_name = 'a', format = 'zip' , root_dir = 'y')
                                    # 压缩文件
shutil.unpack_archive('a.zip', extract_dir = 'xxx', format = 'zip')
                                    # 解除压缩

configparser

import configparser
config = configparser.Configparser()        # 初始化
config.read('path.txt', encoding = 'utf-8') # 读取文件
x = config.sections()                       # 获取节点值['server', 'client']
y = config.items('server')                  # 获取'server'节点键值对
z = config.get('server', 'v1')              # 获取'server'节点,'v1'的值
config.has_section('server')                # 是否存在某个节点

config.add_section('test')                  # 添加节点
config.set('test','name','12')              # 为某个节点添加键值,或修改键值

config.remove_section('server')             # 删除节点
config.remove_option('server', 'v1')        # 删除键值
with open('path.txt','w', encoding = 'utf-8') as f:
    config.write(f)                         # 写入文件
               

json

json.loads()                # 解码json数据,返回字典
json.dumps()                # 将字典编码为json格式
json.dumps(XX, indent = 2)  # 为字符串添加缩进

xml

<data>
  <country name = 'China'>
    <rank updata = 'yes'>69</rank>      
    # tag:rank  attrib:updata = 'yes'   text:99
  </country>
</data>
from xml.etree import ElementTree

root = ElementTree.XML(CONTENT)     # 获取内容
node1 = root.find('country')        # 找到特定节点内容
node2 = root.findall('country')
for i in node2:
  print(i.tag, i.attrib, i.text)

re:正则表达式

\d{11}                              数字  {11位}
\w{5,10}                            字符  {5-10位}
XX[a,b,d]                           固定文本+可变范围[a,b,d]: XXa, XXb, XXd
XX[a-z]   or  XX[0-9]               固定文本+可变范围[a-z]或[0-9]
.                                   除了换行符以外的任意字符
[a-zA-Z0-9_-]                       可组合多个范围的字符

数量相关(\d为例):
\d?                                 ? 表示为0或1
\d+                                 + 表示为1或n
\d*                                 * 表示为0或n
{9}                                   表示为9个
{9,}                                  表示为9及以上
{1,9}                                 表示为1到9个

^                                     起始符
$                                     终止符
默认贪婪匹配
import re
res = re.findall(r'\d{11}', example)         # 获取所有和正则表达式匹配的字符串
res = re.findall(r'@(\d{11})', example)      # 获取匹配的字符串,返回括号内的内容
res = re.match(r'^\d{11}\w+$', example)      # 返回第一个匹配,没有返回None
res = re.search(r'^\d{11}\w+$', example)     # 纵观全部字符串,但返回第一个匹配
res = re.split('[,\.]', example)             # 通过','和'.'将字符串切割,返回列表

openpyxl:excel

from openpyxl import load_workbook

wb = load_workbook('test.xlsx')                 # 以路径方式打开excel文件

f = open('test.xlsx')
wb = load_workbook(f)                           # 以对象方式打开excel文件

all_sheet = wb.worksheets                       # excel中的每个sheet(对象)
single_cell = all_sheet[0].cell(2,3)            # 某个sheet中特定坐标的内特

all_sheet_name = wb.sheetname                   # 所有sheet名字(list形式)
wb['sheet_name']                                # 通过索引方式抓取特定sheet

row1 = sheet[1]                                 # 获取某一行
all_rows = sheet.rows                           # 获取所有行
for i in sheet.iter_rows(min_row=1, max_row=4)  # 循环读取一个区间的行

wb.save('test2.xlsx')                           # 存储文件

并发编程

进程和线程

GIL锁保证每个进程只占用一个CPU,使用多核需要使用多进程。

线程,IO密集型使用多线程(并发)

IO操作、输入输出等,一般可以直接通过驱动完成的任务。如:网络请求

import threading
def task(a):
  pass

for i in range(10):                 # 创建十个线程
  t = threading.Thread(target = task, arg = ('path',))
  t.start()

进程,CPU密集型使用多进程(并行)

一个程序可以有多个进程,其中每个进程会有GIL锁,保证每个进程只占用一个CPU。多线程可以充分利用CPU,但是开销更大。

import multiprocessing
def task(a):
  pass

for i in range(10):                 # 创建十个进程
  t = multiprocessing.Process(target = task, arg = ('path',))
  t.start()
  

进程池和线程池

防止无限制开进程和线程

线程池

from concurrent.futures import ThreadPoolExecutor
def task(a):
  pass

pool = ThreadPoolExecutor(5)            # 创建五个线程的线程池
for i in range(9):
  pool.submit(task, 'test')             # 提交任务

进程池

from concurrent.futures import ProcessPoolExecutor
def task(a):
  pass

pool = ProcessPoolExecutor(5)            # 创建五个线程的线程池
for i in range(9):
  pool.submit(task, 'test')             # 提交任务

数据共享

  • 一个进程中的线程共享数据

  • 进程之间共享数据

from multiprocessing import Manager
import multiprocessing
def task(a):
  pass

if __name__ == '__main__':
  manager = Manager()               # 创建共享对象
  with manager:
    data = manager.list()           # 共享的数据
    p = multiprocessing.Process(target = task, args = (data,))
    t.start()
    t.join()                        # 等到子进程中的代码执行完毕在执行下面的代码
    

协程

协程本身不存在,由程序员人为创建。本质是让一个线程不停止,切换做多个任务(微线程)

应用场景:IO等待

  • 如果开发过程中有IO等待,则适合使用协程。

线程与协程对比

  • 并发能力差不多,但是协程资源消耗更
from greenlet import greenlet
def func1():
  print(1)                  # 第2步:输出1
  gr2.switch()              # 第3步:跳转到func2函数
  print(2)                  # 第6步:输出2
  gr2.swithc()              # 第7步:跳转到func2函数

def func2():
  print(3)                  # 第4步:输出3
  gr1.switch()              # 第5步:跳转到func1函数
  print(4)                  # 第8步:输出4

gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch()                # 第1步:执行协程
import asyncio

async def func1():
  print(1)
  await asyncio.sleep(2)    # IO自动切换到其他任务
  print(2)
  
async def func2():
  print(3)
  await asyncio.sleep(2)
  print(4)
  
tasks = [                   # 添加任务
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_untill_complete(asyncio.wait(tasks))

垃圾回收机制

第 111 天:Python 垃圾回收机制

  • 引用计数:
    为每个对象维护一个 ref 的字段用来记录对象被引用的次数,每当对象被创建或者被引用时将该对象的引用次数加一,当对象的引用被销毁时该对象的引用次数减一,当对象的引用次数减到零时说明程序中已经没有任何对象持有该对象的引用,则释放内存。
    问题:当二者之间交叉引用,则每个对象的引用计数都不为零,会让占用空间无法释放

  • 标记清除:
    是一种基于对象可达性分析的回收算法,该算法分为两个步骤,分别是标记和清除。标记阶段,将所有活动对象进行标记。清除阶段将所有未进行标记的对象进行回收即可。
    则问题变为了 GC 是如何判定哪些是活动对象。GC 会从根结点出发,与根结点直接相连或者间接相连的对象我们将其标记为活动对象(该对象可达),之后进行回收阶段,将未标记的对象(不可达对象)进行清除。前面所说的根结点可以是全局变量,也可以是调用栈。
    问题:必须扫描整个堆内存,即使只有少量的非可达对象需要回收。性能浪费严重

  • 分代回收:
    在引用计数和标记清楚的基础上,将系统中存活时间不同的对象划分到不同的内存区域,共三代,分别是 0 代,1 代 和 2 代。新生成的对象是 0 代,经过一次垃圾回收之后,还存活的对象将会升级到 1 代,以此类推,2 代中的对象是存活最久的对象。
    随着程序的运行,有大量的对象创建和销毁,但是由于交叉引用的存在,创建的对象的数量大于等于销毁的数量,当这两个的数量差大于某个阈值的时候,触发垃圾回收机制。使用标记清除算法将死亡对象进行清除,同时将存活对象移动到 1 代,以此类推。因为程序的一般规律,大部分的对象生存周期都是相当短的,只有少量对象生命周期比较长,甚至会常驻内存。分代回收算法,做到了针对不同的区域采取不同的回收频率,节约了大量的计算从而提高 Python 的性能。

pymysql

连接数据库

import pymysql

conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root123', charset='utf8')           # 连接数据库
cursor = conn.cursor()                      # 创建游标

#1.查看数据库
cursor.execute("show databases;")
result = cursor.fetchall()
print(result)                               # 元组形式返回

# 2.创建数据库
cursor.execute("create database jxday15;")
conn.commit()                               # 创建数据库必须要commit

# 3.删除数据库
cursor.execute("drop database ixday15;")
conn.commit()                               # 删除数据库也要commit

# 4.进入数据库
cursor.execute('use mysql')
cursor.execute('show tables')
result = cursor.fetchall()
print(result)

cursor.close()
conn.close()

表操作

# 创建表
cursor.execute('use ixday14');
sql = """
create table tb:(
id int,
name varchar(16),
age int
)default charset=utf8
"""
cursor.execute(sql)
conn.commit()                               # 创建表后需要commit

# 删除表
cursor.execute('use jxday14')
cursor.execute('drop table tb3')
conn.commit()

删除表

drop table NAME;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,277评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,689评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,624评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,356评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,402评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,292评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,135评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,992评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,429评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,636评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,785评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,492评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,092评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,723评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,858评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,891评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,713评论 2 354

推荐阅读更多精彩内容