python语言特性
python
装饰器
def log(func):
@functools.wraps # 实现 wrapper.__name__ = func.__name__
def wrapper(*args, **kw):
print("befor")
ret = func()
print("after")
return ret
return wrapper
@log # 相当于执行了 fun=log(fun),函数名也会变为 wrapper
def fun():
pass
def log(text):
def decorator(func):
@functools.wraps
def wrapper(*args, **kw):
ret = func(*args, **kw)
return ret
return wrapper
return decorator
@log("string") # 先执行log(),再执行 fun=decorator(fun),函数名变为 wrapper
def fun():
pass
类
type 与类
Hello = type('Hello', (object,), dict(hello=fn)) # class 名称,要继承的类,要绑定的方法
# 等于
class Hello(object):
def hello():
pass
_new_
__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
- __new__是一个静态方法,而__init__是一个实例方法
- __new__方法会返回一个创建的实例,而__init__什么都不返回
- 只有在__new__返回一个cls的实例时,后面的__init__才能被调用
- 当创建一个新实例时调用_new_,初始化一个实例时用_init_
私有变量__var
可通过obj._Obj__var
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
_slots_
在动态运行期间给类绑定一个方法,所有实例都能使用。
class Obj(Object):
__slots__ = ('name', 'age') # 限制类只能绑定一定的属性,对子类无用
# 若子类有__slots__,则子类允许定义的属性为自身__slots__与父类__slots__
property
setter getter
class Student(object):
@property
def score(self):
return self._score
@score.setter # 不设置 score.setter 即为只读属性
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
metaclass 元类
先定义metaclass,就可以创建类,最后创建实例
# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass=ListMetaclass):
pass
当我们传入关键字参数metaclass
时,魔术就生效了,它指示Python解释器在创建MyList
时,要通过ListMetaclass.__new__()
来创建,在此,我们可以修改类的定义
__new__()
方法接收到的参数依次是:
- 当前准备创建的类的对象;
- 类的名字;
- 类继承的父类集合;
- 类的方法集合。
例子: ORM 框架
单元测试
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a=1, b='test')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
self.assertTrue(isinstance(d, dict))
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value')
def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty']
def setUp(self):
"""每个测试方法前执行"""
print('setUp...')
def tearDown(self):
"""每个测试方法执行后执行"""
print('tearDown...')
多进程
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
子进程:
r = subprocess.call(['nslookup', 'www.python.org'])
子进程接收输入:
import subprocess
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx\npython.org\nexit\n')
print(output.decode('utf-8'))
print('Exit code:', p.returncode)
Threadlocal
import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
TCP
客户端:
# 导入socket库:
import socket
# 创建一个socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立连接:
s.connect(('www.sina.com.cn', 80))
# 发送数据:
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
# 接收数据:
buffer = []
while True:
# 每次最多接收1k字节:
d = s.recv(1024)
if d:
buffer.append(d)
else:
break
data = b''.join(buffer)
# 关闭连接:
s.close()
服务端:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 监听端口:
s.bind(('127.0.0.1', 9999))
s.listen(5)
while True:
# 接受一个新连接:
sock, addr = s.accept()
# 创建新线程来处理TCP连接:
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
def tcplink(sock, addr):
print('Accept new connection from %s:%s...' % addr)
sock.send(b'Welcome!')
while True:
data = sock.recv(1024)
time.sleep(1)
if not data or data.decode('utf-8') == 'exit':
break
sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
sock.close()
print('Connection from %s:%s closed.' % addr)
UDP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口:
s.bind(('127.0.0.1', 9999))
while True:
# 接收数据:
data, addr = s.recvfrom(1024)
print('Received from %s:%s.' % addr)
s.sendto(b'Hello, %s!' % data, addr)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
# 发送数据:
s.sendto(data, ('127.0.0.1', 9999))
# 接收数据:
print(s.recv(1024).decode('utf-8'))
s.close()
协程 异步
async def hello():
print("Hello world!")
r = await asyncio.sleep(1) # 此处为异步非阻塞IO,cpu不再等待,而是执行其他。当iO结束后再转来执行
print("Hello again!")
type object class
一切类都继承自object,一切类都是type的实例(type也是其自身的实例)
变量类型
- None(全局只有一个)
- 数值
- 迭代类型
- 序列类型
- 映射
- 集合
- 上下文管理类型(with语句)
- 其他(模块、函数、代码、方法等)
len方法
一般为调用 len,当参数为list、dict、set等时直接调用对象内部保存的长度,此处为解释器优化
抽象基类
# 可以实现,但是只有在调用方法时才报错
class Base(Object):
raise NotImplementedError
import abc
class Base(metaclass=abc.ABCMeta):
@abc.abstractmethos # 加上后就无需抛出异常了
def fun(self):
pass
# 在对其或其子类初始化时就会抛出异常,不常使用,更推荐用鸭子类型、多继承
常用基类在collections.abc
下
类属性与实例属性
class A(object):
aa = 1
a = A()
print(A.aa) # 1
print(a.aa) # 1 在实例中没查找到aa属性,向上到类中查找
a.aa = 100 # 此时给实例也添加了一个 aa 属性
print(A.aa) # 1
print(a.aa) # 100
查找顺序
由下向上
c3算法,MRO序列:
https://blog.csdn.net/u011467553/article/details/81437780
https://lotabout.me/2020/C3-Algorithm/
一般多继承使用深度遍历,菱形继承使用广度遍历
当调用super().__init__()
时,调用的的是MRO序列中的下一个类。
可用obj.__mro__
查看
静态方法、类方法、对象方法以及参数
普通方法与实例绑定,静态方法与类绑定
class Obj(object):
def fun(self, *arg):
pass
# 普通实例方法,运行时是 fun(实例, *arg)
@staticmethod
def static_fun():
return Obj()
# 静态方法,运行时与普通函数无异。但调用方法为 Obj.static_fun()
# 但返回的对象为硬编码进去的,当方法与这个类无关时使用它
@classmethod
def class_fun(cls, *arg):
return cls(*arg)
# 类方法,将类这个对象作为第一个参数传入
# 在类改名后依然可以正常使用
自省
obj.__dir__
对应的是属性字典。对其操作相当于操作对象的属性。但其中不包含继承的属性。
dir(obj)
得到的包括自己的与继承的属性与方法。
mixin 模式
类似java中接口。这是一种编码方法,类以XXXMixin
命名
特点:
- 功能单一
- 不和基类关联,可以和任意基类组合
- 不再mixin中使用super()
上下文管理器协议
实现__enter__
__exit__
后即可使用with语句
进入with语句后最先调用__enter__
退出with语句时最后调用__exit__
利用contextlib库可以更快的实现
@contextlib.contextmanager
def file_open(file_name):
print("befor open file")
yield {}
print("after open file")
with file_open("file.txt") as f:
print("file processing")
# befor open file
# file processing
# after open file
python 变量
python的变量都是指针,指向赋值的目标。
class Com(object):
def __init__(self, staffs=[]):
self.staffs = staffs
def add(self, user):
self.staffs.append(user)
def remove(self, user):
self.staffs.remove(user)
com1 = Com([1,2,3])
print(com1.staffs) # [1, 2, 3]
com2 = Com()
com2.add("person1")
print(com2.staffs) # ['person1']
com3 = Com()
com2.add("person2")
print(com1.staffs) # [1, 2, 3]
print(com3.staffs) # ['person1', 'person2']
print(com3.staffs) # ['person1', 'person2']
print(com2.staffs is com3.staffs) # True
print(Com.__init__.__defaults__) # (['person1', 'person2'],)