文章目录
博客cpen_web
练习1 类的使用
·已经有Bus317这个类
·实例化一个对象 # 注:通过__new__方法创建的实例(一般不要重写)
·使用对象的属性
·使用对象的方法
·添加实例属性 # 注:没有就添加 有就修改
·修改实例属性
·添加类属性
·修改类属性
·删除属性
示例
# 类的使用
class Bus317(object):
line = "317"
prod = "BYD"
obj = 0 # 注:定义属性
def __init__(self, car_num, name):
# print("init Bus317")
self.car_num = car_num
self.name = name
def run(self, flag):
print("bus317 run, %s drive" %self.name)
if flag == 0:
print("从农大到长华小区")
else:
print("从长华小区到农大")
# 实例化对象
bus01 = Bus317("湘A2","甲")
# 使用对象的属性
print(bus01.car_num)
# 使用对象的方法
bus01.run(0)
# 添加实例属性 # 注:实例空间 使用实例名字访问
bus01.time = "1h"
# 修改实例属性
bus01.name = "乙"
# 添加类属性 # 注:类空间 使用类名访问
Bus317.company = "changsha_bus"
# 修改类属性
Bus317.line = "10"
# 删除属性
delattr(Bus317, "line") # 注:删除Bus317的line属性
del Bus317.line # 注:删除索引
#注:删除属性
#方法1、delattr(Bus317, "line") # 注:删除Bus317的line属性
#方法2、del Bus317.line # 注:删除索引
练习2 斐波拉契数列
#注:用类实现斐波那契数列的运算(编写自定义迭代器)
方法1:生成器实现斐波拉契数列
示例
#生成器实现斐波拉契数列
def fib(): # 注:定义生成器函数
pre,cur = 0,1 # 注:初始化值
while True: # 注:循环获取
yield cur # 注:yield 获取
pre, cur = cur, pre+cur
f = fib()
#使用列表推导式
print([ next(f) for i in range(20)])
#结果为 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
#注:循环获取20个值 使用列表推导式
方法2.1:迭代器实现斐波拉契数列
示例
#迭代器实现斐波拉契数列
class Fib():
def __init__(self):
self.pre = 0
self.cur = 1
def __iter__(self):
return self
def __next__(self):
result = self.cur
self.pre, self.cur = self.cur, self.cur+self.pre
return result
f = Fib() # 注:进行实例化对象
print([next(f) for i in range(20)])
#结果为 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
方法2.2:迭代器实现斐波拉契数列
示例
#迭代器实现斐波拉契数列
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
def __iter__(self):
return self
f = Fibs()
print([next(f) for i in range(20)])
#结果为 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]
知识点3 类-self详解
#总结
#self在定义实例方法时,需要定义,调用时自动传如
#self的名字并不是规定死的,但是 最好还是按照约定使用self
#self总是指向调用时的类的实例
#方法:判断使用类去执行,还是使用对象执行
# 看有没有self
# 有self,使用实例对象执行
# 没有self,使用类执行
示例1:self代表的是类的实例,而并非类
#1、self代表的是类的实例,而并非类
class Person():
name = "wy"
age = 18
def info(self):
print(f"我是:{self.name},今年{self.age}岁了") # 定义类属性
print(self) # 注:self代表类的实例(而非类) Person object
print(self.__class__) # 注:查看属于哪个类
p = Person() # 对Person类进行实例化
p.info() # 进行实例化方法
#结果 我是:wy,今年18岁了
# <__main__.Person object at 0x0000023C8D6865B0>
# <class '__main__.Person'>
示例2:self不必非写成self
#2、self不必非写成self
#实例方法 第1个参数不必非写成self
#约定俗成都使用self
class Person():
name = "wy"
age = 18
def info(this): # 注:运行时自动识别第1个参数,当做它的对象
print(f"我是:{this.name},今年{this.age}岁了")
print(this)
print(this.__class__)
p = Person()
p.info()
#结果 我是:wy,今年18岁了
# <__main__.Person object at 0x0000023C53656B80>
# <class '__main__.Person'>
示例3:self可以不写
#3、self可以不写
#但就不是1个实例方法了,属于1个类方法
class Person():
name = "wy"
age = 18
def info(this):
print(f"我是:{this.name},今年{this.age}岁了")
print(this)
print(this.__class__)
def info2(): # 注:self可以不写
print("this is info2")
p = Person()
p.info() # --> Person.info(p)
#当调用p.info()时,实际上Python解释器解释成Person.info(p)去运行的
# p.info2() #注:报错 不可以使用实例化对象去运行
#执行的时候 --> Person.info2(p) info2()需要0个位置参数 但是给了1个位置参数
#TypeError: info2() takes 0 positional arguments but 1 was given
Person.info2() # 注:使用类方法去运行
#结果为 this is info2
# Person.info() # 注:报错
#TypeError: info() missing 1 required positional argument: 'this'
Person.info(p)
#结果为 我是:wy,今年18岁了
# <__main__.Person object at 0x000001DC390765B0>
# <class '__main__.Person'>
示例4:在继承的时候,self代表实例
#4、在继承的时候,self代表哪个类
#self就代表那个实例,无论怎么继承
class Parent:
def pprt(self):
print(self)
class child(Parent):
def cprt(self):
print(self)
c = child()
c.cprt() # 注:self代表c对象 实例化对象
#结果为 <__main__.child object at 0x00000228AFDB6B80>
c.pprt() # 注:继承的父类的方法 self还是代表实例(c对象)
#结果为 <__main__.child object at 0x00000228AFDB6B80>
p = Parent()
p.pprt() # 注:self代表实例本身(p对象)
#结果为 <__main__.Parent object at 0x0000018578C96970>
知识点4 类的继承
面向对象的好处
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。 # 注:继承实现代码的复用
·可以节省很多的代码,不需要写,直接使用 # 注:继承的好处
·衍生出不同的子类,大部分代码一样,部分代码不一样 # 注:继承的好处
练习5 类的继承
·创建一个父类:Animal
·创建子类:Person、Pig
·定义属性category及统计数量
·在父类中定义方法breath
·测试:实例化,检查数量统计情况、检测实例与类的关系
示例
class Animal():
category = "Animal" # 类属性
count = 0
def __init__(self): # 初始化
self.name = "animal"
self.age = "18"
print("初始化animal")
Animal.count += 1
print(Animal.count)
def breath(self):
print("i can breath")
def eat(self):
print("i can eat")
class Person(Animal): # 子类
count = 0
category = "person"
def __init__(self): # *注:子类重写父类的方法
print("初始化Person")
Person.count += 1
print(Person.count)
def eat(self):
print("person is eating...")
class Dog(Animal):
def eat(self):
print("dog is eating...")
class Pig(Animal):
count = 0
def __init__(self): # 注:在父类的初始化后,又重加了一些属性
# self.name = "pig"
print("初始化pig")
super().__init__() # 注:python3的语法;无论是什么父类
# super(Pig, self).__init__() # 注:Python2、3都支持的语法 ;self必须是Pig的实例 super必须只能去访问父类
# Animal.__init__(self) # 需要明确父类
self.name = "pig"
Pig.count += 1
print(Pig.count)
#super 一般在子类里面使用,去访问父类的东西的时候 才会用到
#实例化对象
animal = Animal()
#结果为 初始化animal
#1
person = Person() # 注:子类继承父类的__init__,重写了__init__,使用自己的__init__
#结果为 初始化Person
#1
dog = Dog() # 注:子类会继承父类的所有方法,包括__init__,子类没有重写 会使用父类父类的__init__
#结果为 初始化animal
#2
# pig = Pig()
#结果为 初始化pig
#初始化animal
#3
pig = Pig()
#结果为 初始化pig
# 初始化animal
# 3
# 1
# print(pig.name) # 注:注意super()和self.name = "pig"的位置
#结果为 animal
print(pig.name, pig.age) # 注:super()写在self.name = "pig"前面
#结果为 pig 18
#注:Pig继承Dog,Dog继承Animal,super.__init__(self) 不接参数访问dog的__init__,但直接指定super(Animal).__init__(self) 访问不到Animal的__init__
#示例:重写父类的方法
#重写父类的方法
animal.eat()
#结果为 i can eat
dog.eat() # 重写Animal的eat
#结果为 dog is eating...
pig.eat() # 继承Animal的eat
#结果为 i can eat
#示例:类和实例的关系
#注意类和实例的关系
#注:isinstance判定它属于哪个类
print("isinstance(animal,Animal)",isinstance(animal,Animal))
#结果为 isinstance(animal,Animal) True
#注:animal属于Animal类
print("isinstance(pig,Animal)",isinstance(pig,Animal))
#结果为 isinstance(pig,Animal) True
#注:pig属于Animal类 ;pig属于Pig类,也属于Animal类
print("isinstance(animal,Pig)",isinstance(animal,Pig))
#结果为 isinstance(animal,Pig) False
#注:小类属于大类,大类不属于小类
练习6 自定义异常类
自定义异常类:
·自定义异常能让异常更精准
·自定义异常类:当list内元素长度超过10的时候抛出异常
·自定义异常类:消息小于8时抛出异常
示例1
try:
a = 1/0
except Exception as e:
print("exception error")
#结果为 exception error
#-------------------------------------------------------------------------------------------
#自定义异常类
class ListError(Exception): # 注:继承Exception的基类
def __init__(self,lst,message): # 注:重写Exception异常类的__init__方法
self.list = list # 注:不写的话调用的是Exception异常类的__init__方法
self.message = message
# pass # 注:不写的话直接pass
def __str__(self): # 注:对listError的说明
return "list 长度不在8-10之间"
# print(ListError())
# #结果为 list 长度不在8-10之间
def __str__(self): # 注:重写exception的str方法,获得异常类信息
msg = "list:"+str(self.list)
msg = msg +"\n"+self.message
return msg
try:
lst = [1,2,3,4,5,6,7,8,9,0,11]
if not 8<len(lst)<10:
# raise ListError("长度不在8-10之间") # 注:exception帮你做了
# raise ListError()
raise ListError(lst, "长度不在8-10之间")
except ListError as e:
print("ListError error:",e)
#结果为 ListError error: 长度不在8-10之间
#结果为 ListError error: list 长度不在8-10之间
示例2
#自定义异常类##########
class ListError(Exception):
def __init__(self,list, message): #重写Exception异常类的__init__方法
self.list = list # 注:目的是重写输出信息
self.message = message
# pass
def __str__(self): #重写Exception的str方法,获得异常类信息
msg = "list:"+str(self.list)
msg = msg +"\n" +self.message
return msg
#print(ListError())
try:
lst = [1,2,3,4,5,6,7,8,9,0,11]
if not 8<len(lst)<10 :
raise ListError(lst,"长度不在8-10之间")
# raise ListError(lst,"长度不在8-10之间","xx","yy")
except ListError as e:
print("listError error:",e)
#结果为 listError error: list:[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11]
#长度不在8-10之间
#结果为 listError error: ([1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11], '长度不在8-10之间', 'xx', 'yy')
练习7 接收从键盘的输入,如果输入字符中包含了除数字以外的字符,就抛出自定义异常
示例
#接收从键盘的输入,如果输入字符中包含了除数字以外的字符,就抛出自定义异常
class IsNumber(Exception):
def __init__(self,str1,message):
self.str1 = str1
self.message = message
def __str__(self): # 仅仅只是打印 *args, **kwargs
msg = "\n"+self.str1+"\n"+self.message
return msg
a = input("请输入一串:")
try:
if not a.isdigit(): # 把一串接收的参数作为元组打印(可变长位置参数) 字典(可变长关键字参数)
raise IsNumber(a,f"{a}中存在除数字之外的东西") # 注:抛出异常
except IsNumber as e:
print("IsNumber error",e)
#结果为 请输入一串:123abc
#IsNumber error
#123abc
#123abc中存在除数字之外的东西
知识点8 Python中的多态
#多态:同一种事物的多种形态
#多态:* 实现接口的重用
示例
#Python的多态
#Python里不支持多态,Python处处是多态
#Python动态解释型语言
#1、Python
# def func1(name):
# print(name)
# func1("wy")
#2、java
# def func1(str name) # 注:定义类是str类型,传递的必须是str类型
#java里先对obj进行类型判断(对传递的类型严格把控)
#java里面使用继承,类型指定为A类,传递参数
#Java中使用继承实现多态
#-------------------------------------------------------------------------------------------
class A:
def func1(self):
print("class A func1")
# class B(A):
class B():
def func1(self):
print("class B func1")
# class C(A):
class C():
def func1(self):
print("class C func1")
def func2(obj): # 注:func2() 接收的对象只要有func1()方法,就可以被正确执行
obj.func1() # 注:只要有func1()方法的参数,都可以去执行它
# 注:Python里崇尚鸭子类型,不管这个obj对象是什么类,只要有func1()行为
a1 = A()
# a1.func1()
b1 = B()
# b1.func1()
c1 = C()
func2(a1)
func2(b1)
func2(c1)
#结果为 class A func1
# class B func1
# class C func1
#为什么说不支持多态:不需要像java一样以父类作为参数传递子类的对象()
#为什么说处处是多态:按照python的表现力来说处处是多态
#Python里处处是多态:因为 本身就实现了多态的性质
#Python里不支持多态:因为 按多态的严格语法来说 父类作为参数,可以传递子类对象
知识点9 经典类与新式类
类可以多重继承
定义类A
定义类B\C,B\C继承自A # 注:多重继承 A继承B B继承C
定义类D, D继承自B
定义类E, E继承自C
定义类F, F继承自D\E
示例1:python 类可以多重继承
#python 类可以多重继承
class A:
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D,E):
def test(self):
print("from F")
f = F()
f.test()
#结果为 from F
示例2:经典类与新式类在类型上的区别
#注:tmux 同步
#注::set synchronize-panes on (操作:[ctrl + b (shif +):]set syn[tab键 补齐])
#注:off 是 关闭
#-------------------------------------------------------------------------------------------
#Python2
>>> class A(): pass # 注:经典类
...
>>> class B(): pass
>>> a = A()
>>> b = B()
>>> type(a) # 类的实例都是instance类型;属于instance(代表所有实例)
<type 'instance'> # 经典类里都统称为 实例
>>> type(b)
<type 'instance'>
>>> type(a) == type(b)
True
>>> a.__class__ # 注:__class__查看对象属于哪个类
<class __main__.A at 0x7ff46ddce258> # 注:经典类 类与实例只有通过__class__属性进行关联
>>> b.__class__
<class __main__.B at 0x7ff46ddce2c0>
#-------------------------------------------------------------------------------------------
#Python3
>>> class A(): pass # 注:新式类
...
>>> class B(): pass
...
>>> a = A()
>>> b = B()
>>> type(a) # 属于新式类
<class '__main__.A'> # 新式类实例化对象 type出来的对象都属于某一个类
>>> type(b)
<class '__main__.B'>
>>> type(a) == type(b)
False
>>> a.__class__ # 注:__class__查看对象属于哪个类
<class '__main__.A'>
>>> b.__class__
<class '__main__.B'>
#总结:
#经典类和新式类
1、类型区别
·经典类
·所有的类都是classobj类型,而类的实例都是instance类型。
·类与实例只有通过__class__属性进行关联
·新式类
·类实例的类型是这个实例所创建自的类(通常是和类实例的__class__相同)
2、继承顺序
经典类:深度优先
新式类:广度优先
#广度优先 查找顺序 F --> D --> B --> E --> C --> A
示例3
class A():
def talk(self):
print("A")
class B(A):
pass
#def talk(self):
# print("B")
class C(A):
def talk(self):
print("C")
class D(B,C): #注:D 继承 B和C(这注释写在python2中报错)
pass
#def talk(self):
# print("D")
d1 = D()
d1.talk()
#-------------------------------------------------------------------------------------------
[root@cPen_centos8 lianxi]# python2 test_class.py # 注:深度优先 经典类
A
[root@cPen_centos8 lianxi]# python2 test_class.py # 注:广度优先 新式类
C
示例4
#python 类可以多重继承(这注释写在python2中报错)
class A:
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D,E):
def test(self):
print("from F")
f = F()
f.test()
#-------------------------------------------------------------------------------------------
[root@cPen_python lianxi]# python2 test_class2.py
from F
[root@cPen_python lianxi]# python3 test_class2.py
from F
#注:经典类 python2 深度优先,一条路走到黑(从左到右 从下到上)
#注:新式类 python3 广度优先,先把子类对象找完,再去找另外1边, 不会直接去找父类
#注:广度优先 寻找到每1边的父类为止
#注:广度优先 先找1边的所以子类,再找另一边的所以子类
#广度优先 查找顺序 F --> D --> B --> E --> C --> A
#class F(D,E,B) #注:只能先继承父亲,再继承爷爷