p33~p52

p33 032 异常处理:你不可能总是对的

实例1:

file_name = input(‘请输入需要打开的文件名:’)
file = open(file_name)
print(‘文件的内容是:’)
for each_line in file:
print(each_line)
file.close()
在这里插入图片描述
在这里插入图片描述

注:py文件与要打开的文件在同一个文件下则不需要加路径

Python标准异常总结

以下是 Python 内置异常类的层次结构:
在这里插入图片描述

033 异常处理:你不可能总是对的2

try-except语句

try:
f = open(‘TE.txt’)
print(f.read())
f.close()
except OSError:
print(‘文件打开过程中出错了!!!’)
检测范围

except Exception[as reason]:

出现异常(Exception)后的处理代码

实例1:

try:
f = open(‘TE.txt’)
print(f.read())
f.close()
except OSError:
print(‘文件打开过程中出错了!!!’)
在这里插入图片描述
实例2:

try:
f = open(‘TE.txt’)
print(f.read())
f.close()
except OSError as reason:
print(‘文件打开出错原因是:\n’ + str(reason))

在这里插入图片描述
实例3:

try:
sum = 1 + ‘1’
f = open(‘TE.txt’)
print(f.read())
f.close()
except OSError as reason:
print(‘文件打开出错原因是:\n’ + str(reason))
except TypeError as reason:
print(‘类型出错原因是:\n’ + str(reason))

在这里插入图片描述
实例4(多个异常统一处理):

try:
sum = 1 + ‘1’
f = open(‘TE.txt’)
print(f.read())
f.close()
except(OSError, TypeError):
print(‘出错了’)
注:try语句一旦检测到异常,剩下的语句将不会被执行

try-finally语句

try:

检测范围

except Exception[as reason]:

出现异常(Exception)后的处理代码

finally:

无论如何都会被执行的代码

实例5:

try:
f = open(‘test.txt’)
print(f.read())
sum = 1 + ‘1’
except (OSError,TypeError)as reason:
print(‘出错了\n原因是:’ + str(reason))
finally:
f.close()
在这里插入图片描述

raise语句可以自己抛出一个异常
在这里插入图片描述

034 丰富的else语句及简洁的with语句

丰富的else语句

•要么怎样,要么不怎样

if 条件:
条件为真执行
else:
条件为假执行

•干完了能怎样,干不完就别想怎样

实例1:

def showMaxFactor(num):
count = num // 2#//为整除,判断是素数,只需依次判断当前数num除以1到(num // 2)都不能整除即可
while count > 1:
if num % count == 0:#判断是否整除
print(’%d最大的约数是%d’ % (num, count))
break#跳出循环后else并不执行
count -= 1
else:#当while循环不成立时,或者理解为while循环完全被执行完了,没有给中途跳出(即break)
print(’%d是素数!’ % num)

num = int(input(‘请输入一个数:’))
showMaxFactor(num)

注:else与for语句搭配与while语句相同
在这里插入图片描述

没有问题?那就干

只要try语句块里没有出现任何异常,那么就会执行else语句块里的内容啦

实例2:

try:#尝试运行以下程序
print(int(‘abc’))
except ValueError as reason:#如果程序有异常时
print(‘出错了:’ + str(reason))
else:#程序无异常时
print(‘没有任何异常!’)
在这里插入图片描述

实例3:

try:
print(int(‘123’))
except ValueError as reason:
print(‘出错了:’ + str(reason))
else:
print(‘没有任何异常!’)

简洁的with语句(with会自动帮你关闭文件)

实例4:

try:
with open(‘test.txt’,‘w’) as f:
for each_line in f:
print(each_line)
except (OSError,TypeError) as reason:
print(‘出错了\n原因是:’ + str(reason))

035 图形用户界面入门:EasyGui

图形用户界面编程,也就是平时常说的GUI(Graphical User Interface),python有一个非常简单的GUI工具包:EasyGui

GUI的安装
在这里插入图片描述在这里插入图片描述

导入方法一:

import easygui #导入EasyGui
easygui.msgbox(‘嗨,亦我飞也’)
在这里插入图片描述

导入方法二:

from easygui import *
msgbox(‘嗨,亦我飞也’)
在这里插入图片描述

导入方法三(推荐使用):

import easygui as g
g.msgbox(‘嗨,亦我飞也’)
在这里插入图片描述

