1.类继承object:python3.9类不继承object默认也有这些特性
class Test(object):
pass
test = Test()
print(dir(test))
"""
输出:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
都是类的高级特性
"""
2.dir()
class Test():
def test_test(self):
pass
a = Test()
print(dir(a))
print((dir(a.test_test())))
"""
输出:['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'test_test']
['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
可以得到类的属性和方法、方法的属性
"""
3.cls
cls配合@classmethod使用,self指类对象,cls指类本身
cls方法其他类或者函数可以直接类.方法()调用
class Person:
def __init__(self, num):
self.num = num
print(self)
@classmethod
def age(cls):
print(cls)
return 777
class Obj:
def obj(self):
person = Person.age()
print(person)
Person(888)
a = Obj().obj()
"""
输出:
<class '__main__.Person'> --->cls
777
<__main__.Person object at 0x000001EBDE074E80> --->self
"""
4.namedtuple:具名元组
from collections import namedtuple
# City 是一个具名元组
City = namedtuple('City', 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
"""
City是一个类
tokyo是类实例
"""
5.yield简单理解
带有 yield 的函数在 Python 中被称之为 generator(生成器)
def foo():
print("starting...")
while True:
res = yield 4
print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))
"""
输出:
starting...
4 --第一次运行返回4,结束运行返回值被打印
********************
res: None --第二次运行,next(g) == g.send(None),所以res = None
4 --打印完res后,进入while循环,运行到yield结束,返回4
"""
def gen(num): # python 解释器转换代码为字节码时,视作yield函数为生成器
while num > 0:
tem = yield num
if tem is not None:
num = tem
num -= 1
g = gen(5) # 实例化为生成器对象
first = next(g) # 执行一次迭代对象
print(f"first: {first}") # 5
# next(g) == g.send(None)
# tem = 10,并且执行后面代码
print(f"send: {g.send(10)}") # 9
for i in g:
print(i) # 8, 7, ... , 1
# num执行-1后,进入while循环并且运行到yield结束
6.isinstance()
判断对象是否为哪一类型,返回布尔值。考虑继承关系
x = isinstance("Hello", (float, int, str, list, dict, tuple))
print(x)
y = isinstance("hello", tuple)
print(y)
"""
输出:
True
Flase
"""
7.not>and>or优先级
print(not 0 or 1 and 0)
print(1 and 0)
print(1 or 0)
8.解决循环引用报错most likely due to a circular import
使用延迟引用
9.初始化类且不 __init__初始化
class MyClass(object):
init = False
def __init__(self):
print 'init called!'
self.init = True
def hello(self):
print 'hello world!'
class Empty(object):
pass
>>> a = MyClass()
init called!
>>> a.hello()
hello world!
>>> print a.init
True
>>> b = Empty()
>>> b.__class__ = MyClass #
>>> b.hello()
hello world!
>>> print b.init
False
10.split和rsplit
s = 'a.b.c'
res = s.split('.', 1)
res
// ['a', 'b.c']
s = 'a.b.c'
res = s.rsplit('.', 1)
res
// ['a.b', 'c']
// 类似split,区别为从结尾位置开始计数
11.enumerate(sequence, [start=0])
函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 小标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
12.反射机制 对于任意类、对象知道和调用它的所有属性和方法
- hasattr():函数用于判断对象是否包含对应的属性
- getattr(a, b, c):函数返回a对象b属性的值,默认返回c
判断模块是否包含对应类
module = importlib.import_module("tasks." + login_dict["function"]) # 导入模块
if not hasattr(module, "RunTask"):
logger.error(f"【%s】未找到RunTask类,跳过当前注册,请检查" % login_dict["function"])
continue
13.importlib模块实现动态导包
import importlib
m1 = importlib.import_module('example.submodule')
print(m1)
m2 = importlib.import_module('.submodule', package='example')
print(m2)
print(m1 is m2)
# import_module() 的返回值是导入创建的模块对象
14.__getattr__
python里的一个内建函数,当调用的属性或者方法不存在时,该方法会被调用
15.__repr__
方法定义了实例化对象的输出信息
16.正则
re.match() 返回第一个匹配结果,从头匹配
re.search() 返回第一个匹配结果,从任意位置匹配
re.findall() 返回列表形式所有匹配结果
match = re.search("我是(.*?)人", "我是中国人", 标识符)
match.group(0) # 正则表达式中符合条件字符串
match.group(1) # 正则表达式中第一个()中字符串
输出:我是中国人
输出:中国
17.decode、encode
unicode类型.decode("utf8")
"""机器可读字节 -> utf8类型"""
utf8编码类型.encode("utf8")
"""utf8类型 -> 机器可读字节"""
18.exec
exec 执行储存在字符串或文件中的 Python 语句,比如动态导包
exec("import " + each_third_package_value.CheckName) # 参数化导入包
19.命令行参数
1. 添加参数
# 启动脚本时,添加参数
if len(sys.argv) < 2:
with open("input_arg.json", mode="r") as fp:
content = fp.read()
sys.argv.append(f"--input-argument={content}")
>>> sys.argv
# 输出
['C:/file/demo.py', '--input-argument={\n "input_xml_path": "C:/file/in.xml",\n "out_xml_path": "C:/file/out.xml",\n "is_developer_mode": true,\n "user-agent": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko"\n}']
2.接受参数
1. 实例化对象 2. 添加获取的命令行参数 --input-argument 3. parser.parse_args() 使生效 4. args.input_argument 获取对应参数
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input-argument", help="输入参数")
args = parser.parse_args()
input_argument_str = args.input_argument
input_argument_dict = json.loads(input_argument_str)
>>> input_argument_str
# 输出
'{\n "input_xml_path": "C:/file/in.xml",\n "out_xml_path": "C:/file/out.xml",\n "is_developer_mode": true,\n "user-agent": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko"\n}'
20.xml、dict转换
xmltodict.parse xml -> dict
xmltodict.unparse dict -> xml
21.subprocess 待补充
22.dict补充
3.7版本字典有序,在插入键值对时保存键的顺序
实现有序字典的方式是通过哈希表和维护一个额外的数据结构(链表或跳表)来记录插入顺序。这样就可以在字典内部维护元素的有序性。其查找和访问操作仍然具有常数时间复杂度 O(1)
def test():
return 777
dict_test = {
"name": test()
}
>> dict_test
# 输出
{"name": 777}
# 获取字典第一个key值
next(iter(字典))
23.花活,大受震撼
function = getattr(self, f"_start_{browser_type}_browser")
function()
24.两种实现单例模式方法,待补充
class BrowserBase(metaclass=Singleton): # 用元类实现单例模式
"""
浏览器基类,存放浏览器对象
"""
def __init__(self):
self.driver: WebDriver = None # 浏览器对象 # noqa
self.browser = None # 浏览器名称
self.is_auto_popup = True # 是否开启弹窗管理,默认是
self.is_auto_switch_frame = True # 是否自动切换frame,默认是
self._implicitly_wait = None
class BehaviourBase(ElementBase, PageBase):
"""
行为基类,组合元素基类中的方法
"""
def __init__(self):
# ElementBase, PageBase 的 __init__都是BrowserBase的
BrowserBase.__init__(self)
self.get_new_browser()
self.timeout = 10
browser_base = BehaviourBase() # type: BehaviourBase
25.split,执行后返回list
str.split(' ', 1 ) 返回已空格为分隔符的list
str = "Line1-abcdef \nLine2-abc \nLine4-abcd";
print str.split( ); # 以空格为分隔符,有几个空隔几次
print str.split(' ', 1 ); # 以空格为分隔符,只在第一个空隔断
>>> ['Line1-abcdef', 'Line2-abc', 'Line4-abcd']
>>> ['Line1-abcdef', '\nLine2-abc \nLine4-abcd'] # 只分割成两个
26.装饰器
闭包:能够读取其他函数内部变量的函数
一般用法
project_path = os.path.dirname(os.path.dirname(__file__)) # 路径
ocr_path = project_path + os.sep + "ocr"
def switch_path(func):
"""切换到ocr,执行完函数后返回"""
@wraps(func) # 使func.__name__ 返回函数名
def wrapper(*agrs, **kwargs):
if not os.path.exists(ocr_path):
os.makedirs(ocr_path)
workpath = os.getcwd() # 获取当前工作目录,后续切回
os.chdir(ocr_path) # 切换工作目录至ocr
res = func(*agrs, **kwargs)
os.chdir(workpath)
return res
return wrapper
高级用法
对装饰器优化,实现record执行其他函数
# 在增加一层函数
from functools import wraps
import time
from random import randint
def record(output):
def use_time(func):
@wraps(func)
def wrapper(*args,**kwargs):
st_time = time.time()
result = func(*args,**kwargs)
end_time = time.time()
# print(f'{func.__name__}函数use_time:{end_time-st_time}s')
output(func.__name__, end_time-st_time)
return result
return wrapper
return use_time
def write_log(name,content):
with open('./time.log','a')as f:
f.write(f'{name}耗时:{content}\r\n') # \r\n 换行
# 只需要将装饰器改为@record(write_log)
@record(write_log)
def foo():
time.sleep(randint(2,5))
示例:
def set_temporary_attr_value(attr, value, *, obj=None):
"""
临时改变某个类属性的值,函数运行完毕之后恢复
Args:
attr: 类属性名
value: 属性值
obj: 需要修改属性的对象
Returns:
"""
def handler(func):
def inner(self, *args, **kwargs):
obj_ = obj if obj is not None else self
if not hasattr(obj_, attr):
raise ValueError(f"对象:{obj_.__class__.__name__} 缺失属性: {attr}")
his_value = getattr(obj_, attr)
setattr(obj_, attr, value)
try:
res = func(self, *args, **kwargs)
finally:
setattr(obj_, attr, his_value)
return res
return inner
return handler
27.多个装饰器执行顺序
多个装饰器执行顺序:1. 装饰器在使用于func函数时,就会实例化,dec2 > dec1。2. 执行func()时,逐个闭包dec1进入wrapper执行,然后dec2进入wrapper执行,dec1>dec2
@dec1
@dec2
def func(): pass
func()
@staticmethod
@max_try(3)
def test():
pass
直接运行:在装饰器使用时就运行,直到wrapper
如果实例化Training:再进入wrapper运行,直至结束逐个闭包
def timing(status='Train'):
print('this is timing')
def dec(func):
print('this is dec in timing')
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
func1 = func(*args, **kwargs)
print('[%s] time: %.3f s ' % (status, time.time() - start))
return func1
return wrapper
return dec
@timing(status='Train')
def Training():
time.sleep(3)
# 直接运行返回
# this is timing
# this is dec in timing
Training()
# this is timing
# this is dec in timing
# [Train] time: 3.015 s
28.字典.setdefault()
aaa = dict.get(key, [])
aaa.appent(item)
dict[key] = aaa
======> 如果字典有key,则返回值并且append进去;没有key,则新增key和默认值,再弹出值,append进值中
dict.setdefault(key, []).append(item)
# table_info.setdefault(real_sm, "0") 返回real_sm键对应的值。如果不存在键,则update设置默认值,再返回real_sm键对应的值
table_info[real_sm] = add(table_info.setdefault(real_sm, 0), 777)
29.字典.update(dict)
将字典键值对添加到另一个字典中,如果键冲突,就已最后添加的值为准
30.bisect 库
bisect --- 数组二分查找算法 — Python 3.10.7 文档
bisect.
bisect_right
(a, x, lo=0, hi=len(a), *, key=None)a
x :对a遍历,和a进行比较,相等时右优先
lo=0, hi=len(a) : 比较范围
key : 从数组的每个元素中提取比较键
def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
i = bisect(breakpoints, score) # 等同于 bisect.bisect_right,获取score下标
return grades[i] # 返回成绩
>>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
['F', 'A', 'C', 'C', 'B', 'A', 'A']
31.set 集合
a | b 并集,a & b 交集,a - b 差集
32.functools.patical 冻结参数
def tag(name, *content, cls=None, **attrs):
"""生成一个或多个HTML标签"""
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
else:
attr_str = ''
if content:
return '\n'.join('<%s%s>%s</%s>' %(name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)
>>> tag
<function tag at 0x10206d1e0>
from functools import partial
picture = partial(tag, 'img', cls='pic-frame')
>>> picture(src='wumpus.jpeg')
'<img class="pic-frame" src="wumpus.jpeg" />'
>>> picture
functools.partial(<function tag at 0x10206d1e0>, 'img', cls='pic-frame')
33.解决数组越界思考
popup.local_popups[-1].get("keyword", "") == "777" if popup.local_popups else False
34. 对不可变对象拼接、做增量赋值
对 += 或 *= 所做的增量赋值来说,如果左边的变量绑定的是不可变对象,会创建新对象;如果是可变对象,会就地修改。
aaa = (1, 2)
print(id(aaa)) # 16365328
aaa += (777, ) # s.__iadd__(s2) s.__add__(s2) 元组可以实现拼接、就地拼接
print(aaa) # (1, 2, 777)
print(id(aaa)) # 21765496
35.find() index()
可遍历对象.find(str, beg=0, end=len(string))
可遍历对象.index(str, beg=0, end=len(string))
index查找不到返回ValueError,find查找不到不报错返回-1
36.type运用
begin、step都是数字类型
type(self.begin + self.step)(self.begin)
type对象后得到数字类型,然后通过类型实例化本身
先做加法运算,然后使用计算结果的类型强制转换生成的结果
37.***标准库中的生成器函数***
《流畅的python》--14.9 标准库中的生成器函数
38.浅复制
l1 = [111, 777]
l2 = l1[:] # 对l1做浅复制
l2 is l1 # False
l3 = [3, [66, 55, 44], (7, 8, 9)]
l4 = l3[:]
l3 is l4 # False
l3[1] is l4[1] # True
需注意类实例化2次,不会指向一个引用
class TwilightBus:
"""让乘客销声匿迹的校车"""
def __init__(self, passengers=[]):
self.passengers = passengers
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
aaa = TwilightBus()
bbb = TwilightBus()
aaa is bbb # False
aaa.passengers is bbb.passengers # True
aaa.pick(777)
bbb.passengers # [777]
class TwilightBus2:
"""让乘客销声匿迹的校车"""
def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers) # 实现防御可变参数
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
aaa = TwilightBus2()
bbb = TwilightBus2()
aaa.passengers is bbb.passengers # False
aaa.pick(777)
bbb.passengers # []
39.垃圾回收和弱引用
a_set = {1, 3}
wref = weakref.ref(a_set) # 对a_set弱引用,返回ref类
wref() # {1, 3}
a_set = {3, 4}
wref # <weakref at 0x000002C1CCB754E0; dead>
wref() # None
class Cheese:
def __init__(self, kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
stock = weakref.WeakValueDictionary()
catalog = [Cheese('Red Leicester'), Cheese('Tilsit'), Cheese('Brie'), Cheese('Parmesan')]
for cheese in catalog:
stock[cheese.kind] = cheese
# cheese变量为列表中最后一项,仍然被引用
del catalog
sorted(stock.keys()) # ['Parmesan']
del cheese
sorted(stock.keys()) # []
set、list子类、dict子类,可以作为弱引用的目标。int、tuple实例或者子类都不能作为弱引用目标
40.zip和zip_longest
list(zip(range(3), 'ABC', [0.0, 1.1, 2.2, 3.3]))
# 当一个可迭代对象耗尽后,它不发出警告就停止。
[(0, 'A', 0.0), (1, 'B', 1.1), (2, 'C', 2.2)]
list(zip_longest(range(3), 'ABC', [0.0, 1.1, 2.2, 3.3], fillvalue=-1))
# 当一个可迭代对象耗尽后,使用默认值(None)填充缺少值,直到所有迭代对象耗尽。
[(0, 'A', 0.0), (1, 'B', 1.1), (2, 'C', 2.2), (-1, -1, 3.3)]
41.协程
42.itertools.product()
返回一个笛卡尔积的迭代器
import itertools
a = (1, 2, 3)
b = ('A', 'B', 'C', 'D')
c = itertools.product(a, b)
for elem in c:
print(elem)
43.德摩根定律
not 条件 or not 条件 == not (条件 and 条件)
44.product返回笛卡尔积
接受多个可迭代对象,返回它们的笛卡尔积
list(product([1, 2], [3, 4]))
# [(1, 3), (1, 4), (2, 3), (2, 4),]
45.islice(seq, start, end, step)对可迭代对象切片
with open(filname, "r") as fp:
for line in islice(fp, 0, None, 2)
yield line
46.__eq__
class Node:
def __init__(self, key):
self.key = key
def __eq__(self, other):
return self.key == other
def __lt__(self, other):
return self.key < other
def __hash__(self):
return hash(self.key)
def __getitem__(self, item):
return self.key[item]
def __str__(self):
return str(self.key)
def __repr__(self):
return "<%s: (%r, %r)>" % (self.__class__.__name__, self.key[0], self.key[1])
node = Node((111, 222))
print(node in [(777, 888), (111, 222)]) # True
列表中每一项都和node比较 node == 每一项,即 node.__eq__(每一项)
47.自定义元组类
class DemoTuple(tuple):
def __new__(cls, value, setting, *args, **kwargs):
self = super().__new__(cls, value)
self.setting = setting
return self
aaa = DemoTuple([1, 2], 777)
aaa.setting # 777
isinstance(aaa, tuple) # True
bbb = DemoTuple((1, 2), 111)
bbb.setting # 111
isinstance(bbb, tuple) # True
48.f-string语法
aaa = [1, 777, 2313, 33]
for i in aaa:
print(f"{i: 5}")
"""使输出格式占用5个字符
1
777
2313
33
"""
aaa = "8"
print(f"{aaa: 0>8}")
"""用0补全8位字符串
00000008
"""
49.访问对象属性顺序
__getattribute__ > 特性(property) > 对象__dict__ > 类__dict__ > __getattr__
50.django:ConnectionProxy 代理设计模式
51.django:LazySettings 懒加载设计
52.元类
1. 子类继承父类,父类由元类创建,子类也是由元类创建
2. 在 MyBaseClass MySubClass 被定义时,元类就会调用 __new__ __init__ 方法
class MyMeta(type):
def __new__(cls, *args, **kwargs):
meta_obj = super(MyMeta, cls).__new__(cls, *args, **kwargs)
print("元类实例:", cls.__name__)
return meta_obj
def __init__(cls, name, bases, attrs):
print("元类初始化:", cls.__name__)
class MyBaseClass(metaclass=MyMeta):
pass
class MySubClass(MyBaseClass):
pass
# obj = MySubClass()
# obj2 = MyBaseClass()
"""
元类实例: MyBaseClass
元类初始化: MyBaseClass
元类实例: MySubClass
元类初始化: MySubClass
"""
53.__init_subclass__在不使用元类情况下改变子类行为
54.在遍历生成器时报错,下次再遍历只能从报错位置的下一个起
55.异步上下文管理
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def async_resource1():
print("Entering async resource 1")
try:
yield
finally:
print("Exiting async resource 1")
@asynccontextmanager
async def async_resource2():
print("Entering async resource 2")
try:
yield
finally:
print("Exiting async resource 2")
async def main():
async with async_resource1() as resource1, async_resource2() as resource2:
# 在这里可以安全地使用 resource1 和 resource2
print("Using resources")
asyncio.run(main())
"""
Entering async resource 1
Entering async resource 2
Using resources
Exiting async resource 2
Exiting async resource 1
"""