【1.编程范式】
1.面向过程编程
2.面向对象编程
【2.面向过程编程】
面向过程:核心就是
过程
什么是过程?
过程指的是解决问题的步骤,先做什么,在作什么,面向过程就像是设计一个流水线,是一种机械式的思维方式,这种思维方式的基本思想就是把一个大的问题不断细化为各种子问题,然后不断细化,知道细化到能够在很小的范围里编写,然后逐个击破
面向过程的优缺点?
优点:复杂的问题分解为一步步小问题,复杂问题流程化进而简单化
缺点: 对于写程序,需要扩展代码,对于面向过程就需要不断修改,可扩展性不强,修改某一个功能,其他的功能都要去查,牵一发而动全身
设计一个用户登录界面
def login():
'''
用户输入账号密码
:return:
'''
username = input('>>>').strip()
pwd = input('>>>').strip()
return {
"username": username,
"pwd": pwd
}
def check(user_info):
'''
检查用户输入合法性
:return:
'''
is_valid = True
if len(user_info['username']) == 0:
print('用户名不能为空')
is_valid = False
if len(user_info['pwd'])<6:
print('密码不能少于6位')
is_valid = False
return {
'is_valid': is_valid,
'user_info': user_info
}
def register(check_info):
'''
完成注册
:return:
'''
if check_info['is_valid']:
import json
with open('db.json','w',encoding='utf-8') as f:
json.dump(check_info['user_info'],f)
def main():
'''
主函数代码块
:return:
'''
user_info = login()
check_info = check(user_info)
register(check_info)
if __name__ == '__main__':
main()
def login():#增加需求需要逐行检查
'''
用户输入账号密码
:return:
'''
username = input('>>>').strip()
pwd = input('>>>').strip()
email = input('>>>').strip()
return {
"username": username,
"pwd": pwd,
"email": email,
}
def check(user_info):
'''
检查用户输入合法性
:return:
'''
is_valid = True
if len(user_info['username']) == 0:
print('用户名不能为空')
is_valid = False
if len(user_info['pwd'])<6:
print('密码不能少于6位')
is_valid = False
import re
if not re.search(r'@.*?\.com$',user_info['email']):
print('邮箱格式不合法')
is_valid =False
return {
'is_valid': is_valid,
'user_info': user_info
}
def register(check_info):
'''
完成注册
:return:
'''
if check_info['is_valid']:
import json
with open('db.json','w',encoding='utf-8') as f:
json.dump(check_info['user_info'],f)
def main():
'''
主函数代码块
:return:
'''
user_info = login()
check_info = check(user_info)
register(check_info)
if __name__ == '__main__':
main()
【3.面向对象编程】
面向对象:核心就是对象,理解对象必须站在上帝的视角,任何事物都视为对象
什么是对象?
对象就是特征与技能的组合
总结:面向过程就是设计流水线,面向对象就是设计角色和角色的特征和技能
面向对象的优点和缺点
优点:可扩展性强,面向对象只能解决扩展性,但是软件开发里可扩展性只是一部分,掌握面向对象是开发的一部分
缺点:简单的问题会变的复杂化,编程的复杂度高,容易出现设计的问题
应用场景:用户需求经常变化的场景,互联网应用、游戏、企业内部的应用(办公系统)等经常发生需求变更的场景
【4.定义类与实例化对象】
什么是类?
分类就是从事物里找相似的特征,类就是一系列对象的相似特征与技能的结合体
强调,站在不同角度得到的分类是不一样的
先有类还是先有对象?
1.在现实世界,先存在事物,然后根据事物的特征判断类,所以现实里是先有对象再有类
2.在程序中,想要使用对象,必须是先有类(模板),然后才有对象,这样才能根据类去实例化对象(生产出一个对象)
站在路飞学院的角度,大家都是学生
学生对象:
1.panda
特征:
学校:Luffy
名字:panda
性别:男
技能:
学习
吃饭
睡觉
2.zombie
特征:学校:Luffy
名字:zombie
性别:男
技能:
学习
吃饭
睡觉
3.小哥
特征:学校:Luffy
名字:二师兄
性别:女
技能:
学习
吃饭
睡觉
总结相同的类
相同的特征:学校:Luffy
相同的技能:吃饭、学习、睡觉
下面来定义类
# 先定义类
class LuffyStudent:
school = 'luffy'
def learn(self):
print('学习使我快乐')
def eat(self):
print('吃饭使我幸福')
def sleep(self):
print('睡觉让我开心')
# 后产生对象
stu1 = LuffyStudent()
stu2 = LuffyStudent()
stu3 = LuffyStudent()
print(stu1, stu2, stu3)
【5.如何使用类】
当定义函数的时候,不调用是不会运行函数的,函数体的代码只有在调用的时候执行,一旦执行了函数就会产生一个局部名称空间,会把函数产生的类调用出去
定义类,在类的定义阶段就会内部的代码就会运行
产生的名称空间都是一个字典的形式
# 查看类的名称空间
print(LuffyStudent.__dict__)
Python不限制类在内部加其他的代码的,比如打印操作
类的两个属性
1.针对类内部定义的变量,称为数据属性
2.针对类内部定义的函数,称为函数属性
Pyhton提供了专门的属性访问语法>>类名+.+函数属性
# 查看类的名称空间
# print(LuffyStudent.__dict__)
print(LuffyStudent.school)#print(LuffyStudent.__dict__['school'])
print(LuffyStudent.learn)#print(LuffyStudent.__dict__['learn'])
# 增
LuffyStudent.county = 'China'
print(LuffyStudent.county)
# 删除
del LuffyStudent.county
print(LuffyStudent.county)
# 改
LuffyStudent.school = 'Luffycity1123'
print(LuffyStudent.school)
【小结】
1.调用类-类名+.+函数属性
2.类的增删改查(都坐下,基本操作)
【6.如何使用对象】
如何为每个对象定制各自各有的特征(__init__方法的引出)
# 为对象定制自己独有的特征
class LuffyStudent:
school = 'luffy'
def __init__(self, name, sex, age):
self.Name = name
self.Sex = sex
self.Age = age
def learn(self):
print('学习使我快乐')
def eat(self):
print('吃饭使我幸福')
def sleep(self):
print('睡觉让我开心')
# 后产生对象
# 有init的方法的时候,调用类的时候(实例化的步骤)
# 1.先产生一个空对象
# 2.触发一个__init__方法(类的函数属性)
stu1 = LuffyStudent('三炮', '女', 28)
stu2 = LuffyStudent('大锤', '男', 29)
stu3 = LuffyStudent('二狗', '女', 28)
print(stu1.Name, stu2.Name, stu3.Name)
print(stu1.__dict__)
# 查
# print(stu1.Name, stu2.Name, stu3.Name)
# print(stu1.__dict__)
# 改
# stu1.Name = '山炮'
# print(stu1.Name)
# 删除
# del stu1.Name
# print(stu1.Name)
# 增加
# stu1.Hobby = '篮球'
# print(stu1.Hobby)
【7.属性查找与绑定方法】
# 为对象定制自己独有的特征
class LuffyStudent:
school = 'luffy'
def __init__(self, name, sex, age):
self.Name = name
self.Sex = sex
self.Age = age
def learn(self):
print('%s 学习使我快乐' % self.Name)
def eat(self):
print('吃饭使我幸福')
def sleep(self):
print('睡觉让我开心')
stu1 = LuffyStudent('三炮', '女', 28)
stu2 = LuffyStudent('大锤', '男', 29)
stu3 = LuffyStudent('二狗', '女', 28)
# print(stu1.__dict__)
# print(stu2.__dict__)
# print(stu3.__dict__)
# 对象:特征与技能的结合体
# 类:一系列对象的相似的特征和相似的技能的结合体
# 类中的数据属性:是所有对象共有的
# print(LuffyStudent.school,id(LuffyStudent.school))
# print(stu1.school,id(stu1.school))
# print(stu2.school,id(stu1.school))
# print(stu3.school,id(stu1.school))
# 对象中的共有的类的特征共用一个内存地址,类的数据属性的内存地址是所有对象共有的
# 类中的函数属性
# 类的函数属性是绑定到不同的对象里的,是不同的绑定方法,绑定给谁就只有一个方法,私有化的使用方式
# 类的内部的函数属性就是一个普通的函数内存地址
# 绑定方法的特殊之处,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当做第一个参数(传给self)
# print(LuffyStudent.learn)
# LuffyStudent.learn(stu1)
print(stu1.learn)
stu1.learn() # stu1.learn() == LuffyStudent.learn(stu1)
# print(stu2.learn)
类中定义的函数属性,在未加说明的情况下,实际上是绑定给对象使用的,谁调用的,就会传给self,谁调用就会给谁使用函数属性的方法
对象本身只有独有的属性,相似的属性是放在类里的
如果有相同的函数属性怎么办,谁先调用?
类比函数的名称空间,会先调用自己,自己没有的时候,就会去找类里,只会在自己的函数和类里找,不会去全局找,因为范围里不涉及全局
【8.一切皆对象】
补充说明:
站在不同的角度来说,类的定义是不同的
现实世界中的类并不等于程序中的类,现实中的公司类,在程序中有时需要拆分成很多其他的类
有时为了编程的需求,程序中也可能会定义现实中不存在的类,比如策略类,现实中并不存在,但是程序中却是很常见的一个类
真正写项目的时候类不是真实存在的
其他补充
python中一切皆对象,python3中统一了类与类型的概念
print(type([1,2]))
【9.面向对象可扩展性总结】
面向对象的好处就是扩展性高的原因?
能把数据和处理数据的功能结合在一起
class Chinese:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
p1 = Chinese('panda',19,'male')
p2 = Chinese('boy',20,'Famale')
p3 = Chinese('zombie', 29, 'None')
class Chinese:
country = 'China'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
p1 = Chinese('panda',19,'male')
p2 = Chinese('boy',20,'Famale')
p3 = Chinese('zombie', 29, 'None')
print(p1.country)
【10.小练习1】
#练习1:编写一个学生类,产生一堆学生对象
# 要求:
# 有一个计数器(属性),统计总共实例了多少个对象
class Student:
School = 'Python大学'
Count = 0
def __init__(self,name, age, sex, hobby):
self.Name = name
self.Age = age
self.Sex = sex
self.Hobby = hobby
Student.Count += 1
s1 = Student("二狗", 19, "男", "篮球")
s2 = Student("三炮", 29, "男", "足球")
s3 = Student("四妹", 17, "女", "绣花")
print(Student.Count)
【11.小练习2】
# 练习2:模仿LOL定义两个英雄类,
# 要求:1.英雄需要有昵称、攻击力、生命值等属性
# 2.实例化出两个英雄对象
# 3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判定死亡
class Hero:
def __init__(self, name, attack, health, speed):
self.Name = name
self.Attack = attack
self.Health = health
self.Speed = speed
def kill(self,hero_name):
hero_name.Health -= self.Attack
class Zombie(Hero):
pass
class Rabbit(Hero):
pass
h1 = Zombie("panda", 20, 100, 20)
h2 = Rabbit("pandaboy", 30, 120, 20)
print(h1.Health)
h1.kill(h2)
print(h1.Health)
print(h2.Health)
h1.kill(h2)
print(h2.Health)
【12.继承与重用性】
如何解决类与类之间的代码冗余问题?
通过继承就可以解决类与类之间的代码冗余关系
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类成为派生类或子类
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象过程,才能通过集成的方式去表达出抽象的结构
抽象只是分析和设计的过程中,一个动作或者说是一个技巧,通过抽象就可以得到类(抽象最主要的就是划分类别,可以隔离关注点)
python中的继承分为单继承和多继承,子类可以重用父类的功能
对象访问属性的顺序:对象本身>>继承的父类>>继承的超类
class Parentclass1:
pass
class Parentclass2:
pass
class SubClass1(Parentclass1):
pass
class SubClass2(Parentclass1,Parentclass2):
pass
print(SubClass1.__bases__)
print(SubClass2.__bases__)
# 属性查找小练习
class Foo:
def f1(self):
print('from Foo class')
def f2(self):
print('from FOO f2')
self.f1()
class Bar(Foo):
def f1(self):
print('from Bar.f2')
b = Bar()
b.f2()
【13.派生】
继承实现了节省代码的好处
派生的概念,当子类添加自己的新的属性或者自己这里重新定义这些属性(不会影响父类),需要注意的是,一旦重新定义了自己的属性与父类的重名,那么调用新增的属性时,就以自己的为准了
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有时候可能需要重用父类的那个函数功能,应该是用调用普通函数的方式,即类名func(),此时就与普通函数相同了
因此即便是self参数,也要为其传值
【14.继承的实现原理】
针对多继承的情况下,如何查找?
python到底是如何实现继承的,对于每定义的一个类,pytho会计算出一个方法解析顺序(MRO)列表
这个MRO列表就是一个简答的所有基类的线性顺序列表
lass A:
pass
class B:
pass
class C:
pass
class D:
pass
class E:
pass
class F(A,B,C,D,E):
pass
print(F.mro())
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止,而这个MRO列表的构造是通过一个C3线性化算法来实现的,实际上就是合并了所有的父类的MRO列表并遵循如下三个准则
1.子类会先于父类被检查
2.多个父类会根据它们在列表的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,分别是深度优先和广度优先
简单就说就是会按照mor列表里的顺序去找方法
那么这个列表到底是什么顺序去找的属性呢?
python的mro列表的产生决定了查找的方式,
【python2中的类分为两种,一种是新式类,一种是经典类】
# # python2中的经典类:没有继承object的类以及它的子类都称为经典类
#
# class Foo:
# pass
#
#
# class Bar(Foo):
# pass
#
# # python2中的新式类:继承object的类以及它的子类都称为新式类
# class Foo(object):
# pass
#
# class Bar(Foo):
# pass
# python3中所有的类都是新式类,因为所有的类都是默认继承object的
# class Foo:
# pass
对于经典类就是深度优先,对于新式类就是广度优先(对象自己这里>>自己的类>>父类)
【15.在子类中重用父类的方法和属性】
在子类中重用父类的方法---指名道姓法(不依赖继承)
class Hero:
def __init__(self, nickname, life_value, aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self, enemy):
enemy.life_value -= self.aggresivity
class Garen(Hero):
camp = 'Demacia'
def __init__(self, nickname, life_value , aggresivity, weapon):
Hero.__init__(self, nickname, life_value , aggresivity)
self.weapon = weapon
def attack(self, enemy):
Hero.attack(self, enemy) #指名道姓,直接指定调用函数的对象
print('from Garen Class')
g = Garen('草丛', 100, 30,'大保健')
print(g.__dict__)
在子类中重用父类的方法---super()(依赖继承)
主要有子类继承了父类的,python就会根据MRO列表,计算出继承的执行的顺序关系,而super()就是在MRO列表中去找父类的执行方式【有一个坑要注意的,super()方法并不是找父类,而是根据MRO列表去执行顺序!即使看上去没有继承关系的也必须去根据MRO列表执行】
# 方式二 super继承
class Hero:
def __init__(self, nickname, life_value, aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self, enemy):
enemy.life_value -= self.aggresivity
class Garen(Hero):
camp = 'Demacia'
def __init__(self, nickname, life_value , aggresivity, weapon):
super().__init__(nickname, life_value , aggresivity)
self.weapon = weapon
def attack(self, enemy):
super(Garen,self).attack(enemy) #得到了父类的对象(依赖继承,不用再传self)
print('from Garen Class')
class Riven(Hero):
camp = 'Noxus'
r = Riven('瑞文',100,30)
g = Garen('草丛', 100, 30,'大保健')
g.attack(r)
print(r.life_value)
【16.组合】
什么是组合?
什么是什么(老师是人、学生是人),这种关系用继承
什么有什么(老师有生日,学生有生日),这种关系用组合
# 选课系统
class People:
school = 'Luffycity'
def __init__(self, name, age,sex):
self.name = name
self.age = age
self.sex = sex
class Teather(People):
def __init__(self, name, age,sex, level, salary):
super().__init__(name, age,sex)
self.level = level
self.salary = salary
def teach(self):
print('%s is teaching' % self.name)
class Student(People):
def __init__(self, name, age, sex, class_time):
super().__init__(name, age, sex)
self.class_time = class_time
def learn(self):
print('%s is talking' % self.name)
class Course:
def __init__(self,course_name, course_price, course_period):
self.course_name = course_name
self.course_price = course_price
self.course_period = course_period
def tell_info(self):
print(self.course_name, self.course_period, self.course_price)
teacher1 = Teather('大胖', 99, '男', '低级', 5000)
teacher2 = Teather('小胖', 89, '男', '中级', 3000)
stu1 = Student('小猪',20,"男", "08:30:00")
python = Course('python', 8900, '6mons')
linux = Course('Linux',1200, '3mons')
teacher1.course = python
teacher2.course = python
# teacher1.course.tell_info()
stu1.course1 = python
stu1.course2 = linux
stu1.course1.tell_info()
stu1.course2.tell_info()
【17.抽象类与归一化】
抽象类的引入
相似的类里有相同的功能,但是调用的方法名称不同,对使用者造成困难,最好能统一类的方法
python中没有像JAVA那样提供了interface的接口类去抽象几个类的特征,但是有它独特的方法--使用父类的继承就可以了,
问题:虽然降低的复杂度,但是不能硬性限制类的继承方法,如何限制呢?
使用抽象类啊!使用abc模块, 对父类使用metaclass=abc.ABCMeta,并且对函数使用装饰器@abc.abstractmethod
抽象类本质还是类,抽象类只能被继承不能被实例化,它的功能只是为了规范子类,本身就是不能被实例化的,
抽象类会降低后期类的使用的复杂度,尽量在写程序的时候先使用这个方式去规范后面类继承的方法
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
class People(Animal):
def run(self):
print('people is walking')
def eat(self):
print('people is eating')
class People:
def walk(self):
print('is walking')
class Pig:
def run(self):
print('is running')
class Dog:
def zou(self):
print('is zouing')
p1 = People()
pig1 =Pig()
dog1 = Dog()
p1.walk()
pig1.run()
dog1.zou()
【18.多态与多态性】
面向对象的第二特性:多态(同一种事物的多种形态),比如动物有人、狗、猪的形态
文件也有多种形态,文本文件、可执行文件等
多态性(多态动态性绑定):
可以不考虑实例类型的情况下,直接使用实例
多态性的好处:1.增加了程序的灵活性,以不变应万变,使用者都是同一种形式去调用(func(animal))
2.增加了程序的可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def talk(self):
pass
class People(Animal):#动物的形态之一:人
def talk(self):
print('say hello')
class Dog(Animal):#动物的形态之二:狗
def talk(self):
print('say wangwang')
class Pig(Animal):#动物的形态之三:猪
def talk(self):
print('say aoao')
class Cat(Animal):
def talk(self):
print('say miaomiao')
# 多态性:指的是在可以不考虑对象的类型的情况下,而直接使用对象
# 多态性就是不用考虑自己的实例类的具体类型直接执行就完事了
# 静态的多态性:使用+方法的时候无需考虑数据类型,只要是列表、数字、字符串,直接都可以相加,加就完事了
p1 = People()
d1 = Dog()
pig1 = Pig()
cat1 = Cat()
p1.talk()
d1.talk()
pig1.talk()
# 使用了同一个接口,就像学车一样,不会学开什么车,只是开车的方法就可以了
def func(animal):
animal.talk()
func(p1)
func(pig1)
func(d1)
func(cat1)
鸭子类型:看上去是一个鸭子,具有鸭子的特征,那就是鸭子
# class File:
# def read(self):
# pass
#
# def write(self):
# pass
#
#
# class Disk:
# def read(self):
# print('disk read')
#
# def write(self):
# print('disk write')
#
# class Text:
# def read(self):
# print('text read')
#
# def write(self):
# print('text writre')
#
# disk = Disk()
# text = Text()
#
# disk.read()
# disk.write()
# text.read()
# text.write()
# 序列类型:列表list、元祖tuple、字符串str
l = list([1,2,3])
t = tuple(('a','b'))
s = str('hello')
# print(l.__len__())
# print(t.__len__())
# print(s.__len__())
# 提供接口
def len(obj):
return obj.__len__()
print(len(l))
【19.封装之如何隐藏属性】
封装:从字面上就是隐藏,实际封装不是单纯的意义的隐藏(属性名前 __name)
在类的定义阶段__name就会执行代码,识别__name的就会改成classname__name形成封装
python通过一种变形的操作来隐藏起来,在定义阶段就隐藏
特点:
1.变形完以后,类外部无法直接访问到obj.__AttrName
2.在类的内部obj.__AttrName是可以调用的,是因为在类的定义阶段就已经改成了变形的格式了
3.子类无法覆盖父类__开头的属性
【总结】
1.这种机制也没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:类名__属性名,然后就可以访问了,如a._A__N
2.变形的过程只在类的定义时发生过一次,在定义的后的赋值操作,不会变形,要隐藏就放在类里面!别等人家都生成了你再想隐藏!
3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
# class A:
# __x = 1
#
# def __init__(self, name):
# self.__name = name
#
# def __foo(self):
# print('run foo')
# def bar(self):
# self.__foo()
# print('form bar')
#
# a = A('panda')
# a.bar()
# class Foo:
# def func(self):
# print('from foo')
#
# class Bar(Foo):
# def func(self):
# print('from bar')
#
# b = Bar()
# b.func()
# class Foo:
# def __func(self):
# print('from foo')
#
#
# class Bar(Foo):
# def __func(self):
# print('from bar')
#
#
# b = Bar()
# b._Bar__func()
【20.封装的意义】
封装的意义:封装数据属性或函数属性
1. 将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
2. 封装方法:目的是隔离复杂度
# 封装数据属性:明确的区分内外,只能在内部开一个接口让外部去间接的访问,可以控制用户的使用行为,可以打印为固定的格式
# 把真实的数据隐藏起来,只能访问定制的格式
# class People:
# def __init__(self, name, age):
# self.__name = name
# self.__age = age
#
# def tell_info(self):
# print('Name:<%s> Age:<%s>' %(self.__name, self.__age))
#
# def set_info(self,name, age):
# if not isinstance(name, str):
# print('名字必须是字符串类型')
# return
# if not isinstance(age, int):
# print('年龄必须是数字类型')
# return
# self.__name = name
# self.__age = age
#
#
# p = People('panda', 19)
# p.tell_info()
# p.set_info('zombie', 1)
# p.tell_info()
# 目的二:隔离复杂度
class ATM:
def __card(self):
print('插卡')
def __auth(self):
print('用户认证')
def __input(self):
print('输入取款金额')
def __print_bill(self):
print('打印账单')
def __take_money(self):
print('取款')
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
a = ATM()
a.withdraw()
【21.封装与可扩展性】
封装的可扩展性高体现在哪里?
使用者的方法没有变,需求只需要变自己类的方法里的函数属性就可以了
class Room:
def __init__(self, name, owner, height, weight, length):
self.name = name
self.owner = owner
self.__height = height
self.__weight = weight
self.__length = length
def area(self):
return self.__weight*self.__length*self.__height
r = Room('卫生间','panda',10,10,10)
print(r.area())
# 使用者的方法没有变,需求只需要变自己类的方法里的函数属性就可以了
【22.property的使用】
【23.绑定方法与非绑定方法介绍】
【24.绑定方法与非绑定方法】
【25.反射】
【26.内置方法介绍】
【27.元类介绍】
【28.自定义元类控制类的创建】
【29.自定义元类控制类的实例化行为】
【30.自定义元类控制类的实例化行为的应用】
【31.面向对象的软件开发与作业介绍】
【32.什么是异常处理】
【32.try...except...详细方法】