easygui.buttonbox(msg=‘你喜欢以下哪种水果’,title=‘亦我飞也’,choices=(‘草莓’,‘西瓜’,‘芒果’),image=‘aa.gif’)

实例1:

import easygui as g
import sys

while 1:
g.msgbox(“嗨,欢迎进入第一个界面小游戏”)
msg = “请问你希望在鱼C工作室学习到什么知识呢”
title=“小游戏互动”
choices=[“谈恋爱”,“编程”,“OOXX”,“琴棋书画”]
choice=g.choicebox(msg,title,choices)

#note that we convert choice to string,in case
#the user cancelled the choice,and we got None
g.msgbox("你的选择是:"+str(choice),"结果")
msg="你希望重新开始小游戏吗?"
title=" 请选择"
if g.ccbox(msg,title):  #show a Contiue/Cancel dialog
    pass #user chose Contonue
else:
    sys.exit(0)  #user chose Cancel

修改窗口大小(choicebox)

修改文字大小(PROPORTIONAL_FONT)

036 类和对象:给大家介绍对象

给大家介绍对象

把乱七八糟的数据扔进列表里,称数据层面的封装

把常用的代码段打包成一个函数,称语句层面的封装

把数据和代码都封装在一起,称对象层面的封装
在这里插入图片描述

对象 = 属性 + 方法

对象可以从静态(属性)与动态(方法)两个特征来描述
在这里插入图片描述

OO(面向对象)的特征

继承

class Turtle: # Python 中的类名约定以大写字母开头
“”“关于类的一个简单例子”""
# 属性
color = ‘green’
weight = 10
legs = 4
shell = True
mouth = ‘大嘴’

# 方法
def climb(self):
    print("我正在很努力的向前爬......")

def run(self):
    print("我正在飞快的向前跑......")

def bite(self):
    print("咬死你咬死你!!")

def eat(self):
    print("有得吃,真满足^_^")

def sleep(self):
    print("困了,睡了,晚安,Zzzz")

调用类中的方法:

tt = Turtle() #声明tt对象继承Turtle()
tt.climb()
我正在很努力的向前爬…

tt.bite()
咬死你咬死你!!

定义一个带列表类MyList,将list2对象继承于它,则列表的功能继承它的对象都可以使用

class MyList(list):
pass

list2 = MyList()

list2.append(5)
list2.append(6)

list2.append(1)
list2
[5, 6, 1]

list2.sort()
list2
[1, 5, 6]

多态(下例中都调用的名字相同的方法,但实现不一样)

class A:
def fun(self):
print(‘我是小A。。。’)

class B:
def fun(self):
print(‘我是小B。。。’)

a = A()
b = B()
a.fun()
我是小A。。。

b.fun()
我是小B。。。

037 类和对象:面向对象编程

self是什么?

Python的self其实就相当于C++的this指针。由同一个类可以生产无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了。

class Ball:
def setName(self,name):
self.name = name
def kick(self):
print(‘我叫%s,该死的,谁踢我。。。’ % self.name)

a = Ball()

a.setName(‘球A’)
b = Ball()

b.setName(‘球B’)

a.kick()
我叫球A,该死的,谁踢我。。。

b.kick()
我叫球B,该死的,谁踢我。。。

你听说过Python的魔法方法吗?

python的这些具有魔法的方法,总是被双下划线所包围,例如__init__(),即构造方法,也称构造函数,这个方法会在对象被创建时自动调用。其实,实例化对象时是可以传入参数的,这些参数会自动传入__init__()方法中,可以通过重写这个方法来自定义对象的初始化操作

实例:

class Ball():
def init(self,name):
self.name = name
def kick(self):
print(‘我叫%s,该死的,谁踢我。。。’ % self.name)

b = Ball(‘小土豆’)
b.kick()
我叫小土豆,该死的,谁踢我。。。

公有和私有?python内部采用了一种叫 name mangling(名字改编)的技术

默认上对象的属性和方法都是公开的,可以直接通过点操作符(.)进行访问:

class Person:
name = ‘亦我飞也’

p = Person()
p.name
‘亦我飞也’

为了实现定义私有变量,只需要在变量名或函数名前加上"__"两个下划线,那么这个函数或变量就会变成私有的了:

私有变量不可以直接由外部访问

class Person:
__name = ‘亦我飞也’

