python 高级
python提高
GIL
-
Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在
Cpython虚拟机(解释器),难以移除GIL。 -
GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
-
python 使用多进程是可以利用多核的CPU资源的.
-
多线程爬取比单线程有提升, 因为遇到IO阻塞会自动释放GIL锁 .
eg:多线程客户端向服务器请求多个数据 可以一个个发送后 等待回复. 但是单线程只能等上一个任务完成后才能发送另一个任务.
-
多进程适合高密度计算的程序
多线程适合多IO操作的程序
深拷贝 浅拷贝
-
浅拷贝是拷贝了引用, 不拷贝内容
-
深拷贝是对一个对象所有层次进行了拷贝 这个对象改变, 拷贝来对象不改变
-
拷贝的其他方式:
- 分片表达式可以赋值一个序列
eg: b = a[:] copy.copy方法可以拷贝
- 分片表达式可以赋值一个序列
-
注意点
-
浅拷贝对不可变类型和可变类型的copy不同
copy.copy对于可变类型, 会进行浅拷贝 仅仅拷贝第一层 假如列表中的列表改变则 浅拷贝的内容也会改变copy.copy对于不可变类型, 不会拷贝, 仅仅是指向
In [88]: a = [11,22,33] # 可变类型 In [89]: b = copy.copy(a) In [90]: id(a) Out[90]: 59275144 In [91]: id(b) Out[91]: 59525600 In [92]: a.append(44) In [93]: a Out[93]: [11, 22, 33, 44] In [94]: b Out[94]: [11, 22, 33] #仅仅拷贝第一层,假如列表中的列表改变则 浅拷贝的内容也会改变 In [2]: a = [1, 2, [3, 4]] In [3]: b = copy.copy(a) In [4]: b Out[4]: [1, 2, [3, 4]] In [5]: a[2][1] = 2 In [6]: a Out[6]: [1, 2, [3, 2]] In [7]: b Out[7]: [1, 2, [3, 2]] # 不可变类型 即不可使用append, extend,sort 等要修改自身的操作 In [95]: a = (11,22,33) In [96]: b = copy.copy(a) In [97]: id(a) Out[97]: 58890680 In [98]: id(b) Out[98]: 58890680 -
copy.copy和copy.deepcopy的区别b = copy.copy(a)复所有a指向的数据到一个新的空间, 但不会递归copyb = copy.deepcopy(a)会将c指向的空间进行递copy, 产生两个内容完全一样,但引用不同. 即a指向一个空间 b指向一个新的空间.
-
私有化
xx: 公有变量_x: 单前置下划线, 私有化属性或者方法, 即from somemodule import *禁止导入, 类对象和子类可以访问.__xx: 双前置下划线, 避免与子类的属性命名冲突, 完全私有 不能导入不能继承 外部不能访问.__xx__: 双前后下划线, 用户名字空间的魔法对象或属性. 是公有属性.xx_: 单后置下划线, 用于避免与python关键字冲突 ,print和print_
import 导入模块
-
import 搜索路径
In [2]: import sys In [3]: sys.path Out[3]: ['C:\\Users\\58347\\AppData\\Local\\Programs\\Python\\Python37\\Scripts\\ipython.exe', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\python37.zip', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\DLLs', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37', '', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\sqlalchemy-1.3.3-py3.7-win-amd64.egg', 'c:\\users\\58347\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\IPython\\extensions', 'C:\\Users\\58347\\.ipython']- 路径搜索
- 从上面列出的目录里依次查找要导入的模块文件
''表示当前路径- 列表中的路径的先后顺序代表了python解释器在搜索模块时的先后顺序
-
程序执行时添加新模块
sys.path.append('/xxx/xxx') sys.path.insert(0.'/xxx/xxx')
-
重新导入模块
模块被导入后,
import module不能重新导入模块, 重新导入需用reload
多继承以及MRO顺序
-
单独调用父类的方法
类方法重写是覆盖父类的方法
print("******多继承使用类名.__init__ 发生的状态******") class Parent(object): def __init__(self, name): print('parent的init开始被调用') self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name, age): print('Son1的init开始被调用') self.age = age Parent.__init__(self, name) print('Son1的init结束被调用') class Son2(Parent): def __init__(self, name, gender): print('Son2的init开始被调用') self.gender = gender Parent.__init__(self, name) print('Son2的init结束被调用') class Grandson(Son1, Son2): def __init__(self, name, age, gender): print('Grandson的init开始被调用') Son1.__init__(self, name, age) # 单独调用父类的初始化方法 Son2.__init__(self, name, gender) print('Grandson的init结束被调用') gs = Grandson('grandson', 12, '男') print('姓名:', gs.name) print('年龄:', gs.age) print('性别:', gs.gender) print("******多继承使用类名.__init__ 发生的状态******\n\n")运行结果
******多继承使用类名.__init__ 发生的状态****** Grandson的init开始被调用 Son1的init开始被调用 parent的init开始被调用 parent的init结束被调用 Son1的init结束被调用 Son2的init开始被调用 parent的init开始被调用 parent的init结束被调用 Son2的init结束被调用 Grandson的init结束被调用 姓名: grandson 年龄: 12 性别: 男 ******多继承使用类名.__init__ 发生的状态****** -
多继承中的super调用
print("******多继承使用super().__init__ 发生的状态******") class Parent(object): def __init__(self, name, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数 print('parent的init开始被调用') self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name, age, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数 print('Son1的init开始被调用') self.age = age super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数 print('Son1的init结束被调用') class Son2(Parent): def __init__(self, name, gender, *args, **kwargs): # 为避免多继承报错,使用不定长参数,接受参数 print('Son2的init开始被调用') self.gender = gender super().__init__(name, *args, **kwargs) # 为避免多继承报错,使用不定长参数,接受参数 print('Son2的init结束被调用') class Grandson(Son1, Son2): def __init__(self, name, age, gender): print('Grandson的init开始被调用') # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍 # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因 # super(Grandson, self).__init__(name, age, gender) super().__init__(name, age, gender) print('Grandson的init结束被调用') print(Grandson.__mro__) gs = Grandson('grandson', 12, '男') print('姓名:', gs.name) print('年龄:', gs.age) print('性别:', gs.gender) print("******多继承使用super().__init__ 发生的状态******\n\n")运行结果:
******多继承使用super().__init__ 发生的状态****** (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>) Grandson的init开始被调用 Son1的init开始被调用 Son2的init开始被调用 parent的init开始被调用 parent的init结束被调用 Son2的init结束被调用 Son1的init结束被调用 Grandson的init结束被调用 姓名: grandson 年龄: 12 性别: 男 ******多继承使用super().__init__ 发生的状态******注意:
-
调用累的
__mro__方法会把这个类的所有长辈类(即父类,爷爷类等)通过元组方式列出 例如上面代码中的Grandson类的所有长辈类.print(Grandson.__mro__) (<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>) -
如果两个子类中都继承了父类, 当在孙子类中通过子类名调用两个子类时,parent被执行了两次.
Son1.__init__(self, name, age) Son2.__init__(self, name, gender) -
如果两个父类中都继承了爷爷类, 当在子类中通过
surper调用两个父类时,parent被执行了一次.
super().__init__(name, age, gender)-
子类重写不会影响父类和其他子类
父类重写只会影响没有被重写过的子类
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x, Child1.x, Child2.x) Child1.x = 2 print(Parent.x, Child1.x, Child2.x) Parent.x = 3 print(Parent.x, Child1.x, Child2.x)答案, 以上代码的输出是:
1 1 1 1 2 1 3 2 3
-
静态方法 and 类方法
-
类属性 and 实例属性
- 类属性属于类, 实例属性属于对象
- 类属性是对他的对象共享, 实例属性只属于一个对象
应用场景:
- 通过类创建实例对象时, 如果每个对象需要具有相同的名字和属性, 那么就使用类属性, 用一份即可.
-
实例方法 and 静态方法 and 类方法
三种方法都属于类, 区别在于调用方式不同.
-
实例方法: 由对象调用; 至少有一个
self参数; 执行实例方法时, 自动调用该方法的对象赋值给self. -
类方法: 由类调用; 至少一个
cls参数; 执行类方法时, 自动将调用该方法的类赋值给cls; -
静态方法: 由类调用; 无默认参数;
class Foo(object): def __init__(self, name): self.name = name def ord_func(self): """定义实例方法, 至少有一个self参数""" pass @classmethod def class_func(cls): """定义类方法. 至少有一个cls参数""" pass @staticmethod def static_func(): """定义静态方法, 无默认参数""" pass f = Foo("中国") # 调用实例方法 f.ord_func() # 调用类方法 Foo.class_func() # 调用静态方法 Foo.static_func()
-
property属性
-
使用property
-
定义时, 在实例方法的基础上添加
@property装饰器; 并且仅有一个self参数 -
调用时, 无需括号
# ############### 定义 ############### class Foo: def func(self): pass # 定义property属性 @property def prop(self): pass # ############### 调用 ############### foo_obj = Foo() foo_obj.func() # 调用实例方法 foo_obj.prop # 调用property属性 -
可以复杂的计算方法封装成一个property属性中, 调用这个属性,返回计算结果.
-
-
property属性的两种方式
- 装饰器 即:在方法上应用装饰器
- 类属性 即: 在类中定义值为property对象的类属性
经典类: 具有一种
@property装饰器class Goods(object): @property def price(self): return 'xx yuan' obj = Goods() pri = obj.price print(pri)新式类, 具有三种
@property装饰器class Goods(): """python3中才有@xxx.setter @xxx.deleter""" @property def price(self): return self value @price.setter def price(self, value): self.value = value @price.deleter def price(self): pass obj = Goods() obj.price # 自动执行@property修饰的price方法,并获取返回值 obj.price = 123 # 自动----,并将123赋值给方法的参数 del obj.price
魔法属性
__doc__
- 表示类的描述信息
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print(Foo.__doc__)
#输出:类的描述信息
__module__和__class__
- module 表示当前操作的对象在那个模块
- class 表示当前操作的对象的类是什么
test.py
# -*- coding:utf-8 -*-
class Person(object):
def __init__(self):
self.name = 'laowang'
main.py
from test import Person
obj = Person()
print(obj.__module__) # 输出 test 即:输出模块
print(obj.__class__) # 输出 test.Person 即:输出类
__init__
- 初始化方法,通过类创建对象时,自动触发执行
class Person:
def __init__(self, name):
self.name = name
self.age = 18
obj = Person('laowang') # 自动执行类中的 __init__ 方法
__del__
- 当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
pass
__call__
- 对象后面加括号,触发执行。
注:__init__方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
__dict__
- 类或对象中的所有属性
类的实例属性属于对象;类中的类属性和方法等属于类,即:
class Province(object):
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print('func')
# 获取类的属性,即:类属性、方法、
print(Province.__dict__)
# 输出:{'__dict__': <attribute '__dict__' of 'Province' objects>, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>, 'func': <function Province.func at 0x101897950>, '__init__': <function Province.__init__ at 0x1018978c8>}
obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}
obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
__str__
- 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo:
def __str__(self):
return 'laowang'
obj = Foo()
print(obj)
# 输出:laowang
__getitem__、__setitem__、__delitem__
- 用于索引操作,如字典。以上分别表示获取、设置、删除数据
# -*- coding:utf-8 -*-
class Foo(object):
def __getitem__(self, key):
print('__getitem__', key)
def __setitem__(self, key, value):
print('__setitem__', key, value)
def __delitem__(self, key):
print('__delitem__', key)
obj = Foo()
result = obj['k1'] # 自动触发执行 __getitem__
obj['k2'] = 'laowang' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__
9.__getslice__、__setslice__、__delslice__
- 该三个方法用于分片操作,如:列表
# -*- coding:utf-8 -*-
class Foo(object):
def __getslice__(self, i, j):
print('__getslice__', i, j)
def __setslice__(self, i, j, sequence):
print('__setslice__', i, j)
def __delslice__(self, i, j):
print('__delslice__', i, j)
obj = Foo()
obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__
上下文管理器
任何实现了 __enter__() 和 __exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。
那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 enter() 和 exit() 方法。
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("entering")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, *args):
print("will exit")
self.f.close()
__enter__() 方法返回资源对象,这里就是你将要打开的那个文件对象,__exit__()方法处理一些清除工作。
因为 File 类实现了上下文管理器,现在就可以使用 with 语句了。
with File('out.txt', 'w') as f:
print("writing")
f.write('hello, python')
这样,你就无需显示地调用 close 方法了,由系统自动去调用,哪怕中间遇到异常 close 方法也会被调用。
实现上下文管理器的另外方式
Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。
from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
f = open(path, mode)
yield f
f.close()
调用
with my_open('out.txt', 'w') as f:
f.write("hello , the simplest context manager")
总结
Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。
mysql
python与mysql交互
- python操作mysql的步骤

