046 property方法的原理
-
property方法的原理
-
描述符
描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
-
MyDecriptor就是x的描述符,所以MyDecriptor类就是一个描述符类(通常带有get,set和delete三种方法)
第一个参数是self必须得要的,表示this指针。
第二个参数是表示实例的拥有者,也就是当x = MyDecriptor()时,这个instance实例对象就是另一个类Test类
>>> class MyDecriptor:
def __get__(self,instance,owner):
print("getting",self,instance,owner)
def __set__(self,instance,value):
print("setting",self,instance,value)
def __delete__(self,instance):
print("deleting",self,instance)
>>> class Test:
x = MyDecriptor()
>>> test = Test()
>>>
>>> test.x
getting <__main__.MyDecriptor object at 0x000002A9341D82E0> <__main__.Test object at 0x000002A9341D8400> <class '__main__.Test'>
>>> test.x = "X-man" #test.x = "x-man":出现等号,就是赋值,就会调用set方法,前两个参数是一样的,第三个参数就是我们写的值value。
setting <__main__.MyDecriptor object at 0x000002A9341D82E0> <__main__.Test object at 0x000002A9341D8400> X-man
>>> del test.x
deleting <__main__.MyDecriptor object at 0x000002A9341D82E0> <__main__.Test object at 0x000002A9341D8400>
-
所以实际Property就是这样实现的,我们自己利用描述符实现一个Property试试就可以知道了。
-
小练习
-
现在假设我设置fah = 100,这句出现了赋值号,那么fah这个属性有一个描述符类Fahrenheit,Fahrenheit也就是去描述fah这个属性的,当这个属性被赋值时,就会默认执行描述符类的__set__方法。然后他就去执行instance.cel = (float(value) - 32) / 1.8这句,因为instance就是实例对象Temperature,然后就调用它的属性cel,而cel的描述符类是Celsius,出现了= (float(value) - 32) / 1.8这个赋值符号,那么就会去执行Celsius描述符类的set方法,然后设置到他类的value里面。
047 定制序列
也叫定制容器,但在定制容器之间,需要先了解协议:
-
容器类型的协议
-
如果说希望定制的容器是不可变的,那么**只需要定义__len__()和__getitem()**方法
-
如果希望定制的容器是可变的话,除了__len__()和__getitem__()方法,还需要定义__setitem__()和__delitem__()两个方法
-
容器类型的魔法方法:
-
小练习来验证
自定义一个容器类,写好构造方法,参数是可变数量的,在之前学过如果参数是可变数量的就需要写成*args的形式,我们不知道参数有多少,那么就先把他都放到一个列表里。要实现记录列表中每个元素被访问的次数,可以用字典来做,把列表中的下标作为字典的键,值就是对应的访问次数。
-
048 迭代器
-
提供迭代的容器,就叫做迭代器(字典,元组,列表,字符串)
-
迭代操作,例如for循环,就可以迭代容器里面的内容。
-
迭代字典
-
-
Python提供了两个内置的迭代方法
-
iter()
- 对于一个容器对象调用iter()返回的就是一个迭代器,迭代器调用next方法就会迭代下一个值。
-
next()
-
如果迭代出没有元素,那么就会抛出StopIteration异常
>>> string = "haha" >>> it = iter(string) >>> next(it) 'h' >>> next(it) 'a' >>> >>> next(it) 'h' >>> next(it) 'a' >>> next(it) Traceback (most recent call last): File "<pyshell#44>", line 1, in <module> next(it) StopIteration >>>
-
-
-
我们的循环语句for语句实际内部是自动调用了迭代器的。使用while循环还原for语句:
>>> while True: try: each = next(it) except StopIteration: print("迭代完了") break print(each) h a h a 迭代完了
-
迭代器的魔法方法,他们对应的就是上面两个BIF的实现,如果一个容器如果是一个迭代器,那么必须实现iter的魔法方法和next魔法方法:
- __iter__()
- __next__()
写一个容器类:
在这里他会不断的一直迭代,因为没有条件限制,他就会一直执行下去。所以需要加条件
049 生成器(乱入器)
定义:一旦函数里面出现了yield关键字,这个函数就被称之为生成器。
他是一种特殊的迭代器。生成器使得Python的协同程序得以实现。
-
所谓协同程序就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或重新开始。函数都是一条一条语句进行执行,执行完后该释放的变量就会被释放,而生成器可以暂时暂停,去执行其他程序,等到必要的时候又继续执行或重新开始。
-
当我们调用这个生成器函数时,他执行到第一个yield,就暂停并将yield后面的值返回,当我们next这个生成器的时候他就会打印yield后面的值,有几个yield就可以next几次,超过则抛出stopiteration异常。
具体实例:
050 模块
是一种高级的封装。保存的是一个.py的程序就是一个独立的模块
-
第一种模块导入的方式
语法:
Import模块名
-
但是要使用模块里面的函数,则需要有命名空间的区别,因为不同的模块会出现相同的方法,为了避免冲突,就有了命名空间这个概念,也就是用模块名.方法,进行分别。
-
-
第二种模块导入的方式
语法:
from 模块名 import 函数名
-
这种方式导入的话就不需要命名空间了,就可以直接导入了。
-
也可以直接导入模块中所有的函数:form 模块名 import *
-
-
第三种模块导入的方式(推荐使用)
语法:
import 模块名 as 导入的命名空间的新名字
__name__=’__main__'搜索路径和包
-
回顾模块的主要作用:
1.封装代码
2.实现代码的重用
-
if __name__==’__main__'
-
因为在我们导入模块时,他是将整个python文件进行导入,所以当我们执行程序时,他会把整个文件的东西都执行一遍。
例如:
那我们现在就想执行这两个方法,其他的都不执行,我们就应该让Python知道该模块是作为程序运行,还是导入到其他程序中。
就可以用if __name__==’__main__'来进行判断是作为程序运行还是导入到其他程序中。
这句话也就是判断当他不是作为导入模块时(作为程序运行时)才运行。
-
-
搜索路径
Python模块的导入需要一个路径搜索的过程,导入一个模块,他会在预订的搜索路径中去搜索这个路径中是否存在这个模块,这个路径有很多个,可以通过sys.path进行查看(记得先导入sys)
那么模块一般都存在哪个位置呢?一般都存在site-packages这个文件夹里,这个文件夹是专门用来放模块的。
如果你的模块放在其他的路径中,你也可以使用sys.path.append方法添加路径
-
包(apckage)
因为可能我们的模块文件也会出现同名的情况,所以Python中有包的概念
-
一定要有一个__init__.py文件,因为是告诉Python这个文件夹是要当做包来进行管理,这个文件可以为空,但一定得有。
-
导入包中的模块
语法:
import 包名.模块名
-
像一个极客去思考
-
Python自己带着电池:也即是说Python自己带着标准库
-
用一种方法,最好是只有一种方法来做一件事
-
像一个极客去思考问题
- 跟学Java一样,看手册,看文档,尝试各种方法的使用。
- 还有就是可以使用Python的内置函数help进行方法的查看。
Python总结
- 学Python的目的是为了更好地进行机器学习,不打算往深的方向走,例如爬虫、网络编程、GUI等,暂时学会基础语法,能看懂机器学习大佬写的代码,能自己动手实验就是我的目的。G4ubmV0L3FxXzQyMjYzNTUz,size_16,color_FFFFFF,t_70)
- 等到有需要用Python做高级应用时再进行学习。