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。

  1. __new__是一个静态方法,而__init__是一个实例方法
  2. __new__方法会返回一个创建的实例,而__init__什么都不返回
  3. 只有在__new__返回一个cls的实例时,后面的__init__才能被调用
  4. 当创建一个新实例时调用_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__()方法接收到的参数依次是:

  1. 当前准备创建的类的对象;
  2. 类的名字;
  3. 类继承的父类集合;
  4. 类的方法集合。

例子: 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也是其自身的实例)

变量类型

  1. None(全局只有一个)
  2. 数值
  3. 迭代类型
  4. 序列类型
  5. 映射
  6. 集合
  7. 上下文管理类型(with语句)
  8. 其他(模块、函数、代码、方法等)

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命名

特点:

  1. 功能单一
  2. 不和基类关联,可以和任意基类组合
  3. 不再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'],)
posted @ 2021-01-14 22:45  某某人8265  阅读(53)  评论(0编辑  收藏  举报