二、Python面向对象(一)
面向对象
- 对象是对变量和函数的封装
- 基本代码还是封装在函数中
- 通过对象, 把函数再次封装, 可以减少函数的数量
- 即使代码很多 函数很多,可以把不同的函数放入不同的对象, 这样有效降低了对象的数量
- 类似c++,java包括python都属于面向对象的语言
类与对象
- 类
- 类是一个模板, 不能直接使用
- 类似于是一张设计图纸
- 对象
- 是通过类创建出来的
- 对象可以使用
- 方法
- 把函数封装到对象内部, 叫对象的方法(类似于函数)
- 属性
- 把变量封装到对象内部, 叫对象的属性(类似于变量)
方法与属性
- 方法是函数演化来的, 方法是用来执行的, 代表一种行为
- 属性是变量演化来的, 属性只是一个具体的值
一个案例
一个小狗叫拜登, 毛是白色的, 小狗可以汪汪叫, 可以撒泼打滚
小狗的名字叫拜登
小狗的颜色是白色
小狗的行为汪汪叫
小狗的行为撒泼打滚
对象是小狗
属性, 名字name, 值为 "拜登"
属性, 颜色color, 值为 "白色"
方法 汪汪叫 wangwang
方法 撒泼打滚 dagun
类的设计
-
设计一个类的三个要素
- 类名
- 方法
- 属性
-
设计一个人(person)类
- 属性
- 姓名name
- 年龄age
- 身高height
- 方法
- 跑run
- 吃eat
- 属性
-
person类可以设计多个对象
-
属性
- 姓名name-小明
- 年龄age-18
- 身高height-1.75
-
方法
- 跑run, 喜欢早上跑步
- 吃eat
-
person类可以设计多个对象
-
属性
- 姓名name-小美
- 年龄age-17
- 身高height-1.65
-
方法
- 跑run
- 吃eat
类与对象的关系
- 先有类, 然后才有对象
- 一定先有图纸, 然后才能按图纸盖房子
- 一个类可以创建多个对象
- 一个图纸, 可以盖多套房子
- 类中有什么属性和方法, 对象中就有什么属性和方法
- 图纸是什么样, 房子盖好了, 就什么样
- 不同的对象, 属性的值可能不一样
- 按图纸造飞机, 编号是属性, 但每架飞机的编号可能是不同的
- 按图纸造飞机, 颜色是属性, 但每架飞机的颜色可能是不同的
类的定义
class 类名: # 类名习惯用大驼峰
# 定义一个方法
def 方法名(self, 形参1, 形参2......):
pass
# 方法一定要定义在类的内部, 和类名有一个tab缩进
# 方法的第一个形参一定为self, 其他的语法与函数一致
# 定义一个类, 名字叫Dog
class Dog:
def wangwang(self): # 定义了一个方法
print("汪汪叫")
def dagun(self): # 定义了一个方法
print("满地打滚")
# 定义类和定义函数道理一样, 代码不会执行
对象的创建
对象名 = 类名() # 根据类创建一个对象
对象名.方法名() # 调用对象的方法
# 定义一个类, 名字叫Dog
class Dog:
def wangwang(self): # 定义了一个方法
print("汪汪叫")
def dagun(self): # 定义了一个方法
print("满地打滚")
# 定义类和定义函数道理一样, 代码不会执行
d = Dog() # 根据类Dog创建一个对象d
d.wangwang() # 调用对象d的wangwang方法
d.dagun() # 调用对象d的dagun方法
术语
- 实例
- 一个对象就是一个类的实例
- 对象d就是类Dog的一个实例
- 实例化
- 创建对象的过程就是实例化 d = Dog()这条语句就是d的实例化过程
d1 = Dog() # d1是Dog的实例, 这条语句就是实例化的体现
定义一个cat类
class Cat: # 定义一个Cat类
def eat(self): # 定义一个方法eat
print("吃")
def drink(self): # 定义一个方法drink
print("喝")
c1 = Cat() # 把Cat类实例化为对象c1, c1位Cat类的实例
c1.eat() # 调用对象c1的eat方法
c1.drink() # 调用对象c1的drink方法
c2 = Cat() # 把Cat类实例化为对象c2, c2位Cat类的实例
c2.eat() # 调用对象c2的eat方法
c2.drink() # 调用对象c2的drink方法
self的作用
self的第一个作用-在方法中定义属性
# 在方法内部
self.属性名 = 值
# Cat有eat和drink两个方法
# Cat有name和age两个属性
# Cat添加一个方法, set, 方法的作用是定义name和age两个属性
class Cat: # 定义一个Cat类
def eat(self): # 定义一个方法eat
print("吃")
def drink(self): # 定义一个方法drink
print("喝")
def set(self):
self.name = "小猫" # 给Cat类定义了一个属性name, 值为"小猫"
self.age = 1 # 给Cat类定义了一个属性age, 值为1
name = "猫" # 这里离的name不是属性, 是方法内部定义的一个局部变量name
age = 1 # 这里的age不是属性, 是方法内部定义的一个局部变量age
c = Cat() # 实例化
c.drink() # 调用对象的方法
c.eat() # 调用对象的方法
c.set() # 调动对象的set方法 # 因为在set方法里面有定义属性name和age的语句, 所以只有执行了set方法, 对象才会有属性
print(c.name) # 显示对象name属性的值
print(c.age) # 显示对象age属性的值
self的第二个作用-在定义属性方法之外的其他方法中使用属性
# 在其他方法中使用属性
self.属性名
# Cat有eat和drink两个方法
# Cat有name属性
# Cat添加一个方法, set, 定义name属性
class Cat: # 定义一个Cat类
def eat(self): # 定义一个方法eat
print(f"{self.name}吃") # 在eat方法中使用属性name
def drink(self): # 定义一个方法drink
print(f"{self.name}喝") # 在eat方法中使用属性name
def set(self):
self.name = "小猫" # 给Cat类定义了一个属性name, 值为"小猫"
c = Cat() # 实例化
c.set() # 因为set中定义了属性name
c.drink()
c.eat()
self的第三个作用-在一个方法内部调用另一个方法
# 一个方法内部, 调用另外一个方法
self.方法名()
class Cat: # 定义一个Cat类
def eat(self): # 定义一个方法eat
print("吃")
def my_func(self): # 定义了一个方法my_func,
self.eat() # 在方法内部调用eat方法
c = Cat() # 实例化
c.my_func()
self作用-小结
- 作用1--定义属性
- 作用2--在方法内部使用属性
- 作用3--在方法内部调用方法
- self只能在类的内部使用, 不能在类的外部使用
'''
定义cat类
有set方法, set方法中定义属性name
有eat方法, 使用属性name
定义my_func方法, 方法中调用eat方法
'''
class Cat: # 定义一个Cat类
def set(self): # 定义一个set方法
self.name = "小猫" # 定义一个name属性, 值为"小猫"
def eat(self): # 定义一个eat方法
print(f"{self.name}爱吃鱼") # 在eat方法内部使用属性name
def my_func(self): # 定义一个方法my_func
self.eat() # 在my_func方法内部调用方法eat
c = Cat() # 把类Cat实例化对象c
c.set() # 调用对象c的set方法
c.my_func() # 调用对象c的方法my_func
# cat, 有方法set, 定义属性name
# 方法eat, 使用属性name
class Cat: # 定义一个类Cat
def set(self, name): # 定义一个方法set, 有一个形参name
self.name = name # 定义一个属性name, 值等于形参name的值
def eat(self): # 定义一个eat方法
print(f"{self.name}吃")
c1 = Cat() # 把Cat实例化为对象c1
c1.set("小猫") # 调用对象c1的set方法,实参为小猫
c1.eat() # 调用c1的eat方法
c2 = Cat() # 把Cat实例化为对象c2
c2.set("懒猫") # 调用对象c1的set方法,实参为懒猫
c2.eat() # 调用c1的eat方法
''''
Cat类有两个方法, 分别是set和eat, 一个属性name, 对于cat类来讲name属性没有值
Cat类实例化了两个对象, 分别是c1和c2
c1和c2有两个方法, 分别是set和eat, 一个属性name
c1的name属性值为"小猫"
c2的name属性值为"懒猫"
c1的eat方法调用执行结果为显示"小猫吃"
c2的eat方法调用执行结果为显示"懒猫吃"
'''
初始化方法
方法名__init__
- init的前面有两个下划线, init后面有两个下划线
- 不能习惯性的写成int, init是initial前面四个字母, initial意思就是初始化的意思
- 初始化方法在对象实例化的时候自动调用, 不需要通过代码明确的调用
class Cat:
def __init__(self):
print("我是cat类的初始化方法")
c = Cat() # 实例化的时候__init__方法自动被调用
# c.__init__() 不用这样写代码, __init__方法不需要这样调用
- 初始化方法一个作用
- 在初始化方法中定义类的属性
- 在对象实例化的同时, 属性就自动定好好, 并不需要额外的提供定义属性的方法
- 一个类中的属性, 一般都是在init方法中定义, 而不是其他方法中定义
'''
定义一个cat类
有方法eat
有属性name
有属性set
'''
'''
class Cat:
def set(self): # set方法只有一个作用, 就是定义属性name
self.name = "小猫"
def eat(self):
print(f"{self.name}爱吃鱼")
c = Cat()
c.set()
c.eat() # 在调用eat方法前, 必须先调用set方法
# 类的不足, 在调用eat方法前, 必须先调用set, 使用起来不方便
'''
class Cat:
def __init__(self): # 在初始化方法总定义name
self.name = "小猫"
def eat(self):
print(f"{self.name}爱吃鱼")
c = Cat() # 实例化的时候, __init__被自动调用, 带来的好处是, 实例化的时候, 属性name会自动出现
c.eat()
带有形参的初始化方法
- 初始化方法的形参主要作用是给属性赋值的
class Cat:
def __init__(self, name): # 初始化方法的形参name
self.name = name # 属性name的值等于形参name的值
def eat(self):
print(f"{self.name}爱吃鱼")
c1 = Cat("小猫") # 实参"小猫"实际是给了初始化方法的形参name
c1.eat()
c2 = Cat("懒猫")
c2.eat()
# 一个Cat类有两个对象c1和c2, 两个对象都有name属性和eat方法
# c1的name属性值为小猫
# c2的name属性值为懒猫
初始化方法的缺省参数
class Cat:
def __init__(self, name = "小猫", age = 1):
self.name = name # 属性name的值等于形参name的值
self.age = age
def show(self):
print(f"我的名字叫{self.name}, 我今年{self.age}岁")
c1 = Cat() # __init__方法的形参name和age将采用缺省值
c1.show() # 调用对象c的show方法
c2 = Cat("肥猫") # 只有age缺省, name采用实参的值
c2.show()
c3 = Cat("肥猫", 10) # name和age都放弃缺省, 都采用实参的值
c3.show()
c4 = Cat(age = 5) # name缺省, age的值为5
c4.show()
# 以上四个对象都有name和age属性, 都有show方法
# 四个对象的name和age属性的值是不同的
dir函数
- 显示对象所有的属性和方法
dir(对象)
class Cat:
def __init__(self, name = "小猫", age = 1):
self.name = name # 属性name的值等于形参name的值
self.age = age
def show(self):
print(f"我的名字叫{self.name}, 我今年{self.age}岁")
c1 = Cat()
print(dir(c1)) # 显示一个对象所有的属性和方法
__str__方法
__str__
必须有return返回值, 返回值必须是字符串__str__
方法除了self形参外, 不能有其他的形参- 把一个对象直接放到print里面, 显示结果为
__str__
的返回值
class Cat:
def __str__(self):
return "我是Cat类的实例"
c = Cat()
print(c) # 把对象c直接放到print里显示, 显示的就是__str__方法返回的字符串
__del__方法
- 也叫销毁方法
- 对象在内存中消失的时候, 自动调用
__del__
方法除了self,没有其他形参, 也没有返回值
class Cat:
def __init__(self):
print("初始化方法调用了")
def __del__(self):
print("销毁方法调动了")
c = Cat() # 自动调用了__init__方法, 初始化方法
# c是个对象, 道理和变量一样, 由于是在函数外定义的, 所以全局的
print("程序结束")
# 到这里, 所有代码执行完了, 对象c要在内存中消失, 消失的时候, 会自动调用__del__销毁方法
# 程序的执行顺序
'''
初始化方法调用了
程序结束
销毁方法调动了
'''
设计类的基本套路
- 类的所有属性都在
__init__
方法中定义 - 类有几个属性
__init__
方法就有几个形参, 目的是为了给属性赋初值
'''
设计了一个Person, 有属性name, age和height
有方法run和eat
'''
class Person: # 定义一个Person类
def __init__(self, name, age, height):
self.name = name
self.age = age
self.height = height
def run(self):
print(f"我叫{self.name}, 今年{self.age}, 身高{self.height}, 跑步")
def eat(self):
print(f"我叫{self.name}, 今年{self.age}, 身高{self.height}, 吃饭")
p1 = Person("小明", 20, 1.75) # 实例化对象p1
p2 = Person("小美", 18, 1.65) # 实例化对象p2
p1.run() # 调用了p1的方法
p1.eat()
p2.run() # 调用了p2的方法
p2.eat()