九 Python面向对象
1. 面向对象与面向过程
1-1. 介绍
面向对象编程:Object Oriented Programming,简称OOP,是一种程序设计方法。
1-2. 概念及术语
术语 | 概念及介绍 |
---|---|
类(Class) | 用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对 象所共有的属性和方法。其中的对象被称作类的实例。 |
实例 | 也称对象。通过类定义的初始化方法,赋予具体的值,成为一个"有血有肉 的实体"。 |
实例化 | 创建类的实例的过程或操作。 |
实例变量 | 定义在实例中的变量,只作用于当前实例。 |
类变量 | 类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。 |
数据成员 | 类变量、实例变量、方法、类方法、静态方法和属性等的统称。 |
方法 | 类中定义的函数 |
静态方法 | 不需要实例化就可以由类执行的方法 |
类方法 | 类方法是将类本身作为对象进行操作的方法。 |
方法重写 | 如果从父类继承的方法不能满足子类的需求,可以对父类的方法 进行改写,这个过程也称override。 |
封装 | 将内部实现包裹起来,对外透明,提供api接口进行调用的机制。 |
继承 | 即一个派生类(derived class)继承父类(base class)的变量和方法。 |
多态 | 根据对象类型的不同以不同的方式进行处理。 |
1-3. 区别
面向过程:根据业务逻辑从上到下写代码
面向对象:将数据与函数绑定到一起,进行封装。减少重复代码的重写过程
1-4. 示例参考
示例1:面向过程
def stu_info(name,age,gender):
print(name,age,gender)
stu_info("oldli","18","male")
stu_info("ellen","18","male")
stu_info("bruin","18","male")
示例2:面向对象
class Students(object):
def stu_info(self,name, age, gender):
print(name, age, gender)
s = Students()
s.stu_info("oldli","18","male")
s.stu_info("ellen","18","male")
s.stu_info("bruin","18","male")
2. 面向对象之(类)
2-1. 介绍
类是抽象的模板,用来描述具有相同属性和方法的对象的集合,比如 Animal类。
类名通常采用驼峰式命名,尽量让字面意思体现出类的作用。
2-2. 结构
Python使用class关键字来定义类,结构如下:
class 类名(object): # object 可有可无
def 方法名(self,参数): # 行为
pass
name = 类名() # 定义一个实例对象
name.方法名(参数) # 调用
3. 面向对象之 (self)
3-1. 介绍
self 形参
self 是对象本身,也就是说,当创建的对象是谁时,self就是谁
3-2. 示例参考
class Student(object):
def test(self):
# print(self)
pass
oldli = Student() # 实例化对象
print(oldli)
oldli.test()
Chy = Student() # 实例化对象
print(Chy)
Chy.test() # 调用类
# 输出结果
#<__main__.Student object at 0x03955190>
#<__main__.Student object at 0x039552C8>
class Student(object):
def info(self):
print(self.name,self.age)
marshal = Student()
marshal.name = "marshal"
marshal.age = "18"
# print(marshal)
marshal.info() # 输出结果 marshl 18
xiaoming = Student() # 实例化对象
xiaoming.name = "xiaoming"
xiaoming.age = "22"
# print(marshal)
xiaoming.info() # 输出结果 xiaoming 22
- 当只有一个变量,其它相同时,可以参考这个
class Students(object):
def stu_info(self,name):
print(name, self.age, self.gender)
s = Students() # 实例化对象
s.age = "18"
s.gender = "male"
s.stu_info("oldli")
s.stu_info("ellen")
s.stu_info("bruin")
'''
输出结果:
oldli 18 male
ellen 18 male
bruin 18 male
'''
4. 面向对象之 init 魔法方法
4-1. 介绍
# 构造方法(初始化方法)
def __init__(self):
pass
# 特殊意义
创建对象的同时,通过对象执行这样的一个方法,叫做构造方法
4-2. 示例参考
class students(object):
def __init__(self,age,gender):
#属性
self.age = age
self.gender = gender
self.addr = "ChongQing"
# 打印信息
def stu_info(self,name):
print(name,self.age,self.gender,self.addr)
s = students() # 实例化对象
s.stu_info("oldli")
s.stu_info("enlen")
s.stu_info("bruin")
# 输出结果:
# oldli 18 male ChangSha
# ellen 18 male ChangSha
# bruin 18 male ChangSha
5. 面向对象之 str 魔法方法
5-1. 介绍
tips: 使用了该函数,一定返回字符串;如果返回出错,可以
定义的 str
def __str__(self):
pass
# 1. return 关键字 将我们的信息直接返回对象
# 2. 只能时str 如果非字符串 str() 强转
5-2. 示例参考
class People(object):
def __init__(self):
self.age = 18
self.name = "zero"
self.hobby = "play game"
def __str__(self):
return str({"name":self.name,"age":self.age})
# return 返回的多个值 元组
# 一定返回字符串
zero = People()
print(zero) # 输出结果: {'name':'zero',
6. 练习
‘’‘只有当年龄>0的时候才返回出来,否则默认为0岁’’’
class People(object):
def __init__(self): # 初始化参数
self.age = 0
def set_age(self,new_age): # 判断
if new_age >= 0 and new_age <=120:
self.age = new_age
elif new_age > 120:
self.age = 0
else:
# abs()取绝对值的内置方法
self.age = abs(new_age)
def get_age(self):
return self.age
xiaoming = People() # 实例化对象
xiaoming.set_age(10) # 调用函数
print(xiaoming.get_age())
# 输出结果为 10
7. 私有属性与方法
7-1. 介绍
在类中,不希望外部去访问我的属性。
格式:
# 私有属性 -->__属性名():
7-2. 私有属性示例参考
# 定义一个类
class People(object):
def __init__(self): # 初始化参数
self.__age = 18 # 私有属性,外部访问不了
self.name = zero
def get_age(self): # 可从内部调用私有属性
print(self.__age)
def set_age(self,age):
self.__age = age
zero = People() # 实例化对象
print(zero.name) # 打印取出名字 输出结果 zero
print(zero.__age) # 会报错,no attribute 。 不能直接从外部调用私有的属性(__age)
zero.get_age() # 调用get_age 方法获取私有属性 输出结果18
zero.set_age(22) # 重新传入参数
zero.get_age() # 输出结果 22
print(zero.__dir__()) # 查看对象的方法跟属性
7-3. 私有方法示例参考
定义私有方法
class Demo(object): # 定义一个类
def test1(self):
print("test1:)
def __test2(self):
print("test2")
d = Demo() # 实例化对象
d.test1() # 输出结果为 test1
d.__test2() # 报错,不能调用
8. 成员-方法与属性
8-1. 示例1 静态属性
class Province(object):
country = "中国" # 类属性, 静态属性 对象, 类来调用
def __init__(self,name):
self.name = name
def print_info(self):
print(Province.country,self.name) # 静态属性调用 类名.静态属性名
guangdong = Province("广东")
chongqing = Province("重庆")
guangdong.print_info() # 输出结果 中国广东
chongqing.print_info() # 输出结果 中国重庆
- 实例方法:对象需要保存的一些值,执行某功能时,需要使用对象中的值
静态方法:跟我们在函数外部定义独立的方法没有什么区别,但是有的时方便维护。不需要创建对象 直接访问,不需要self参数。调用 通过类调用
类方法: 保存在类中 由类直接调用 cls–>当前类
class Demo(object):
def __init__(self):
self.name = "zero"
def test(self):
print(self.name)
@staticmethod # 静态方法,等同于上面的
def test1(name):
print(name)
@classmethod
def class_md(cls):
print(cls)
d = Demo() # 实例化对象
d.test() # 输出结果 zero
Demo.test1("王先生") # 输出结果 王先生 调用了静态属性@staticmethod
d.test1("小周") # 输出结果 小周
Demo.class_md() # <class '__main__.Demo'>
8-2. 在类中如何实现当前格式化时间
- 面向过程
import time
def show_time():
print(time.strftime("%H:%M:%S",time.localtime()))
show_time() # 输出结果, 当前时间
- 面向对象
import time
class TimeTest(object):
@staticmethod
def show_time():
print(time.strftime("%H:%M:%S",time.localtime()))
nowtime = Timetest()
TimeTest.showtime() # 输出结果, 当前时间
8-3. property
8-3-1. 介绍
可以将类的方法变为属性
8-3-2. 示例参考
class Demo(object):
def __init__(self):
self.name = "zero"
@property # 将方法变为属性
def test(self):
print(self.name)
return "test"
@test.setter # d.test = "456"
def test(self,nums):
print(nums)
@test.deleter
def test(self):
print(1111)
d = Demo() # 实例化对象
print(d.name)
res = d.test
print(res)
d.test = "456" # 想要改变
del d.test
- 制作翻页效果
class Page(object):
def __init__(self,current_page):
try:
p = int(current_page)
except Exception as e: # 万能异常捕获
p = 1
self.page = p
@property
def start(self):
start = (self.page-1)*10
return start
@property
def end(self):
end = self.page * 10
return end
li = list(range(100))
while True:
p = int(input("请输入要查看的页码:"))
page = page(p) # 实例化对象
print(li[page.start:page.end])
9. 函数的继承
9-1. 介绍
创建新类的方式,新类可以继承一个或者多个父类;
作用:避免重复造轮子
新式类 继承object
经典类 不继承object
tips:
如果调用的是继承的父类中的方法,可以在这个公有方法中访问父类中的私有属性和私有方法;
但是如果在子类中实现了一个公有方法,那么这个方法是不能够调用继承的父类中的私有方法和私有属性
class Father(object):
def __init__(self):
self.name = "amy"
self.__age = 18
def __test(self):
print("__test")
def test1(self):
print(self.__age)
class Son(Father):
# def __init__(self):
# print("Son")
# super().__init__()
def test3(self):
# print(self.__age)
self.__test()
def __test(self):
print("__test")
s = Son()
print(s.name) # amy
# print(s.__age) # 私有属性不会被继承
# s.__test() #私有方法不会被继承
# s.test1()
s.test3() # __test
9-2. 示例
class GrandFather(object):
def sleep(self):
print("睡10个小时")
class Father(GrandFather): # 父类 基类
def run(self):
print("我会跑")
def eat(self):
print("我会吃")
class Son(Father):
def study_python(self):
print("我学python")
s = Son()
# 子类没有, 就往父类中去找
s.run() # 输出结果 我会跑
s.study_python() # 输出结果 我学python
# 父类没有 就会往父类的父类中去找
s.sleep() # 输出结果 睡10个小时
9-3. 多继承
示例:
class GrandFather(object):
def sleep(self):
print("GrangF睡觉")
class Father(GrandFather):
def run(self):
print("Father会跑")
class Father1(Father):
def run(self):
print("Father1会跑")
def sleep(self):
print("Father1睡觉")
class Son(Father,Father1):
pass
s = Son()
s.run()
s.sleep() # C3
# print(Son.__mro__) # 可以查看调用顺序
tips:
- 左边优先
- 当左边父类的父类,有该方法。右边父类有该方法。左边一条路走到底
- 他们有一个根,根最后执行
10. 函数重写
10-1. 示例
'''
重写的同时并且执行父类中的方法
'''
class GrandFather(object):
def sleep(self):
print("睡10个小时")
class Father(GrandFather):
def run(self):
print("我会跑")
def eat(self):
print("我会吃")
class Son(Father):
def study_python(self):
print("我学python")
def sleep(self):
print("我睡8个小时")
#super(Son,self).sleep() # 下面的完整版
super().sleep() # 效果同上
#GrandFather.sleep(self) # 效果同上
s = Son()
s.sleep() # 输出结果 我睡8个小时 睡10个小时
总结:
- 继承机制 深度优先 先从自己找 自己找不到 就往父类找
- 重写 防止执行父类的该方法
- self 都指当前实例化的对象
- 既想要继承父类当中方法 又想拓展新的东西
4.1 super(cls,self).父类中的方法(para)
4.2 父类名父类中的方法(self,para)
11. 多态
示例:
class Person(object):
def print_info(self):
print("我是个人")
class Girl(Person): # 继承
def print_info(self):
print("我是zero")
def info(travel): # 定义一个函数
travel.print_info()
zero = Person() # 实例化对象
info(zero) # 我是个人
zero1 = Girl() # 实例化对象
info(zero1) # 我是zero
12. 面向对象之魔法方法
12-1. 魔法方法
- doc
tips:
当函数中有多个注释时,只会打印第一个注释
# str()
# print(str().__doc__)
class Demo(object):
'''
我是Demo的注释
'''
'我有一个构造方法'
"我....."
def __init__(self):
pass
d = Demo()
print(d.__doc__) # 输出结果:我是demo的注释
- del
tips:
只有等到对象全部释放,才会主动触发__del__
class Demo:
def __del__(self):
print("好惨,我被回收了")
d = Demo()
d1 = d
print("-"*20)
del d
del d1
print("-"*20)
'''
输出结果:
--------------------
好惨,我被回收了
--------------------
'''
- call
tips:
一个实例,也可以变成一个可调用的对象
class Demo(object):
def __call__(self,*args,**kwargs):
print("我可以调用了哟")
d = Demo()
d() # 'Demo' object is not callable # 输出结果: 我可以被调用了哟
# str()
- dict 查看类或者对象的成员 字典
dict 更像__dir__的一个子集
class Demo(object):
gender = "female"
def __init__(self):
self.name = "zero"
self.__age = 18
def test(self):
print("test")
d = Demo()
d.test()
print(d.__dict__) # dict 查看对象中的实例属性
print(Demo.__dict__) # 查看类中的成员 -->类属性与行为
print(d.__dir__()) # 列表 查看对象的 -->成员
print(Demo.__dir__(d))
print(d._Demo__age)
12-2. new方法
12-2-1. 介绍
new 在类准备自身实例化时调用的
new 静态方法 创建对象
init 实例方法,对象自动调用的方法
12-2-2. 示例
class Demo(object):
def __init__(self):
print("__init__")
# 如果我们这个类中没有new,会创建对象的时候,会自动执行父类中的new方法
def __new__(cls,*args,**kwargs):
return super().__new__(cls) # 传入别的类名时,不会调用__init__方法
d = Demo()
# 1.创建对象 __new__
# 2.调用__init__方法
# 3.返回对象引用
12-3. 单例模式
12-3-1. 介绍
永远只使用一份对象 (重点:记录日志在logger)
对象不存在时候 -->创建对象
对象存在 -->永远只返回当前创建对象
12-3-2. 示例
class Demo(object):
flag = None # 标志
# 创建对象 __new__
def __new__(cls,*args,**kwargs):
# return super().__new__(cls)
if cls.fflag is None:
cls.flag = super().__new__(cls):
return cls.flag
else:
return cls.flag
d = Demo()
print(id(d))
d1 = Demo()
print(id(d1)) # 输出两个相同的ID地址
12-4. reflect 反射
12-4-1. 会用到的函数
- getattr 函数 获取属性值或者获取方法变量的地址
getattr(py文件名,输入的名字)
getattr(views,ipt)
- hasattr 函数 判断是否有此变量,返回bool 值