045魔法方法:属性访问(下)
本帖最后由 摆渡终极鉴黄师 于 2017-10-20 19:57 编辑class Rectangle:
def __init__(self, width=0, height=0):
self.width = width
self.height = height
def __setattr__(self, name, value):
if name == 'square':
self.width = value
self.height = value
else:
self.__dict__ = value
def getArea(self):
return self.width * self.height
(老湿:这名童鞋越来越偷懒了{:10_297:} )
046魔法方法:描述符(Property的原理)(上)
本帖最后由 摆渡终极鉴黄师 于 2017-10-21 11:50 编辑描述符就是将某种特殊类型的类的实例指派给另一个类的属性。
__get__(self, instance, owner)
-用于访问属性,Ta返回属性的值
__set__(self, instance, value)
-将在属性分配操作中调用,不返回任何内容
__delete__(self, instance)
-控制删除操作,不返回任何内容
046魔法方法:描述符(Property的原理)(中)
本帖最后由 摆渡终极鉴黄师 于 2017-10-22 13:53 编辑class MyDescriptor: #Descriptor其实就是一个描述符类
def __get__(self, instance, owner): #self就是描述符类的本身的一个实例,instance是Test的拥有者的类的实例,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 = MyDescriptor() #括号是取这个类的实例,指派Test类的属性x,MyDescriptor是x的描述符,class Test:的上面的那一段代码就是描述符类
046魔法方法:描述符(Property的原理)(中2)
本帖最后由 摆渡终极鉴黄师 于 2017-10-23 19:35 编辑class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
return self.fget(instance)
def __set__(self, instance, value):
self.fset(instance, value)
def __delete__(self, instance):
self.fdel(instance)
class C:
def __init__(self):
self._x = None
def getX(self):
return self._x
def setX(self, value):
self._x = value
def delX(self):
del self._x
x = MyProperty(getX, setX, delX)
>>> c = C()
>>> c.x = 'x-man'
>>> c.x
'x-man'
>>> c._x
'x-man'
>>>
这样就自己实现了一个property函数了
046魔法方法:描述符(Property的原理)(下)
本帖最后由 摆渡终极鉴黄师 于 2017-10-24 17:21 编辑class Celsius:
def __init__(self, value = 26.0):
self.value = float(value)
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)
class Fahrenheit:
def __get__(self, instance, owner):
return instance.cel * 1.8 + 32
def __set__(self, instance, value):
instance.cel = (float(value) - 32) / 1.8
class Temperature:
cel = Celsius()
fah = Fahrenheit()#(笔记传送门——001,传送成功!)也就是在这里出现赋值了,fah这个属性有一个描述符类方法 Fahrenheit(),也就是说,Fahrenheit()这个描述符类,是描述这个fah属性的,当这个属性被赋值的时候,就会执行这个描述符类Fahrenheit的set方法,Ta事实上呢就是执行这个temp.cel(instance.cel)的等于号后面的那个计算后的值,然后存放到temp.cel里,temp.cel呢也是对这个temp的实例对象的cel属性进行赋值(也就是cel = Celsius()),Ta也有一个描述符类(也就是Celsius()),然后Ta就会执行到set里面去(Ceisius类里的set),最后设置到self.value里边去
>>> temp = Temperature() # 实例化对象
>>> temp.cel # 这是默认的,没有设置过的,如果你设置的话↓
26.0
>>> temp = Temperature(30) # 这个类不行,这个类我们没有写Ta的init方法,init是在这个cel里边的,我们要设置的话呢要通过cel
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
temp = Temperature(30)
TypeError: object() takes no parameters
>>> temp.cel = 30 # 设置华氏度为30
>>> temp.fah
86.0 # 30*1.8+32 = 86度
>>> temp.fah = 100 # 现在设置华氏度为100,这个temp.fah = 100,也就是给Ta赋值(笔记传送门——001,开始传送中。。。。)
>>> temp.cel
37.77777777777778
>>>
047魔法方法:定制序列(上)
本帖最后由 摆渡终极鉴黄师 于 2017-10-25 18:31 编辑协议是什么?
·协议(Protocols)与其他编程语言中的接口很相似,Ta规定你那些方法必须要定义。然而,在Python中的协议就显得不那么正式。事实上,在Python中,协议更像是一种指南。
047魔法方法:定制序列(中)
本帖最后由 摆渡终极鉴黄师 于 2017-10-26 18:55 编辑·如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法。
·如果你希望定制的容器是可变的话,出了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法
047魔法方法:定制序列(中2)
本帖最后由 摆渡终极鉴黄师 于 2017-10-28 01:58 编辑上下文管理(with语句)
__enter__(self) 1.定义当使用with语句时的初始化行为
2.__enter__的返回值被with语句的目标或者as后的名字绑定
__exit__(self, exc_type,exc_value,traceback) 1.定义当一个代码被执行或者终之后上下文管理器应该做什么
2.一般被用来处理异常,清楚工作或者做一些代码块执行完毕之后的日常工作。
047魔法方法:定制序列(中3)
本帖最后由 摆渡终极鉴黄师 于 2017-10-29 12:15 编辑容器类型
__len__(self) 定义当使用with语句时的初始化行为(返回容器中元素的个数)
__getitem__(self,key)定义获取容器中指定元素的行为,相当于self
__setitem__(self, key, value)定义设置容器中指定元素的行为,相当于self = value
__delitem__(self, key, value)定义删除容器中指定元素的行为,相当于 del self
__iter__(self) 定义当迭代容器中的元素的行为
__reversed__(self) 定义当被reversed()调用时的行为
__contains__(self, item)定义当使用成员测试运算符(in 或 not in)时的行为
本帖最后由 摆渡终极鉴黄师 于 2017-10-30 16:10 编辑
__len__(self)
返回容器的长度。可变和不可变容器都要实现它,这是协议的一部分
__getitem__(self, key)
定义当某一项被访问时,使用self所产生的行为。这也是可变容器和不可变容器协议的一部分。如果键的类型错误将产生TypeError;如果key没有合适的值则产生KeyError
__setitem__(self, key, value)
定义当一个条目被赋值时,使用self = value所产生的行为。这也是可变容器协议的一部分。而且,在相应的情形下也会产生KeyError和TypeError
__delitem__(self, key)
定义当某一项被删除时所产生的行为。(例如del self)。这是可变容器协议的一部分。当你使用一个无效的键时必须抛出适当的异常。
__iter__(self)
返回一个迭代器,尤其是当内置的iter()方法被调用的时候,以及当使用for x in container:方式进行循环的时候。
迭代器要求实现next方法(python3.x中改为__next__),并且每次调用这个next方法的时候都能获得下一个元素,元素用尽时触发 StopIteration 异常。
而其实 for 循环的本质就是先调用对象的__iter__方法,再不断重复调用__iter__方法返回的对象的 next 方法,触发 StopIteration 异常时停止,并内部处理了这个异常,所以我们看不到异常的抛出。
这种关系就好像接口一样,如果回顾以前几篇的魔法方法,可以发现许多的内置函数得到的结果就是相应的魔法方法的返回值。
可迭代对象:对象实现了一个__iter__方法,这个方法负责返回一个迭代器。
迭代器:内部实现了next(python3.x为__next__)方法,真正负责迭代的实现。当迭代器内的元素用尽之后,任何的进一步调用都之后触发
StopIteration 异常,所以迭代器需要一个__iter__方
法来返回自身。所以大多数的迭代器本身就是可迭代对象。这使两者的差距进一步减少。
但是两者还是不同的,如果一个函数要求一个可迭代对象(iterable),而你传的迭代器(iterator)并没有实现__iter__方法,那么可能会出现错误。
不过一般会在一个类里同时实现这两种方法(即是可迭代对象又是迭代器),此时__iter__方法只要返回self就足够的了。当然也可以返回其它迭代器。
__reversed__(self)
实现当reversed()被调用时的行为。应该返回序列反转后的版本。仅当序列是有序的时候实现它,例如列表或者元组
__contains__(self, item)
定义了调用in和not in来测试成员是否存在的时候所产生的行为。这个不是协议要求的内容,但是你可以根据自己的要求实现它。当__contains__没有被定义的时候,Python会迭代这个序列,并且当找到需要的值时会返回True
(从网上拷贝的一份感觉很有质量的笔记) 本帖最后由 摆渡终极鉴黄师 于 2017-10-31 23:31 编辑
__missing__(self, key)
其在dict的子类中被使用。它定义了当一个不存在字典中的键被访问时所产生的行为。(例如,如果我有一个字典d,当"george"不是字典中的key时,使用了d["george"],此时d.__missing__("george")将会被调用)
047魔法方法:定制序列(下)
本帖最后由 摆渡终极鉴黄师 于 2017-11-1 17:19 编辑class CountList: #把一个类定义成为一个容器
def __init__(self, *args): #Ta的这个参数*args参数是可变类型的,可变数量的,初始化一下
self.values = #把用户传进去的这一堆数据把Ta放到这个列表里边,通过这个列表推导式的形式,把Ta存放进这个values推导式的里边
self.count = {}.fromkeys(range(len(self.values)), 0) #初始化用fromkeys就可以了,加一个内部方法,这里是使用Ta的下标而不是使用Ta的元素,然后全部初始化为0,刚开始是没有访问的
def __len__(self): #这是一个不可变的一个容器,所以要定义一个len和一个getitem
return len(self.values) #len的话是直接返回len(self.values)的值
def __getitem__(self, key): #这个key是Ta的相应的下标
self.count += 1 #这里要获取Ta的值,就会访问Ta一次。这里的self.count Ta对应的key就要+=1。获取Ta的值,就会访问Ta一次
return self.values
048魔法方法:迭代器(上)
本帖最后由 摆渡终极鉴黄师 于 2017-11-2 13:33 编辑迭代的意思呢就类似于循环——每一次重复的过程被称之为一次迭代的过程,而每一次迭代得到的结果将会被用来作为下一次迭代的初始值,提供迭代方法的容器我们称之为迭代器。
048魔法方法:迭代器(中)
本帖最后由 摆渡终极鉴黄师 于 2017-11-3 06:53 编辑>>> for i in "Kuang3": #字符串就是一个容器,同时也是一个迭代器
print(i)
K
u
a
n
g
3
048魔法方法:迭代器(下)
本帖最后由 摆渡终极鉴黄师 于 2017-11-4 15:55 编辑内置函数iter()仅仅是调用了对象的__iter()方法,所以list对象内部一定存在方法iter__()
内置函数next()仅仅是调用了对象的__next()方法,所以list对象内部一定不存在方法next__(),但是Itrator中一定存在这个方法。
for循环内部事实上就是先调用iter()把Iterable变成Iterator在进行循环迭代的。
049乱入:生成器(上)
本帖最后由 摆渡终极鉴黄师 于 2017-11-5 14:46 编辑所谓协同程序就是可以运行的独立函数调用,函数可以暂停或挂起,并在需要的时候从程序离开的地方继续或者重新开始。
049乱入:生成器(中)
本帖最后由 摆渡终极鉴黄师 于 2017-11-6 17:23 编辑>>> def myGen():
print("生成器被执行!")
yield 1 # 一但函数中出现yield语句,那么这个函数就被定义为了一个生成器,相当于return语句,但是普通函数return返回,那么这个函数就结束,但是对于生成器来说,出现yield,Ta就会把yield右边的这个参数给返回去,然后就会暂停在这里
yield 2
>>> myG = myGen()
>>> next(myG)
生成器被执行!
1
>>> next(myG)
2 # 2就打印出来了,上边没有打印
>>>
049乱入:生成器(中2)
本帖最后由 摆渡终极鉴黄师 于 2017-11-7 17:00 编辑>>> def myGen():
print("生成器被执行")
yield 1
yield 2
>>> myG = myGen()
>>> for i in myGen():
print(i)
生成器被执行
1
2
>>> def libs():
a = 0
b = 1
while True:
a, b = b, a + b
yield a
>>> for each in libs(): # 没有元素的时候会跳出StopIteration,python的for循环会自动调用next方法和探测StopIteration,结束
if each > 100:
break
print(each, end=' ')
1 1 2 3 5 8 13 21 34 55 89
>>>
049乱入:生成器(下)
本帖最后由 摆渡终极鉴黄师 于 2017-11-8 17:55 编辑>>> e = (i for i in range(10))
>>> e
<generator object <genexpr> at 0x0000000002EC4FC0> # 不是元祖(tuple)推导式,居然是生成器(generator)推导式,圆括号括起来的那个就是生成器推导式,生成器就是迭代器
>>> next(e)
0
>>> next(e)
1
>>> next(e)
2
>>> for each in e:
print(each)
3
4
5
6
7
8
9
>>>
生成器推导式,如果作为函数的参数,可以直接写这个推导式就可以了,不用加圆括号,例如:
>>> sum(i for i in range(100) if i % 2)
2500
>>> sum((i for i in range(100) if i % 2))
2500
>>>
050模块:模块就是程序(上)
本帖最后由 摆渡终极鉴黄师 于 2017-11-9 08:13 编辑模块——>更高级的封装
·容器->数据的封装
·函数->语句的封装
·类->方法和属性的封装
·模块->模块就是程序