python基础进阶
一、基础
1. import xxx和from xxx import yyy
import Module #引入模块
from Module import Other #引入模块中的类、函数或者变量
from Module import * #引入模块中的所有'公开'成员
# 导入整个datetime包
import datetime
print(datetime.datetime.now())
# 导入datetime包里的datetime类
from datetime import datetime
print(datetime.now())
# import之后前者是datetime这个包可见,后者是datetime.datetime这个类可见
import或from-import只能导入一个模块(.py)或者导入一个函数或者类,不能导入一个文件夹。
import:解释器执行到import语句, 如果在搜索路径中找到了指定的模块, 就会加载它。该过程遵循LEGB作用域原则, 如果在一个模块的顶层导入, 那么它的作用域就是全局的;如果在函数中导入,那么它的作用域是局部的。 如果模块是被第一次导入, 它将被加载并执行。
from-import:导入指定的模块属性, 也就是把指定名称导入到当前作用域。容易破坏命名空间,如果使用from导入变量,变量碰巧和作用域中现有变量重名,变量就会被悄悄的覆盖掉。
在实践中, "from module import *" 不是良好的编程风格,如果使用from导入变量,且那些变量碰巧和作用域中现有变量同名,那么变量名就会被悄悄覆盖掉。使用import语句的时候就不会发生这种问题,因为我们是通过模块名才获取的变量名,像module.attr不会和现有作用域的attr冲突。
我们只在两种场合下建议使用这样的方法, 一个场合是:目标模块中的属性非常多, 反复键入模块名很不方便 , 例如 Tkinter (Python/Tk) 和 NumPy (Numeric Python) 模块 , 可能还有 socket 模块。另一个场合是在交互解释器下, 因为这样可以减少输入次数。
2. 导入子目录模块
- hello.py
- base_unit
-- __init__.py
-- person.py
person.py
#!/usr/bin/env python
import time
class Person:
def __init__(self):
self.no = 1234
self.age = 20
print("Person %d output start" % self.no)
time.sleep(1)
print("Person %d output end" % self.no)
def get_age(self):
return self.age
if __name__ == "__main__":
Person()
hello.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base_unit.person
#from base_unit import person
p=base_unit.person.Person()
print(p.age, p.no)
print(p.get_age())
导入子目录模块必须使用import base_unit.person或from base_unit import person,而不能使用import base_unit(报错,不能导入文件夹)。
当使用import base_unit.person时,调用person对象,也必须使用base_unit.person前缀。
3. 查找python包位置
1)modele.path变量
2)module.__file__变量
3)环境变量PYTHONPATH
4)pip show package
3. 单引号、双引号、三引号区别
Python中的单引号'',双引号"",都可以用来包含字符串,没有任何区别。
三引号""" """,或者''' ''' 用于注释。三引号包含的字符串可由多行组成,一般可表示大段的叙述性字符串。特例,多行注释用三个单引号(""")或三个双引号(""")。
在使用时基本没有差别,但双引号和三引号("""...""")中可以包含单引号,三引号('''...''')可以包含双引号,而不需要转义。单引号也可包含双引号而不需要转义。
4. r'',b'',u'',f''含义
字符串前加r,去除转义字符。s=r'ABC\-001'是‘ABC\-001'
字符串前加f,字符串中支持大括号内的python表达式。
import time
t0 = time.time()
time.sleep(1)
name = 'processing'
print(f'{name} done in {time.time() - t0:.2f} s')
----------
processing done in 1.00 s
字符串前加b,后面的字符串是bytes类型。例如,网络编程中,服务器和浏览器只认bytes类型数据。如send函数的参数和recv函数的返回值都是bytes类型。
# python3中,bytes和str互相转换方式
str.encode('utf-8')
bytes.decode('utf-8')
字符串前加u,后面的字符串以Unicode格式编码,一般用在中文字符串前面,防止因为源码存储格式问题,导致再次使用时出现乱码。
5. 变量后冒号
变量名后面的冒号是类型注解,3.6以后加入的,冒号右边是类型,仅仅是注释,方便帮助复杂案例中的类型推断。类型注释只是一种提示,并非强制的,Python解释器不会去校验value的类型是否真的是type。
var: type = value
# 本质就是var = value # type就是var期望的类型
6. 函数声明后箭头
声明函数后箭头:"->" 是返回值的注释,-> str 意思即是提醒函数使用者返回值会是一个str型。
def f(ham: str, eggs: str = 'eggs') -> str :
print("Annotations:", f.__annotations__)
print("Arguments:", ham, eggs)
return ham + ' and ' + eggs
print(f("test","abc"))
在官方文档指明.__annotations__是函数的参数注释和返回值注释:
所以打印出Annotations: {'ham': <class 'str'>, 'eggs': <class 'str'>, 'return': <class 'str'>}
7. 三目运算符(if else在同一行)
a = 'abc'
b = a if a == 'abc' else 'cba'
二、时间
time
import time
print(time.time())
print(time.time_ns())
datetime
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import datetime
i = datetime.datetime.now()
print ("当前的日期和时间是 %s" % i)
print ("ISO格式的日期和时间是 %s" % i.isoformat())
print ("dd/mm/yyyyThh:mm:ss 格式是 %s/%s/%sT%s:%s:%s" % (i.day, i.month, i.year, i.hour, i.minute, i.second))
当前的日期和时间是 2022-01-06 19:16:53.150451
ISO格式的日期和时间是 2022-01-06T19:16:53.150451
dd/mm/yyyyThh:mm:ss 格式是 6/1/2022T19:16:53
定时任务框架apscheduler
参考:Python定时任务框架apscheduler - csdn
三、二进制处理
四、文件
with open('hello.py', "rb") as file:
while True:
content = file.read(64)
if len(content):
content_h = content.hex()
print(content_h)
print(type(content_h))
print(type(content),len(content))
else:
break
读取大文件
def readlines(f, separator):
'''
读取大文件方法
:param f: 文件句柄
:param separator: 每一行的分隔符
:return:
'''
buf = ''
while True:
while separator in buf:
position = buf.index(separator) # 分隔符的位置
yield buf[:position] # 切片, 从开始位置到分隔符位置
buf = buf[position + len(separator):] # 再切片,将yield的数据切掉,保留剩下的数据
chunk = f.read(4096) # 一次读取4096的数据到buf中
if not chunk: # 如果没有读到数据
yield buf # 返回buf中的数据
break # 结束
buf += chunk # 如果read有数据 ,将read到的数据加入到buf中
with open('text.txt',encoding='utf-8') as f:
for line in readlines(f,'|||'):
# 为什么readlines函数能够使用for循环遍历呢, 因为这个函数里面有yield关键字呀, 有它就是一个生成器函数 ......
print(line)
五、串口
import time
import serial
import datetime
import serial.tools.list_ports
port_list = list(serial.tools.list_ports.comports())
print(port_list)
for i in range(0, len(port_list)):
print(port_list[i])
port = "/dev/ttyS1"
bps = 115200
ser = serial.Serial(port, bps, timeout=0.1)
print(ser)
time_fix = False
msg = ""
with open("/home/robot/logs/rcu_com.log", "a") as fp:
while True:
if ser.in_waiting:
try:
msg = ser.read(ser.in_waiting).decode()
except:
pass
if "\n" in msg:
data_list = msg.strip().split("\n")
for i in range(len(data_list)):
if data_list[i] != "":
fp.write(data_list[i] + "\n")
dt_ms = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')
fp.write(dt_ms + " ")
elif msg.strip() is "\n":
continue
else:
fp.write(msg)
time.sleep(0.1)
六、基于函数的生成器
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
生成器返回yield的右值,当下次调用生成器时,yield左边等号的左值等于yield的返回值。初始yield返回Node,之后可以通过send()发送返回值。
>>> def test(val=0):
while True:
y = yield val
print(y)
>>> t = test() # 启用生成器
>>> next(t)
0
>>> next(t)
None
0
为什么第二次Next调用后,print(y)输出了None,而不是 0 ?因为赋值语句从等号右边开始。
第一次Next调用后,执行等号右边的表达式 yield val,执行完后函数暂停运行,赋值操作根本没有被执行。
当第二次再运行时才执行赋值(等号左半部分),而生成器恢复运行时yield初始值为None,所以 y = None。
>>> def test(val=0):
while True:
y = yield val
val = y
>>> t = test()
>>> next(t)
0
>>> t.send('Hello,world')
'Hello,world'
send方法包含与next同样的效果,但还能为生成器传值。
send方法与next的不同在于: send首先给生成器传值,再执行和Next相同的操作( 从上次暂停的地方开始,执行到下一个yield ),send(None) 等价于 Next。
所以为什么第一次运行生成器send参数只能为None?
Because generator-iterators begin execution at the top of the generator's function body,
there is no yield expression to receive a value when the generator has just been created.
Therefore, calling send() with a non-None argument is prohibited when the generator iterator has just started,
and a TypeError is raised if this occurs (presumably due to a logic error of some kind).
Thus, before you can communicate with a coroutine you must first call next() or send(None) to advance its execution to the first yield expression.
生产者消费之协程示例,参考廖雪峰协程
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):
c.send(None)
n = 0
while n < 2:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
七、hash
import hashlib
import sys
def calculate_sha256(file_path):
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
# 逐块读取文件并更新哈希对象
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
file_path = "test.gif"
sha256_value = calculate_sha256(file_path)
ll=len(sha256_value)
# 输出到屏幕
print(f"文件 {file_path} 的 SHA256 值为: {sha256_value}, len:{ll}")
# 输出到文件
with open("sha256_output.txt", "w") as output_file:
output_file.write(f"文件 {file_path} 的 SHA256 值为: {sha256_value}\n")
浙公网安备 33010602011771号