p = Person()
p.__name
Traceback (most recent call last):
File “<pyshell#65>”, line 1, in
p.__name
AttributeError: ‘Person’ object has no attribute ‘__name’

室友变量可以由内部(内部函数)进行访问

class Person:
__name = ‘亦我飞也’
def getName(self):
return self.__name

p = Person()
p.__name
Traceback (most recent call last):
File “<pyshell#72>”, line 1, in
p.__name
AttributeError: ‘Person’ object has no attribute ‘__name’

p.getName()
‘亦我飞也’

其实,name mangling(名字改编)技术,只是把双下划线开头的变量进行了改名而已。实际上在外部使用“_类名__变量名“即可访问双下划线开头的私有变量了:

p._Person__name
‘亦我飞也’

038 类和对象:继承

继承

              子类                              父类

class DerivedClassName(BaseClassName):

……

实例:一个子类可以继承它的父类的所有属性和方法

class Parent:
def hello(self):
print(‘正在调用父类的方法。。。’)

class Child(Parent): #子类继承父类
pass #直接往下执行

p = Parent()
p.hello()
正在调用父类的方法。。。

c = Child()
c.hello()
正在调用父类的方法。。。

如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法和属性(即子类方法属性改变,父类是不变的)

class Child(Parent):
def hello(self):
print(‘正在调用子类的方法’)

c = Child()
c.hello()
正在调用子类的方法

p.hello()
正在调用父类的方法。。。

实例2:

import random as r
class Fish:
def init(self):
self.x = r.randint(0,10)
self.y = r.randint(0,10)

def move(self):
    self.x -= 1
    print('我的位置是:',self.x,self.y)

class Goldfish(Fish):
pass

class Garp(Fish):
pass

class Shark(Fish):
def init(self):
self.hungry = True

def eat(self):
    if self.hungry:
        print('吃货的梦想就是天天有的吃')
        self.hungry = False
    else:
        print('太撑了,吃不下了!')

fish = Fish()
fish.move()
我的位置是: -1 10

fish.move()
我的位置是: -2 10

goldfish = Goldfish()
goldfish.move()
我的位置是: 2 3

goldfish.move()
我的位置是: 1 3

shark = Shark()
shark.eat()
吃货的梦想就是天天有的吃

shark.eat()
太撑了,吃不下了!

shark.move() #报错原因时因为子类重写构造函数,覆盖了父类D的构造函数
Traceback (most recent call last):
File “<pyshell#9>”, line 1, in
shark.move()
File “D:\python3.3.2\小甲鱼python\python程序\第三十八节课\fish.py”, line 8, in move
self.x -= 1
AttributeError: ‘Shark’ object has no attribute ‘x’

注:继承父类属性的子类,其变量值只属于当前子类,是子类的局部变量
在这里插入图片描述

报错修改部分解决方法一:调用未绑定的父类方法
在这里插入图片描述

shark = Shark()
shark.move()
我的位置是: 2 1

shark.move()
我的位置是: 1 1

报错修改部分解决方法二:使用super函数(super函数会帮我们自动找到基类的方法,而且还自动为我们传入self参数)
在这里插入图片描述

shark = Shark()
shark.move()
我的位置是: 1 1

shark.move()
我的位置是: 0 1

多重继承

class DerivedClassName(Base1, Base2, Base3):

……

实例:子类c同时继承基类Base1和基类Base2

class Base1:
def fool1(self):
print(‘我是fool1,我为Base1代言。。。’)

class Base2:
def fool2(self):
print(‘我是fool2,我为Base2代言。。。’)

class C(Base1,Base2):
pass

c = C()
c.fool1()
我是fool1,我为Base1代言。。。

c.fool2()
我是fool2,我为Base2代言。。。

039 类和对象:拾遗

组合(将需要的类一起进行实例化并放入新的类中)

实例:

class Turtle:
def init(self,x):
self.num = x

class Fish:
def init(self,x):
self.num = x

class Pool:
def init(self,x,y):
self.turtle = Turtle(x)
self.fish = Fish(y)

def print_num(self):
    print('水池里一共有乌龟 %d 条,鱼 %d 条' % (self.turtle.num,self.fish.num))

pool = Pool(5,2)
pool.print_num()
水池里一共有乌龟 5 条,鱼 2 条

•现在要求定义一个类,叫水池,水池里要有乌龟和鱼。

