提示:本文代码完全来源于哔哩哔哩《10小时搞定Python面向对象(完整版)》,本文用途仅限于Python编程的学习。
网址:https://www.bilibili.com/video/BV1t34y197tv?spm_id_from=333.999.0.0&vd_source=3b0d75c3bc9e365b679882b6812cac6d
文章目录
前言
提示:这里简要介绍关于面向对象的知识
编程范式就是一个编程的套路、思维
编程范式:1、面向过程的编程范式(Procedure Programming);2、面向对象的编程范式(Object-Oriented Programming)
1、面向过程的编程范式
程序从上到下一步步地执行,一步步从上到下,从头到尾的解决问题。基本设计思路就是程序一开始就是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题
或者子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决
2、面向对象的编程范式
面向对象的编程是利用类和对象来创建各种模型来实现对于真实世界的描述,使用对象对象的编程的原因:一方面是因为他可以使得程序的维护和扩展变得更加简单
并且可以大大的提高程序的开发效率,另外就是,基于面向对象的程序可以使它人更容易的理解你的代码逻辑。
提示:接下来是详细的代码实现
零、回顾面向过程的编程
- 创建一个字典类型的变量
# 1 整合日志
def collect_log():
print("log on server A , get access.log")
print("log on server B , get access.log")
print("log on server C , get access.log")
print("combine logs in to one file")
# 2 日志分析
def log_analyze():
print("pv、uv分析....")
print("用户来源分析....")
print("访问的设备来源分析....")
print("页面停留时间分析....")
print("入口页面分析....")
# 3 生成报告并发送
def send_report():
print("connect email server....")
print("send email....")
def main():
collect_log()
log_analyze()
send_report()
if __name__ == '__main__':
main()
一、通过字典的方式来实现类似于面向对象的功能
- 创建一个字典类型的变量
attack_vals = {
"京巴":30,
"藏獒":80
}
- 定义一个类(功能方面的类,并不是实际的类,这是通过函数实现的),相当于dog是一个类,在内部定义的data相当于类的属性,而内部定义的函数dog_bite相当于类方法。
def dog(name, d_type):
data = { # 定义一个字典类型的变量,最终该函数将把这个字典变量返回
"name" : name,
"d_type" : d_type,
"life_val": 100
}
if d_type in attack_vals:
data["attack_val"] = attack_vals[d_type]
else:
data["attack_val"] = 15
def dog_bite(person_obj): # 定义一个方法(函数),这个函数名可以通过字典变量进行调用
person_obj["life_val"] -= data["attack_val"] # 执行咬人减血动作
print("狗[%s]咬了人[%s]一口,人掉血[%s],还有血量[%s]..."%(data["name"],
person_obj["name"],
data["attack_val"],
person_obj["life_val"]
))
data["bite"] = dog_bite # 注意这个地方给字典中的键赋值时,是函数名不带括号,调用时要带括号
return data
- 同样的道理,创建另外一个类
def person(name, age):
data = {
"name" : name,
"age" : age,
"life_val": 100
}
if age < 18:
data["attack_val"] = 30
else:
data["attack_val"] = 50
def hit(dog_obj): # 定义一个方法(函数),这个函数名可以通过字典变量进行调用
dog_obj["life_val"] -= data["attack_val"] # 执行咬人减血动作
print("人[%s]打了狗[%s]一棍,狗掉血[%s],还有血量[%s]..."%(data["name"],
dog_obj["name"],
data["attack_val"],
dog_obj["life_val"]
))
data["hit"] = hit # 注意这个地方给字典中的键赋值时,是函数名不带括号,调用时要带括号
return data
- 实例化
dog1 = dog( "XXX", "京巴") # 实体
dog2 = dog( "YYY", "藏獒")
person1 = person( "ZZZ", 22)
# 调用实体本身具有的方法
person1["hit"](dog1)
dog1["bite"](person1)
二、面向对象的编程范式OOP
- 创建一个字典类型的变量
'''
1、Class 类
一个类就是对于一类拥有相同属性的对象的“抽象”、蓝图、原型。
在类中定义了这些对象的都具有的属性(variables(data))、共同的方法(functions)。
类:人
2、Object 对象
一个对象就是一个类的实例化,一个类必须经过实例化后方可在程序中调用
一个类可以实例化多个对象,每个对象亦可以有不同的属性(variables)
对象:某个人
3、 Encapsulatation 封装
在类中对于数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里边包含着类的数据和方法
4、 Inheritance 继承
一个类可以派生出子类,在父类里定义的属性、方法自动被子类继承
5、 Polymorphsim 多态
'''
三、类
- 创建一个字典类型的变量
class Dog: # 在python官方规范里,类名首字母要大写。
# 1、公有的属性是类定义体内定义的。实例化的对象(所有的对象都共享类定义体的公共属性空间(类在声明后是占用内存空间的))
# 公有属性可以在类定义体以外进行修改,但是所有实例化的对象都跟着变(共享同一内存空间)
# 公共属性又叫做类属性
d_type = "京巴" # 类属性,类变量1(公有的属性)
home = "中国" # 类属性,类变量2(公有的属性)
# 2、初始化方法,构造方法,构造函数,实例化时自动执行(无需调用),进行一些初始化的工作
# 一些私有属性要通过初始化函数传入进来
# 私有属性在初始化函数中定义,初始化函数执行完了内存空间释放,所以在类定义体中的其他函数中无法调用私有属性
# 私有属性又叫做实例属性、成员变量
'''
def __init__(self) -> None:
pass
'''
'''
def __init__(self, name, age): # 这样传入时,内存释放,实例化后的对象并没有name, age这两个属性
print("哈哈哈....", name, age)
'''
# 要想保存私有属性,那就要将私有属性和实例绑定。self代表实例本身
def __init__(self, name, age):
self.name = name
self.age = age
def sayhi(self): # self 代表实例本身,类定义中的方法,第一个参数必须是self
print("hello, I am a dog! My type is [%s],and my age is [%s]."%(self.d_type,self.age)) # 调用类属性需要self.
#实例化
D1 = Dog("XXX",2) # 创建一个Dog类的对象,叫做D1,传入参数就是私有属性(变量),这些参数将传入到__init__(self, name, age)函数中去。
D2 = Dog("ZZZ",3) # 创建一个Dog类的对象,叫做D2,传入参数就是私有属性(变量),这些参数将传入到__init__(self, name, age)函数中去。
D1.sayhi() # 调用这个对象(属于类)的方法
print("[%s],[%s]"%(D1.d_type,D1.home)) # 调用这个对象(属于类)的属性(变量)
print("上述两个实例的公共属性所在的地址空间都是",id(D1.d_type),id(D2.d_type))
# 上述两个实例的公共属性所在的地址空间都是 4317187696 4317187696
Dog.d_type = "藏獒" # 在类定义体以外修改公共属性(所有类都变)
print("[%s],[%s]"%(D1.d_type,D2.d_type))
D1.d_type = "二哈" # 在类定义体以外修改实例化后的对象的公共属性(只有该对象的公共属性变)
print("[%s],[%s]"%(D1.d_type,D2.d_type))
# def __init__(self, name, age): # 这样传入时,内存释放,实例化后的对象并没有name, age这两个属性
# print("[%s],[%s]"%(D1.name(),D2.name)) 会报错
四、类的公共属性
- 创建一个字典类型的变量
class People:
# 1、公有属性(可以在类定义体外整体的修改)
nationlity = "Chinese"
# 2、类初始化函数,定义实例属性(可以每个实例化后的对象单独修改)
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
# 实例化类,创建对象
P1 = People("XXX",22,"W")
P2 = People("ZZZ",23,"M")
# 理论上讲,公共属性是所有实例共享类定义体的同一块内存,公共属性只能通过[类.公共属性]这样去整体修改
# 但是实际上,是允许每个实例对象单独去修改自己的公共属性的,这样时,相当于给这个实例的公共属性开辟一个内存空间,而原来类定义体的公共属性并没有改变
People.nationlity = "England" # 通过[类.公共属性]去修改,结果是所有实例的公共属性都变化
print(P1.nationlity,P2.nationlity)
P1.nationlity = "Chinese" # 通过[实例.公共属性]去修改,结果是只有该实例的公共属性变化
print(P1.nationlity,P2.nationlity)
五、对象的交互
- 创建一个字典类型的变量
class Dog: # 定义一个类:狗类
role = "dog" # 每个狗(实例化后)都是狗类(角色)
# 私有属性
def __init__(self, name, breed, attack_val):
self.name = name
self.breed = breed
self.attack_val = attack_val
self.life_val = 100
def bite(self, person): # 这里传入的person也是一个对象
person.life_val -= self.attack_val
print("狗[%s]咬了人[%s]一口,人掉血[%s],还有血量[%s]..."%(self.name,
person.name,
self.attack_val,
person.life_val
))
class Person:
role = "person"
def __init__(self, name, sex, attack_val):
self.name = name
self.sex = sex
self.attack_val = attack_val
self.life_val = 100
def hit(self, dog):
dog.life_val -= self.attack_val
print("人[%s]打了狗[%s]一棍,狗掉血[%s],还有血量[%s]..."%(self.name,
dog.name,
self.attack_val,
dog.life_val
))
Dog1 = Dog("XXX","二哈",10)
Per1 = Person("ZZZ","男",90)
Per1.hit(Dog1)
六、依赖关系以及关联关系
# 依赖关系是不同的实例属于不同的类,但是存在依赖的关系
class Dog:
def __init__(self, name, age, breed, master):
self.name = name
self.age = age
self.breed = breed
self.master = master # 是一个对象
self.sayhi() # 在初始化的时候调用自己的方法
def sayhi(self):
print("Hi, I'm %s, a %s dog, my master is %s."%(self.name, self.breed, self.master.name))
class Person:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def walk_dog(self, dog):
print("主人[%s]带着狗狗[%s]去溜溜"%(self.name,dog.name))
per1 = Person("ZZZ",23,"男")
dog1 = Dog("XXX",22,"二哈",per1) # noticed:传入的是一个对象
#------------------------------------------------------------------------------------------------------------------------------------
'''关联关系'''
# 关联关系是不同的实例属于同一个类,但是存在关联的关系
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
self.parter = None # 应该是一个对象, 代表 另一半
def do_some_thing(self):
pass
p1 = People("XXX",22,"Woman")
p2 = People("ZZZ",23,"Man")
# 方法一:
p1.parter = p2
p2.parter = p1
print("%s的男朋友是%s"%(p1.name,p1.parter.name))
# 方法二:
# 在7中
七、关联关系(方法2)
- 创建一个字典类型的变量
class Relationship:
def __init__(self):
# 字典类型,里边放了两个对象
self.couple = {"Woman":None,
"Man":None
}
def make_couple(self,Woman,Man): # 传入的是对象
self.couple["Woman"] = Woman
self.couple["Man"] = Man
print("%s和%s确定了男女关系"%(Woman.name,Man.name))
def Get_Parter(self,People):
if People.sex == "Woman":
return self.couple["Man"] # 返回的是一个对象
elif People.sex == "Man":
return self.couple["Woman"] # 返回的是一个对象
else:
print("傻逼你没有对象")
def Break_up(self):
print("%s和%s正式分手了,江湖再见..."%(self.couple["Man"].name,self.couple["Woman"].name))
self.couple["Woman"] = None
self.couple["Man"] = None
class People:
def __init__(self, name, age, sex, Relationship):
self.name = name
self.age = age
self.sex = sex
self.Relationship = Relationship # 应该是一个对象, 代表 另一半
def do_some_thing(self):
pass
relation = Relationship() # 实例化一个关系(对象)
p1 = People("XXX",22,"Woman",relation)
p2 = People("ZZZ",23,"Man",relation)
relation.make_couple(p1,p2)
print("%s的男朋友是%s"%(p1.name,p1.Relationship.Get_Parter(p1).name))
p1.Relationship.Break_up()
print("%s的男朋友是%s"%(p1.name,p1.Relationship.Get_Parter(p1)))
八、组合关系
由一堆组件构成一个完整的整体,组件本身相互独立,但是又不能自己运行,必须和宿主组合在一起,运行
class Dog:
role = "dog" # 每个狗(实例化后)都是狗类(角色)
def __init__(self, name, breed, attack_val):
self.name = name
self.breed = breed
self.attack_val = attack_val
self.life_val = 100
def bite(self, person): # 这里传入的person也是一个对象
person.life_val -= self.attack_val
print("狗[%s]咬了人[%s]一口,人掉血[%s],还有血量[%s]..."%(self.name,
person.name,
self.attack_val,
person.life_val
))
class Weapon:
# 定义几个方法:
def stick(self, obj):
"""打狗棒"""
self.name = "打狗棒"
self.attack_val = 40
obj.life_val -= self.attack_val
self.print_log(obj) # 调用类方法
def knife(self, obj):
"""屠龙刀"""
self.name = "屠龙刀"
self.attack_val = 80
obj.life_val -= self.attack_val
self.print_log(obj) # 调用类方法
def gun(self, obj):
"""AK47"""
self.name = "AK47"
self.attack_val = 100
obj.life_val -= self.attack_val
self.print_log(obj) # 调用类方法
def print_log(self,obj):
print("[%s]被[%s]攻击了,掉血[%s],还剩血量[%s]..."%(obj.name,self.name,self.attack_val,obj.life_val))
class Person:
role = "person"
def __init__(self, name, sex):
self.name = name
self.sex = sex
self.Weapon = Weapon() # 在Person这个类中直接对于Weapon这个类进行实例化
self.life_val = 100
def hit(self, dog):
dog.life_val -= self.attack_val
print("人[%s]打了狗[%s]一棍,狗掉血[%s],还有血量[%s]..."%(self.name,
dog.name,
self.attack_val,
dog.life_val
))
per1 = Person("ZZZ","M")
dog1 = Dog("XXX","二哈",30)
dog1.bite(per1)
per1.Weapon.stick(dog1)
九、继承
# 父类:
class Animal:
a_type = "哺乳动物"
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def Eatting(self):
print("%s is eatting..."%(self.name))
# 子类 :子类将继承父类所有的属性和方法
class Person(Animal): # 继承Animal父类
a_type = "哺乳高等动物"
def __init__(self, name, age, sex, hobbie):
# Animal.__init__(self, name, age, sex) # 作用同上
# super(Person, self).__init__(name, age, sex) # 作用同上
# super().__init__(name, age, sex) # 作用同上
# 表示继承父类属性
super(Person, self).__init__(name, age, sex)
self.hobbie = hobbie
def Talking(self):
print("%s is Talking...."%(self.name))
# 重写父类的方法
def Eatting(self):
print("%s正在优雅的吃东西"%(self.name))
p1 = Person("张辉",22,"男","女人")
p1.Talking()
p1.Eatting()
十、多继承
# 多继承Multiple Inheritance
class ShenXian:
'''神仙类'''
def fly(self):
print("神仙会飞....")
def fight(self):
print("神仙在打架....")
class Monkey:
def eat_peach(self):
print("猴子都喜欢吃桃子....")
def fight(self):
print("猴子在打架....")
class MonkeyKing(ShenXian, Monkey): # 相同的方法时,继承第一继承人的方法ShenXian
def Play_Goden_Stick(self):
print("孙悟空玩金箍棒....")
# 实例化
sxz = MonkeyKing()
sxz.eat_peach()
sxz.fly()
sxz.Play_Goden_Stick()
sxz.fight()
十一、封装
# 封装:把一些重要的实例的数据(不想被外部访问或者修改的数据)通过一些方法进行封装起来,但是这个数据还存在
# 把它变成私有变量,加两个下划线
# 私有变量只读
from time import clock_settime
class Person():
def __init__(self, name, age):
self.name = name # 实例变量、实例属性
self.age = age # 实例变量、实例属性
self.__life_vel = 100 # 私有属性、私有变量 这样就实现了封装
# 为了可以访问私有属性,我们可以从实例所在的类内部进行访问
def Get_life_val(self):
'''这是对于私有属性的封装(方法)'''
return self.__life_vel
# 私有方法
def __breath(self):
print("%s正在呼吸呢..."%(self.name))
# 如果想访问私有方法,只能在类内部进行访问
def Quick_Breath(self):
self.__breath()
p = Person("ZZZ",23)
# print(p.__life_vel) 这样会报错,因为私有属性外部无法访问
print(p.Get_life_val())
# p.__breath() 这样也是会报错的,因为私有方法外部无法访问
p.Quick_Breath() # 这样就可以进行访问了
# 私有方法在实际上也是可以访问的: 实例名._类名+方法名(带着__)
p._Person__breath()# 一般不推荐这样用
# 私有属性在实际上也是可以访问的: 实例名._类名+属性名(带着__)
p._Person__life_val = 80
print(p.Get_life_val())
# 多态
class Dog(object):
def __init__(self) -> None:
pass
def sound(self):
print("汪汪汪...")
class Cat(object):
def __init__(self) -> None:
pass
def sound(self):
print("喵喵喵...")
def make_sound(animal_obj):
"统一调用接口"
animal_obj.sound()
d = Dog()
c = Cat()
make_sound(d)
make_sound(c)
# ----->
class Document: # 父类
def __init__(self, name):
self.name = name
def show(self): # 主动报错,要求子类必须重新该方法
raise NotImplementedError("Subclass must implement abstrat method!")
class Word(Document):
pass
# 并没有重写show方法
class Pdf(Document):
def show(self):
return 'Show pdf contents1'
pdf = Pdf("000.pdf")
print(pdf.show())
word = Word("000.word")
# word.show() 这样会报错
十二、类方法
# 1、类方法
# 类方法通过@classmethod装饰器实现,类方法和普通方法的区别是,类方法只能访问类变量,不能访问实例变量
class Dog(object):
age = 10 # 类变量、公共变量
def __init__(self, name):
self.name = name # 实例变量
@classmethod
def eatting(self): # classmethod的self传进来的是类本身,而不是实例本身
print("dog %s is eatting..."%self.name) # 看看类方法可不可以访问实例变量
@classmethod
def looking(self):
print("dog %s is looking..."%self.age) # 看看类方法可不可以访问类变量
d = Dog("asd")
# d.eatting() 报错
d.looking()
#---------->
class Student(object):
stu_num = 0 # 类变量类似于静态变量,在访问类空间时,可以看到类变量(公共变量的值)
def __init__(self, name):
self.name = name # 实例变量
# self.stu_num += 1 # 一定要主要在这里其实相当于又创建了一个与stu_num公共变量重名的实例变量
# 如果要实现计数(多少次实例化)那应该写着一行代码
Student.stu_num += 1 # 这样,每一次实例化(初始化的过程中)便可以实现对于类变量(公共变量)的改变
print("刚刚生成了一个学生(对象),叫做%s"%self.name,self.stu_num) # 查看现在一共几个学生
s1 = Student("A") # A 1
s2 = Student("B") # B 2
s3 = Student("C") # C 3
print(Student.stu_num) # 从外部访问类变量stu_num = 3
十三、静态方法
# 静态方法 @staticmethod
# 不能访问类变量,也不能访问实例变量
class Student(object):
role = "Student"
def __init__(self, name):
self.name = name
def fly(self):
print(self.name,"is flying...")
@staticmethod
def look(self): # 静态方法隔离了他跟类或者实例的任何关系,其实这个self并没有传进来,self代表的是实例本身
print(self.name,"is looking...")
s = Student("张辉")
s.fly()
# s.look() # 这样会报错 说是缺少一个变量 'self'
s.look(s) # 这样手动的进行传(实例变量进入到静态方法中是可以的)
十四、属性方法
- 把一个方法变成一个静态的属性
class Student(object):
role = "Student"
def __init__(self, name):
self.name = name
@property
def fly(self): # 把方法变成一个属性
print(self.name,"is flying...")
s = Student("ZZZ")
# s.fly() 这样会报错
s.fly # 要知道fly()方法已经被变成了一个属性,所以在调用的时候也要按照属性的格式进行调用
十五、反射
# 反射:
# 程序可以访问、检测和修改他本身状态或者行为的一种能力(自省)
# python中面向对象的反射:
# 通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
#
# 四个可以实行自省的函数
class Person(object):
role = "Person"
def __init__(self, name, age):
self.name = name
self.age = age
def walk(self):
print("Walking....")
p = Person("张辉",22)
if hasattr(p,"name2"): # hasattr去检测在实例p中有没有一个叫做name2的属性attribute
print("yes")
else:
print("No")
if hasattr(p,"name"): # hasattr去检测在实例p中有没有一个叫做name2的属性attribute
print("yes")
else:
print("No")
# !!!从外部获取指令,判断有没有,然后再调用类或者实例的方法
# 四种方法用于反射(自省)实例的属性或者方法,
# getattr 获取
# hasattr 判断
# setattr 赋值
# delattr 删除
# getattr & hasattr
a = getattr(p,"age")
print(a)
user_command = input(">>:").strip()
if hasattr(p,user_command):
func = getattr(p,user_command)
func()
# setattr
setattr(p,"sex","female") # 新建一个属性,叫sex,并且赋值叫做"female"
print(hasattr(p,"sex")) # return : Ture
print(p.sex) # return : female
# 给实例新增一个方法
def speak(self):
print(self.name,"is Speaking....")
setattr(p,"speak",speak)
p.speak(p)
# delattr
print(p.age)
delattr(p,"age")
print(p.age)
十六、文件反射
class Person(object):
role = "Person"
def __init__(self, name, age):
self.name = name
self.age = age
def walk(self):
print("Walking....")
p = Person("张辉",22)
# 如何反射一个文件下指定字符串对象的属性或者方法
print(__name__) # 结果是__main__
if __name__ == "__main__": # 只有在被别的模块(文件.py)导入的时候这个判断才有意义
print("yes,执行程序")
# 本模块(文件.py)在被别的模块(文件.py)导入的时候,__name__等于模块名,也就是"17"
import sys
# for k,v in sys.modules.items():
# print(k,v)
print(sys.modules["__main__"]) # 这个玩意就是本模块(文件.py)
#在本模块之前已经定义了一个p对象
mod = sys.modules["__main__"]
if hasattr(mod,"p"):
o = getattr(mod,"p") #此时o就是p这个对象
print(o)
o.walk()
# 上述操作也可以在不同模块间进行,导入方法也可以,并不是只限于类对象实例啥的
十七、动态加载模块指令
# 动态加载模块指令(热加载,在运行的过程中加载进来)
# 就是有一个字符串,然后我们将这个字符串对应的模块名导入进来
__import__("15") # 这个一般是解释器用的,导入15.py这个模块并执行
# python官方建议这样使用:
import importlib
importlib.import_module("15")
# ----->
class User(object):
def login(self):
print("欢迎来到登陆界面...")
def register(self):
print("欢迎来到注册页面...")
def save(self):
print("欢迎来到存储页面...")
u = User()
while True:
user_cmd = input(">>:").strip()
if hasattr(u, user_cmd):
func = getattr(u,user_cmd)
func()
十八、new方法
# new方法
# 注意:__new__会在__init__之前执行
# __new__是用来调用__init__的
# 如果重写了__new__那么需要手动调用__init__
class Student(object):
def __init__(self, name): # self代表实例或者类本身
self.name = name
print("hhhhh")
def __new__(cls, *args, **kwargs): # cls代表类本身
# __new__是负责执行__init__的
print(cls, *args, **kwargs)
# <class '__main__.Student'> XXX
# 继承一下之前的__new__(),否则无法调用__init__()
return object.__new__(cls)
p = Student("XXX")
十九、动态创建方法
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("ZZZ",22)
print(type(p))
# <class '__main__.Person'>
print(type(Person))
# <class 'type'>
def __init__(self, name, age):
self.name = name
self.age = age
dog_class = type("Dog",(object,),{"role":"dag","__init__":__init__}) # Dog是类名字,(object,)表示继承的父类,{"role":"dag","__init__":__init__}是属性和方法,采用健值对的方式
# dog_class类的变量名
print(dog_class)
# <class '__main__.dog'>
d = dog_class("mjj",22)
print(d.role) # dag
总结
提示:没有总结,哈哈哈哈。