引入模块
在py文件中引入pymysql模块
from pymysql import *
Connection 对象
用于建立与数据库的连接
创建对象:调用connect()方法
conn=connect(参数列表)
参数host:连接的mysql主机,如果本机是'localhost'
参数port:连接的mysql主机的端口,默认是3306
参数database:数据库的名称
参数user:连接的用户名
参数password:连接的密码
参数charset:通信采用的编码方式,推荐使用utf8
对象的方法
close()关闭连接
commit()提交
cursor()返回Cursor对象,用于执行sql语句并获得结果
Cursor对象
用于执行sql语句,使用频度最高的语句为select、insert、update、delete
获取Cursor对象:调用Connection对象的cursor()方法
cs1=conn.cursor()
对象的方法
close()关闭
execute(operation [, parameters ])执行语句,返回受影响的行数,主要用于执行insert、update、delete语句,也可以执行create、alter、drop等语句
fetchone()执行查询语句时,获取查询结果集的第一个行数据,返回一个元组
fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回
对象的属性
rowcount只读属性,表示最近一次execute()执行后受影响的行数
connection获得当前连接对象
- 增删改
from pymysql import *
def main():
# 创建Connection连接
conn = connect(host='localhost',port=3306,database='jing_dong',user='root',password='mysql',charset='utf8')
# 获得Cursor对象
cs1 = conn.cursor()
# 执行insert语句,并返回受影响的行数:添加一条数据
# 增加
count = cs1.execute('insert into goods_cates(name) values("硬盘")')
#打印受影响的行数
print(count)
count = cs1.execute('insert into goods_cates(name) values("光盘")')
print(count)
# # 更新
# count = cs1.execute('update goods_cates set name="机械硬盘" where name="硬盘"')
# # 删除
# count = cs1.execute('delete from goods_cates where id=6')
# 提交之前的操作,如果之前已经之执行过多次的execute,那么就都进行提交
conn.commit()
# 关闭Cursor对象
cs1.close()
# 关闭Connection对象
conn.close()
if __name__ == '__main__':
main()
-
查询一行
from pymysql import * def main(): # 创建Connection连接 conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8') # 获得Cursor对象 cs1 = conn.cursor() # 执行select语句,并返回受影响的行数:查询一条数据 count = cs1.execute('select id,name from goods where id>=4') # 打印受影响的行数 print("查询到%d条数据:" % count) for i in range(count): # 获取查询的结果 result = cs1.fetchone() # 打印查询的结果 print(result) # 获取查询的结果 # 关闭Cursor对象 cs1.close() conn.close() if __name__ == '__main__': main() -
查询多行
from pymysql import * def main(): # 创建Connection连接 conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8') # 获得Cursor对象 cs1 = conn.cursor() # 执行select语句,并返回受影响的行数:查询一条数据 count = cs1.execute('select id,name from goods where id>=4') # 打印受影响的行数 print("查询到%d条数据:" % count) # for i in range(count): # # 获取查询的结果 # result = cs1.fetchone() # # 打印查询的结果 # print(result) # # 获取查询的结果 result = cs1.fetchall() print(result) # 关闭Cursor对象 cs1.close() conn.close() if __name__ == '__main__': main()
元类
元类就是用来创建类的东西
type就是Python在背后用来创建所有类的元类
type 的创建类的方式
-
type("类名",(父类名,),{"类属性名":"类属性值",})eg :
type("son",("father",),{"num1":"100", "num2":"200"}) -
如果要创建类中带有实例方法 需要先创建好一个实例方法
eg:
type("son",("father",),{"num1":"100", "实例方法名 ":xxxx})xxx是一个函数def sltest(self): print("this is 实例方法") test = type("test", (), {"wtest":wtest}) -
如果要创建的类中带有类方法 需要先创建好一个类方法
eg:
type("son", (), {"num1":"100", "类方法名 ":xxxx})xxx是一个类方法@classmethod def ltest(cls): print("this is 类方法") pass test = type("test", (), {"ltest":ltest})
__metaclass__
-
在创建类的时候添加
__metaclass__属性 python就会使用元类来创建类def create_class(class_name, class_parents, class_attr): return type(class_name, class_parents, class_attr) class Foo(object, metaclass = create_class): num1 = 100Python做了如下的操作:
- Foo中有
__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象) - 如果Python没有找到
__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。 - 如果Python在任何父类中都找不到
__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。 - 如果还是找不到
__metaclass__,Python就会用内置的type来创建这个类对象。
- Foo中有
def upper_attr(class_name, class_parents, class_attr):
#遍历属性字典,把不是__开头的属性名字变为大写
new_attr = {}
for name,value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
#调用type来创建一个类
return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr):
bar = 'bip'
print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))
f = Foo()
print(f.BAR)
__new__
class UpperAttrMetaClass(type):
# __new__实在__init__之前被调用的方法
# __new__使用来创建对象并返回之的方法
# __new__的返回值当做self给__init__
# 而__init__只是用来将传入的参数初始化给对象
# 很少用到__new__, 除非你希望能够控制对象的创建
# 这里创建的对象是类, 我们希望能够自定义它, 所以我们这里改写了__new__
def __new__(cls, class_name, class_parents, class_attr):
# 遍历属性字典 把不是__开头的属性名字变成大写
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 方法1: 通过'type'来做类对象的创建
return type(class_name, class_parents, new_attr)
# 方法2:复用type.__new__方法
# 这就是基本的OOP编程,没什么魔法
# return type.__new__(cls, class_name, class_parents, new_attr) #不懂
class Foo(object, metaclass=UpperAttrMetaClass):
bar = "bip"
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'
不懂看博客blog.csdn.net/qq_41020281…
- 就元类本身而言,很简单:
- 拦截类的创建
- 修改类
- 返回修改后的类
元类实现ORM
orm是什么
- ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。
- 一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句
demo:
class User(父类省略):
uid = ('uid', "int unsigned")
name = ('username', "varchar(30)")
email = ('email', "varchar(30)")
password = ('password', "varchar(30)")
...省略...
u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()
# 对应如下sql语句
# insert into User (username,email,password,uid)
# values ('Michael','test@orm.org','my-pwd',12345)