类、类对象和实例对象
在这里插入图片描述

以下例子可见,对实例对象c的count属性赋值后,就相当于覆盖了类对象C的count属性。如果没有赋值覆盖,那么引用的是类对象的count属性

a = C()
b = C()
c = C()
print(a.count,b.count,c.count)
0 0 0

c.count += 10
print(a.count,b.count,c.count)
0 0 10

C.count += 100
print(a.count,b.count,c.count)
100 100 10

另外,如果属性的名字跟方法名相同,属性会覆盖方法:

class C:
def x(self):
print(‘X-man’)

c = C()
c.x()
X-man

c.x = 1 #新定义对象c的一个x属性,并赋值为1
c.x
1

c.x() #可见,方法x()已经被属性x给覆盖了
Traceback (most recent call last):
File “<pyshell#8>”, line 1, in
c.x()
TypeError: ‘int’ object is not callable

结论:不要试图在一个类里边定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展;用不同的词性命名,如属性名用名词、方法名用动词,并使用骆驼命名法等。

到底什么是绑定?

实例1:(python严格要求需要有实例才能被调用,即绑定概念)

class BB:
def printBB(): #缺少self,导致无法绑定具体对象
print(‘no zuo no die’)

BB.printBB()
no zuo no die

bb = BB()
bb.printBB() #出现错误原因是由于绑定机制,自动把bb对象作为第一个参数传入
Traceback (most recent call last):
File “<pyshell#15>”, line 1, in
bb.printBB()
TypeError: printBB() takes 0 positional arguments but 1 was given

•Python严格要求方法需要有实例才能被调用,这种限制其实就是Python所谓的绑定概念。

040 类和对象:一些相关的BIF

一些相关的BIF

issubclass(class, classinfo) 如果第一个参数(class)是第二个参数(classinfo)的一个子类,则返回True,否则返回False

class A:
pass

class B(A):
pass

issubclass(B,A)
True

issubclass(B,B) #一个类被认为是其自身的子类
True

issubclass(B,object) # object是所有类的基类
True

class C:
pass

issubclass(B,C)
False

isinstance(object, classinfo) 如果第一个参数(object)是第二个参数(classinfo)的实例对象,则返回True,否则返回False

issubclass(B,C) 注:第一个参数如果不是对象,则永远返回False
False

b1 = B()
isinstance(b1,B)
True

isinstance(b1,C)
False

isinstance(b1,A)
True

isinstance(b1,(A,B,C))
True

hasattr(object, name) 用来测试一个对象里是否有指定的属性,第一个参数(object)是对象,第二个参数(name)是属性名(属性的字符串名字)

class C:
def init(self,x=0):
self.x = x

c1 = C()
hasattr(c1,‘x’) #注意,属性名要用引号括起来
True

getattr(object, name[, default]) 返回对象指定的属性值,如果指定的属性不存在,则返回default(可选参数);若没有设置default参数,则抛出异常

getattr(c1,‘x’)
0

getattr(c1,‘y’)
Traceback (most recent call last):
File “<pyshell#25>”, line 1, in
getattr(c1,‘y’)
AttributeError: ‘C’ object has no attribute ‘y’

setattr(object, name, value) 可以设置对象中指定属性的值,如果指定的属性不存在,则会新建属性并赋值

setattr(c1,‘y’,‘FishC’)
getattr(c1,‘y’)
‘FishC’

delattr(object, name) 用于删除对象中指定的属性,如果属性不存在,抛出异常。

delattr(c1,‘y’)
delattr(c1,‘Z’)
Traceback (most recent call last):
File “<pyshell#30>”, line 1, in
delattr(c1,‘Z’)
AttributeError: Z

property(fget=None, fset=None, fdel=None, doc=None) 用来通过属性设置属性,第一个参数是获取属性的方法名,第二个参数是设置属性的方法名,第三个参数是删除属性的方法名

class C:
def init(self,size =10):
self.size = size
def getSize(self):
return self.size
def setSize(self,value):
self.size = value
def delSize(self):
del self.size
x=property(getSize,setSize,delSize)

c = C()
c.x #调用getSize()
10

c.x = 12 #调用SetSize()
c.x
12

c.size
12

del c.x #调用DelSize()
c.size
Traceback (most recent call last):
File “<pyshell#53>”, line 1, in
c.size
AttributeError: ‘C’ object has no attribute ‘size’

