Python的重载
Python的装饰器
装饰器的作用就是在不改变函数的结构下为函数增加其他的功能,
参考文章
Python的装饰器有两种:函数装饰器和类装饰器
函数装饰器:
函数装饰器就是把函数当做一个对象来传递和返回,
import logging
def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
logging.warn("%s is running" % func.__name__)
elif level == "info":
logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper
return decorator
@use_logging(level="warn")
def foo(name='foo'):
print("i am %s" % name)
foo()
代码结果如下:
E:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:5: DeprecationWarning: The 'warn' function is deprecated, use 'warning' instead
"""
WARNING:root:foo is running
i am foo
类装饰器:
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Foo
def bar():
print ('bar')
bar()
结果如下:
class decorator runing
bar
class decorator ending
常见的装饰器
@property:
使调用类中的方法像引用类中的字段属性一样。被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式。遵循了统一访问的原则
@property可以用来实现类似与Java中set和get方法
class A(object):
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
a = A("Yznx")
print(a.name)
a.name = "yznx"
print(a.name)
结果如下:
Yznx
yznx
@classmethod:
使用这个装饰器,类方法的第一个参数是一个类,是将类本身作为操作的方法。类方法被哪个类调用,就传入哪个类作为第一个参数进行操作。
# coding: utf-8
class Car(object):
car = "audi"
@classmethod
def value(self, category): # 可定义多个参数,但第一个参数为类本身
print ("%s car of %s" % (category, self.car))
class BMW(Car):
car = "BMW"
class Benz(Car):
car = "Benz"
print ("通过实例调用")
baoma = BMW()
baoma.value("Normal") # 由于第一个参数为类本身,调用时传入的参数对应的时category
print ("通过类名直接调用")
Benz.value("SUV")
结果如下:
通过实例调用
Normal car of BMW
通过类名直接调用
SUV car of Benz
@staticmethod:
将类中的方法装饰为静态方法,即类不需要创建实例的情况下,可以通过类名直接引用。到达将函数功能与实例解绑的效果。
# coding: utf-8
class TestClass:
name = "test"
def __init__(self, name):
self.name = name
@staticmethod
def fun(self, x, y):
return x + y
cls = TestClass("felix")
print ("通过实例引用方法")
print (cls.fun(None, 2, 3)) # 参数个数必须与定义中的个数保持一致,否则报错
print ("类名直接引用静态方法")
print (TestClass.fun(None, 2, 3))
结果如下:
通过实例引用方法
5
类名直接引用静态方法
5
Python的深拷贝和浅拷贝
这个很简单,学Python的都要会,反正深拷贝只有一种模式:copy模块中的deepcopy()
函数
多进程、多线程及其中间的通信
进程(multiprocessing):
定义:
一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。
通信:
进程与进程之间通信:queue(消息队列)
多线程(threading):
定义:
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
通信:
同一进程中的不同线程之间可以直接通信,共享变量。所以 线程非安全,需要进行上锁。
对比
- 一个程序至少有一个进程,一个进程至少有一个线程.
- 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
- 线程不能独立运行,需要依存在进程中
示意图:
GIL
- Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。
- GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
- 线程释放GIL锁的情况: 在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100
就是因为有GIL的存在,Python也就不是真正意义上的多线程。
悲观锁和乐观锁
定义:
乐观锁和悲观锁是两种思想,用于解决并发场景下的数据竞争问题。
乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,否则执行操作。
悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。
实现:
乐观锁实现:
CAS
版本号
参考文章:
如何把一个类方法变成属性
见前面常见的装饰器中的 @property 装饰器
垃圾回收机制
Python的垃圾回收机制,Python就是万物都是对象,然后每一个对象有一个引用计数,当引用计数为0时,对象会被回收。
单例模式
定义:
单例是一种设计模式,应用该模式的类只会生成一个实例。 单例模式保证了在程序的不同位置都可以且仅可以取到同一个对象实例:如果实例不存在,会创建一个实例;如果已存在就会返回这个实例。因为单例是一个类,所以你也可以为其提供相应的操作方法,以便于对这个实例进行管理。
实现方式:
使用函数装饰器实现:
代码:
def singleton(cls):
_instance = {}
def inner():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return inner
@singleton
class Cls(object):
def __init__(self):
pass
cls1 = Cls()
cls2 = Cls()
print(id(cls1) == id(cls2))
输出结果:
True
使用类装饰器实现:
代码:
class Singleton(object):
def __init__(self, cls):
self._cls = cls
self._instance = {}
def __call__(self):
if self._cls not in self._instance:
self._instance[self._cls] = self._cls()
return self._instance[self._cls]
@Singleton
class Cls2(object):
def __init__(self):
pass
cls1 = Cls2()
cls2 = Cls2()
print(id(cls1) == id(cls2))
输出结果:
True
使用new关键字实现:
代码:
class Single(object):
_instance = None
def __new__(cls, *args, **kw):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kw)
return cls._instance
def __init__(self):
pass
single1 = Single()
single2 = Single()
print(id(single1) == id(single2))
输出结果:
True
使用mateclass实现
代码:
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Cls4(metaclass=Singleton):
pass
cls1 = Cls4()
cls2 = Cls4()
print(id(cls1) == id(cls2))
输出结果:
True
参考文章:
设计模式(MVC和ORM)
ORM
定义:
ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。 一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句
MVC和ORM的定义很简单,但是需要掌握。容易忘记
Python的多类继承
is 与 == 的区别
Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。对象之间比较是否相等可以用==,也可以用is。
is和==都是对对象进行比较判断作用的,但对对象比较判断的内容并不相同。下面来看看具体区别在哪?
is比较的是两个对象的id值是否相等,也就是比较两个对象是否为同一个实例对象,是否指向同一个内存地址。
==比较的是两个对象的内容是否相等,默认会调用对象的eq()方法。判断两个对象的value值
lambda函数与with()函数
lambda函数:
又叫匿名函数,lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数。
1、lambda 函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,
连名字都很随意的情况下;
2、匿名函数,一般用来给 filter, map 这样的函数式编程服务;
3、作为回调函数,传递给某些应用,比如消息处理。
with函数:
当with 执行时,执行 上下文表达式(context_expr) 来获得一个上下文管理器,上下文管理器的职责是提供一个上下文对象,用于在with语句块中处理细节:
1、 一旦获取的上下文对象,就会调用它的 enter() 方法, 将完成 with语句 块执行前的所有准备功能工作。
2、如果with 语句后面跟了 as 语句,则用 enter() 方法的返回值来赋值;
3、当with语句块结束时,无论是正常结束,还是由于异常,都会调用上下文对象的exit()方法,exit()方法有3个参数,如果with语句正常结束,三个参数全部都是 None;如果发生异常,三个参数的值分别等于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和跟踪记录(traceback),相应的跟踪记录对象。