python 笔记 03—python高级语法
浅拷贝、深拷贝
import copy a= [11,22] b = a # 赋值 c = copy.copy() # 浅拷贝 d = copy.deepcopy(a) # 深拷贝 a.append(33) # c值还是[11,22]
等号赋值、浅拷贝、深拷贝之间的区别:
1、等号赋值等同于拷贝原数据的指向(字符,列表,元组,字典),改变原数据时,赋值后的变量指向的值也会一起变
2、浅拷贝只拷贝指向,不拷贝数据,例:拷贝列表,但是,拷贝之后,原列表数据修改,新增导致指向变化,拷贝指向的数据跟原数据会产生差异
3、深拷贝整个拷贝原数据+指向,但是无法拷贝整个元组(即里外整体全是元组的数据),所以原数据改变后,新拷贝的值不变
4、如果元组内部有可变的量(例如:([11,22],[33,44])),深拷贝可以正常拷贝,否则,深拷贝也不会拷贝只能正常指向原元组
深拷贝的应用场景:需要保留原数据,保证原数据不变,用深拷贝可以拷贝一份随意改动
import导入模块:
import导入会依次检查sys.path路径下是否有这个模块,找不到则报错:
>>> from pprint import pprint >>> pprint(sys.path) ['', 'D:\\workspace\\virtualenv\\py38django2\\Scripts\\python38.zip', 'D:\\workspace\\virtualenv\\py38django2\\DLLs', 'D:\\workspace\\virtualenv\\py38django2\\lib', 'D:\\workspace\\virtualenv\\py38django2\\Scripts', 'c:\\python38\\Lib', 'c:\\python38\\DLLs', 'D:\\workspace\\virtualenv\\py38django2']
重新导入:
import aa print(aa.test_aa()) # 如果此时修改test_aa()里代码,想要新代码生效,不能直接import 需要: reload(aa) print(aa.test_aa())
封装、继承、多态:
class T(object): num = 0 def __init__(self, age): self.age = age t = T(11) print(t.__dict__) print(t.__class__)
打印结果:
{'age': 11}
继承各个父子类之间的属性关系:
class Parent(object): x = 1 class Child1(Parent): pass class Chlid2(Parent): pass print(Parent.x, Chlid1.x, Child2.x) Chlid1.x = 2 # 这步会给当前Chlid1类添加个类属性 x 并赋值 print(Parent.x, Chlid1.x, Child2.x) Parent.x = 3 print(Parent.x, Chlid1.x, Child2.x) # 结果: # 1, 1, 1 # 1, 2, 1 # 3, 2, 3
# 结论:注意继承不会复制父类里的属性,调用子类里没有的属性值时,回去父类找
多态,看一则案例:
class MiniOS(object): """多态案例-模拟操作系统安装应用""" def __init__(self, name): self.name = name self.apps = [] def __str__(self): return "{}安装的应用列表有为{}".format(self.name, self.apps) def add_app(self, name): self.apps.append(name) def install_apps(self, app): # 判断是否已经安装了软件 if app.name in self.apps: print("已经安装了{},无需再次安装。".format(app.name)) else: app.install() self.add_app(app.name) print("{}已经完成安装!".format(app.name)) class App(object): def __init__(self, name, version, desc): self.name = name self.version = version self.desc = desc def __str__(self): return "应用:{},版本:{},描述:{}".format(self.name, self.version, self.desc) def install(self): print("将{}{}安装到制定目录中...".format(self.name, self.version)) class PyCharm(App): pass class Chrome(App): def install(self): print("解压{}安装包".format(self.name)) super().install() linux = MiniOS("linux") pycharm = App("pycharm", "2019.3", "绿色免费版") chrome = App("chrome", "73.0.1", "用于selenium测试") linux.install_apps(pycharm) linux.install_apps(chrome) linux.install_apps(chrome)
结果:
将pycharm2019.3安装到制定目录中...
pycharm已经完成安装!
将chrome73.0.1安装到制定目录中...
chrome已经完成安装!
已经安装了chrome,无需再次安装。
多继承(MRO顺序):
class Parent(object): def __init__(self, name, *args, **kwargs): # 防止调用报错,使用不定长参数,接收参数 """父类""" print("父类开始初始化") self.name = name print("父类结束初始化") class Son1(Parent): def __init__(self, name, age, *args, **kwargs): """子类1""" print("Son1开始初始化") self.age = age super().__init__(name, *args, **kwargs) print("Son1结束初始化") class Son2(Parent): def __init__(self, name, gender, *args, **kwargs): """子类2""" print("Son2开始初始化") self.gender = gender super().__init__(name, *args, **kwargs) print("Son2结束初始化") class Grandson(Son2, Son1): def __init__(self, name, age, gender): """子类2""" print("Grandson开始初始化") # super(Son1,self).__init(name, age, gender) 这种写法可以任意指定方法,然后从此方法往后执行 super().__init__(name, age, gender) print("Grandson结束初始化") # 通过调用C3算法,查看超类调用链(元组) print(Grandson.__mro__)
*args,**kwargs用法:
# 方法定义时使用 def test(a,b,*args,**kwargs): print(a) print(b) print(args) print(kwargs) test(11,22,33,44,55,66,name="Tom",age=2) # 结果: # args = (33,44,55,66) # kwargs = {"name":"Tom", "age":"2"} # 函数调用时使用 list1 = [33,44,55,66] dict1 = {"name":"Jerry","age":"3"} test(11,22,*list1,**dict1) # 结果: # args = (33,44,55,66) # kwargs = {"name":"Jerry", "age":"3"}
实例方法、类方法、静态方法:
class Foo(object): class_str = 11 # 类对象只能有一个,实例对象可以有多个 def __init__(self, name): self.name = name def ord_func(self): """实例方法,self指向实例对象,可以修改实例属性self.name""" print(self.name) print("实例方法!") self.class_func() self.static_func() @classmethod def class_func(cls): """类方法,cls指向类对象,可以修改类属性class_str""" cls.class_str = 22 print("类方法!") # cls.ord_func() # 类方法不能调实例方法 cls.static_func() @staticmethod def static_func(): """静态方法,内部调用时直接写方法,外部调用时无需实例化""" print("静态方法!") # 外部调用除实例方法以外, f = Foo("Annis") f.ord_func() f.class_func() # 或者 Foo.class_func() f.static_func() # 或者 Foo.static_func()
property属性装饰器:
用法,上代码:
class Goods(object): @property def size(self): # 不能传参数 return self._size @size.setter def size(self, value): if value > 0: self._size = value else: raise ValueError("尺寸不合格!")
@size.deleter
def size(self):
del self._size
goods = Goods()
size = goods.size
goods.size = -1 # 无法赋值
del goods.size # 删除属性值
作用跟意义:可以用调用属性的方式直接调用方法,获得返回值,如果直接把属性暴露出去,虽然写起来很简单,但是没办法按预期设想参数检查(比如:成绩不能 <0、>100,年龄不能<0,性别不能为男,女之外的值)
property另外一种写法:
class API(object): def _get_post(self): return self._post def _set_post(self, value): if value > 0: self._post = value else: raise ValueError("!") def _del_post(self): del self._post POST = property(_get_post, _set_post, _del_post)
内建属性:
常用专有属性 | 说明 | 触发方式 |
---|---|---|
__init__ |
构造初始化函数 | 创建实例后,赋值时使用,在__new__ 后 |
__new__ |
生成实例所需属性 | 创建实例时 |
|
实例所在的类 | 实例.__class__ |
|
实例所在的模块,即py文件 | 实例.__module__ |
__str__ |
实例字符串表示,可读性 | print(类实例),如没实现,使用repr结果 |
__repr__ |
实例字符串表示,准确性 | 类实例 回车 或者 print(repr(类实例)) |
__del__ |
析构 | del删除实例 |
__dict__ |
实例自定义属性 | vars(实例.__dict__) |
__doc__ |
类文档,子类不继承,类的描述(类名下面那行注释) | help(类或实例) |
__getattribute__ |
属性访问拦截器 | 访问实例属性时 |
__bases__ |
类的所有父类构成元素 | 类名.__bases__ |
__call__ | 类里实现__call__方法,然后用实例()调用 | 实例() |
__getitem__ __setitem__ __delitem__ |
类里实现这些方法,然后调用,类似get set del |
obj = F() r = obj['k1'] # 触发get obj['k2'] = '老王' # 触发set del obj['k1'] # 触发del |
with、上下文管理器:
with存在的意义:
def m1(): f = open("a.txt", "wb") f.write("222") f.close() def m2(): f = open("a.txt", "wb") try: f.write("222") except Exception as e: raise e finally: f.close() def m3(): with open("a.txt", "wb") as f: f.write("aaa")
# 遇到异常会自动关闭open打开的文件
with实现原理:
class File(object): 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() with File("hh.txt", "w") as f: f.write('xxxx') # 所有实现了 __enter__,__exit__的程序也可以使用with
另外一种实现方法:
from contextlib import contextmanager @contextmanager def my_open(path, mode): f = open(path, mode) yield f f.close() # 调用with一样的效果 with my_open('out.txt', 'w') as f: f.write("hello")
装饰器-元编程
实例:
from functools import wraps def print_result(func): @wraps(func) # 不改变使用装饰器原有函数的结构(如name, doc) def wrapper(*args, **kwargs): result = func(*args, **kwargs) print(result) return result return wrapper @print_result def add(x, y): return x + y add(5, 3)