041 魔法方法:构造和析构
在这里插入图片描述

init(self[, …]) 方法是类在实例化成对象的时候首先会调用的一个方法

class Rectangle:
def init(self,x,y):
self.x = x
self.y = y
def getPeri(self):
return (self.x + self.y) * 2
def getArea(self):
return self.x * self.y

rect = Rectangle(5,2)
rect.getPeri()
14

rect.getArea()
10

注:init()方法的返回值一定是None

其实,new()才是在一个对象实例化时候所调用的第一个方法,它的第一个参数是这个类(cla),而其他的参数会直接传递给__init__()方法

new(cls[, …])

class CapStr(str):
def new(cls,string):
string = string.upper()
return str.new(cls,string)

a = CapStr(‘hello world’)
a
'HELLO WORLD

del(self) 当对象将要被销毁的时候,这个方法就会被调用。但要注意,并非del x就相当于调用x.del(),del()方法是当垃圾回收机制回收这个对象的时候才调用的。

class C:
def init(self):
print(‘我是__init__方法,我被调用了…’)
def del(self):
print(‘我是__del__方法,我被调用l…’)

c1 = C() #创建对象c1
我是__init__方法,我被调用了…

c2 = c1
c3 = c2
del c1
del c2
del c3 #删除c3时,对象c1才会彻底被删除(即没有标签指向对象c1时,其才会被回收)
我是__del__方法,我被调用l…

042 魔法方法:算术运算

python2.2以后,对类和类型进行了统一,做法就是讲int()、float()、str()、list()、tuple()这些BIF转换为工厂函数(类对象):

type(len)
<class ‘builtin_function_or_method’> #普通的BIF

type(int)
<class ‘type’> #工厂函数(类对象),当调用它们的时候,其实就是创建了一个相应的实例对象

type(dir)
<class ‘builtin_function_or_method’>

type(list)
<class ‘type’>

a = int(‘123’) #创建一个相应的实例对象a
b = int(‘345’)
a + b #python在两个对象进行相加操作
468
在这里插入图片描述

举个例子,下面定义一个比较特立独行的类:

class New_int(int):
def add(self,other):
return int.sub(self,other)
def sub(self,other):
return int.add(self,other)

a = New_int(3)
b = New_int(5)
a + b #两个对象相加,触发 add(self,other)方法
-2

a - b
8

实例2:

class New_int(int):
def add(self,other):
return (int(self) + int(other)) #将self与other强制转换为整型,所以不会出现两个对象相加触发__add__()方法
def sub(self,other):
return (int(self) - int(other))

a = New_int(3)
b = New_int(5)
a + b
8

043 魔法方法:算术运算2

实例1:

class int(int):
def add(self,other):
return int.sub(self,other)

a = int(3)
b = int(2)
a + b
1

反运算:
在这里插入图片描述

反运算与算术运算符的不同之处是,反运算多了一个’r’,例如 add()的反运算对应为 radd()

a + b

这里a是加数,b是被加数,如果a对象的__add__()方法没有实现或者不支持相应的操作,那么python就会自动调用b的__radd__()方法

实例:

class Nint(int):
def radd(self,other):
return int.sub(self,other)

a = Nint(5)
b = Nint(3)
a + b #由于a对象默认有__add__()方法,所以b的__radd__()没有执行
8

实例2:

class Nint(int):
def radd(self,other):
return int.sub(self,other)

b = Nint(5)
3 + b #由于3无__add__()方法,所以执行b的反运算__radd__(self,other)方法,其中self是b对象
2

注:在重写反运算魔法方法时,一定要注意顺序问题。

增量赋值运算:
在这里插入图片描述

比较操作符:
在这里插入图片描述

其它操作符:
在这里插入图片描述

044 魔法方法:简单定制

简单定制

•基本要求:

–定制一个计时器的类

–start和stop方法代表启动计时和停止计时

–假设计时器对象t1,print(t1)和直接调用t1均显示结果

–当计时器未启动或已经停止计时,调用stop方法会给予温馨的提示

–两个计时器对象可以进行相加:t1 + t2

–只能使用提供的有限资源完成

你需要这些资源

•使用time模块的localtime方法获取时间

–扩展阅读:time 模块详解(时间获取和转换)

有关time模块的localtime方法获取时间(参考:

https://fishc.com.cn/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403)

•time.localtime返回struct_time的时间格式

•表现你的类:strrepr

实例:

import time as t #导入时间模块,调用对象t

class Mytimer():
def init(self):
self.unit = [‘年’,‘月’,‘天’,‘小时’,‘分钟’,‘秒’]
self.prompt = “未开始计时”
self.lasted = []
self.begin = 0 #属性
self.end = 0
def str(self):
return self.prompt

__repr__ = __str__

def __add__(self,other):   #重写加法操作符,运行时间相加
    prompt = "总共运行了"
    result = []
    for index in range(6):
        result.append(self.lasted[index] + other.lasted[index])
        if result[index]:
            prompt += (str(result[index]) + self.unit[index])
    return prompt
                       
#开始计时
def start(self):    #方法,属性名和方法名不能相同
    if not self.stop:
        self.prompt = ("提示:请先调用stop()停止计时!")
    else:
        self.begin = t.localtime()
        print('计时开始...')

#停止计时
def stop(self):
    if not self.begin:
        print('提示:请先调用start()进行计时!')
    else:
        self.end = t.localtime()
        self._calc()
        print('计时结束!')

#内部方法,计算运行时间
def _calc(self):
    self.prompt = "总共运行了"
    for index in range(6):
        self.lasted.append(self.end[index] - self.begin[index])
        if self.lasted[index]:
            self.prompt += (str(self.lasted[index]) + self.unit[index])
    #为下一轮计时初始化变量
    self.begin = 0
    self.end = 0

t1 = Mytimer()
t1.stop()
提示:请先调用start()进行计时!

t1.start()
计时开始…

t1.stop()
计时结束!

t1
总共运行了4秒

t2 = Mytimer()
t2.start()
计时开始…

t2.stop()
计时结束!

t2
总共运行了4秒

t1 + t2
‘总共运行了8秒’

进阶定制

•如果开始计时的时间是(2022年2月22日16:30:30),停止时间是(2025年1月23日15:30:30),那按照我们用停止时间减开始时间的计算方式就会出现负数(3年-1月1天-1小时),你应该对此做一些转换。

•现在的计算机速度都非常快,而我们这个程序最小的计算单位却只是秒,精度是远远不够的。

045 魔法方法:属性访问

属性访问

getattr(self, name)

–定义当用户试图获取一个不存在的属性时的行为

getattribute(self, name)

–定义当该类的属性被访问时的行为

setattr(self, name, value)

–定义当一个属性被设置时的行为

delattr(self, name)

–定义当一个属性被删除时的行为

实例1:

class C:
def getattribute(self, name):
print(‘getattribute’)
# 使用 super() 调用 object 基类的 getattribute 方法
return super().getattribute(name)

def __setattr__(self, name, value):
    print('setattr')
    super().__setattr__(name, value)

def __delattr__(self, name):
    print('delattr')
    super().__delattr__(name)

def __getattr__(self, name):
    print('getattr')

c = C()
c.x
getattribute
getattr

c.x = 1
setattr

c.x
getattribute
1

del c.x
delattr

setattr(c,‘y’,‘Yellow’)
setattr

练习要求

•写一个矩形类,默认有宽和高两个属性;

•如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

实例2:

class Rectangle:
def init(self, width=0, height=0):
self.width = width
self.height = height

def __setattr__(self, name, value):#一发生赋值操作,则会触发__setattr__()魔法方法
    if name == 'square':#判断name属性是否为正方形
        self.width = value
        self.height = value
    else:
        self.__dict__[name] = value

def getArea(self):
    return self.width * self.height

r1 = Rectangle(4,5)
r1.getArea()
20

r1.square = 10
r1.getArea()
100

046 魔法方法:描述符(Property的原理)

描述符

•描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

get(self, instance, owner)

–用于访问属性,它返回属性的值

set(self, instance, value)

–将在属性分配操作中调用,不返回任何内容

delete(self, instance)

–控制删除操作,不返回任何内容

实例 1:

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() #取Mydecriptor类的实例指派给Test类的属性x

test = Test()
test.x
getting… <main.MyDecriptor object at 0x00000000033467F0> <main.Test object at 0x000000000335EF98> <class ‘main.Test’>

test
<main.Test object at 0x000000000335EF98>

test.x = “X-man”
setting… <main.MyDecriptor object at 0x00000000033467F0> <main.Test object at 0x000000000335EF98> X-man

del test.x
deleting… <main.MyDecriptor object at 0x00000000033467F0> <main.Test object at 0x000000000335EF98>

实例2:

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 = “HELLOW”
c.x
‘HELLOW’

c._x
‘HELLOW’

del c.x
c._x
Traceback (most recent call last):
File “<pyshell#70>”, line 1, in
c._x
AttributeError: ‘C’ object has no attribute ‘_x’

练习要求

•先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。

•要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。

实例3:

ss Celsius: #摄氏度描述符类
def init(self,value = 26.0):#self为描述符类自身(此为摄氏度描述符类)的实例(此为cel)
self.value = float(value)
def get(self,instance,owner):#instance是这个描述符的拥有者所在的类的实例(此为temp)
return self.value
def set(self,instance,value):#owner是这个描述符的拥有者所在的类本身(此为温度类)
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()#设置华氏度属性

temp = Temperature()
temp.cel
26.0

temp.fah
78.80000000000001

temp.fah = 78.8
temp.cel
25.999999999999996

047 魔法方法:定制序列

协议是什么?

•协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在Python中的协议就显得不那么正式。事实上,在Python中,协议更像是一种指南。

容器类型的协议

•如果说你希望定制的容器是不可变的话,你只需要定义__len__()和__getitem__()方法。

•如果你希望定制的容器是可变的话,除了__len__()和__getitem__()方法,你还需要定义__setitem__()和__delitem__()两个方法。

练习要求

•编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。

class CountList: #定义记录列表中每个元素访问次数类
def init(self,*args): #参数是可变类型的
self.values = [x for x in args]#将args的数据存入列表self.values中
self.count = {}.fromkeys(range(len(self.values)),0)#创建字典,初试化为0

def __len__(self):  #返回容器中元素的个数
    return len(self.values)#len方法用于返回参数的长度 
def __getitem__(self,key):  #获取容器中指定元素的行为,key为访问对应的键
    self.count[key] += 1#每访问一次,字典键对应的键值加1
    return self.values[key]

c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)
c1[1] #c1[1]第一次访问
3

c2[2]
6

c1[1] + c2[2] #c1[1]第二次访问
9

c1.count
{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}

c2.count
{0: 0, 1: 0, 2: 2, 3: 0, 4: 0}

048 魔法方法:迭代器

迭代的意思类似于循环,每一次重复的过程被称为一次迭代的过程,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。提供迭代方法的容器称为迭代器(如序列(列表、元组、字符串)、字典等)。

对一个容器对象调用iter()就得到它的迭代器,调用next()迭代器就会返回下一个值。入托迭代器没有值可以返回了,就会抛出异常。

•iter()

iter()

•next()

next()

实例1:

string = “FishC”
it = iter(string)
next(it)
‘F’

next(it)
‘i’

next(it)
‘s’

next(it)
‘h’

next(it)
‘C’

next(it)
Traceback (most recent call last):
File “<pyshell#8>”, line 1, in
next(it)
StopIteration

一个容器如果是迭代器,那就必须实现__iter__()魔法方法,这个方法实际上就是返回迭代器本身。重点要实现的是__next__()魔法方法,因为它决定了迭代的规则。

实例2:

class Fibs:
def init(self):
self.a = 0
self.b = 1
def iter(self):
return self
def next(self):
self.a,self.b = self.b,self.a + self.b
return self.a

fibs = Fibs()
for each in fibs:
if each < 20:
print(each)
else:
break

1
1
2
3
5
8
13

实例3:

class Fibs:
def init(self,n =20):
self.a = 0
self.b = 1
self.n = n
def iter(self):
return self

def __next__(self):
    self.a,self.b = self.b,self.a + self.b
    if self.a > self.n:
        raise StopIteration
    return self.a

fibs = Fibs()
for each in fibs:
print(each)

1
1
2
3
5
8
13

fibs = Fibs(10)
for each in fibs:
print(each)

1
1
2
3
5
8

049 乱入:生成器

所谓协同程序,就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。

生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。

一个函数中如果有yield语句,则被定义为生成器。

实例1:

def myGen():
print(“生成器被执行了!”)
yield 1 #暂停一次,相当于return,返回1
yield 2 #暂停一次,相当于return,返回2

myG = myGen()
next(myG)
生成器被执行了!
1

next(myG)
2

像前面介绍的斐波那契的例子,也可以用生成器来实现:

def fibs():
a = 0
b = 1
while True:
a,b = b,a + b
yield a

for each in fibs():
if each > 100:
break
print(each)

1
1
2
3
5
8
13
21
34
55
89

列表推导式表达:

100以内,能被2整除,但不能被3整除的所有整数

a = [i for i in range(100) if not (i % 2) and (i % 3 )]
a
[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]

字典推导式:

10以内是否为偶数

a = {i:i % 2 == 0 for i in range(10)}
a
{0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}

集合推导式:

a = {i for i in [1,2,3,3,4,5,5,5,6,7,7,8]}
a
{1, 2, 3, 4, 5, 6, 7, 8}

元组生成器推导式:

e = (i for i in range(5))
next(e)
0

next(e)
1

next(e)
2

050 模块:模块就是程序

什么是模块

•容器 -> 数据的封装

•函数 -> 语句的封装

•类 -> 方法和属性的封装

•模块 -> 模块就是程序

命名空间

爱的宣言:世界上只有一个名字,使我这样牵肠挂肚,像有一根看不见的线,一头牢牢系在我心尖上,一头攥在你手中,这个名字就叫做鱼C工作室计算机一班的小花……

导入模块

•第一种:import 模块名

实例1:import导入模块
在这里插入图片描述

实例2:import导入模块
在这里插入图片描述

•第二种:from 模块名 import 函数名(不推荐使用)
在这里插入图片描述

•第三种:import 模块名 as 新名字(推荐使用)

TemperatureConversion文件:

def c2f(cal):
return cal * 1.8 + 32
def f2c(fah):
return (fah - 32)/1.8

calc文件:

import TemperatureConversion as tc #tc为取得新名字

print(“32摄氏度 = %.2f 华氏度\n” % tc.c2f(32))
print(“99华氏度 = %.2f 摄氏度” % tc.f2c(99))
在这里插入图片描述

051 模块:name=‘main’、搜索路径和包

模块!模块!

实例1:为TemperatureConversion添加测试程序(TemperatureConversion被作为程序运行)

def c2f(cal):
return cal * 1.8 + 32

def f2c(fah):
return (fah - 32)/1.8

def test():
print(“0摄氏度 = %.2f 华氏度\n” % c2f(0))
print(“0华氏度 = %.2f 摄氏度” % f2c(0))

test()

运行calc文

当希望TemperatureConversion被调用时作为模块导入时

def c2f(cal):
return cal * 1.8 + 32

def f2c(fah):
return (fah - 32)/1.8

def test():
print(“0摄氏度 = %.2f 华氏度” % c2f(0))
print(“0华氏度 = %.2f 摄氏度” % f2c(0))

if name == “main”:#当此文件当做程序运行时,执行test(),否则不执行
test()

运行calc文件

•if name == ‘main

•搜索路径(系统会首先搜索的路径)

import sys
sys.path
[‘D:\python3.3.2\小甲鱼python\python程序\第五十节课\Temperature’, ‘D:\python3.3.2\Lib\idlelib’, ‘C:\windows\system32\python33.zip’, ‘D:\python3.3.2\DLLs’, ‘D:\python3.3.2\lib’, ‘D:\python3.3.2’, ‘D:\python3.3.2\lib\site-packages’]

添加搜索路径:

import TemperatureConversion
Traceback (most recent call last):
File “<pyshell#0>”, line 1, in
import TemperatureConversion
ImportError: No module named ‘TemperatureConversion’

import sys
sys.path.append(“D:\python3.3.2\WODE\Temperature”)
sys.path
[’’, ‘D:\python3.3.2\Lib\idlelib’, ‘C:\windows\system32\python33.zip’, ‘D:\python3.3.2\DLLs’, ‘D:\python3.3.2\lib’, ‘D:\python3.3.2’, ‘D:\python3.3.2\lib\site-packages’, ‘D:\python3.3.2\WODE\Temperature’]

import TemperatureConversion
TemperatureConversion.f2c(59)
15.0

•包(package)

1.创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字;

2.在文件夹中创建一个__init__.py的模块文件,内容可以为空;

3.将相关的模块放入文件夹中
在这里插入图片描述

052 模块:像个极客一样去思考

使用print调用__doc__属性,可以带格式查看这个模块的简介

使用dir()可以查询到该模块定义了哪些变量、函数和类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值