代码获取:https://github.com/qingxuly/hsp_python_course
完结版:Python基础学习(完结版)
面向对象编程(基础)
类与对象
类与实例的关系
- 类与实例的关系示意图
快速入门—面向对象的方式解决养猫问题
# 定义一个猫类,age, name, color 是属性,或者称为成员变量
# Cat 类 就是你自己定义的一个新类型
# 定义 Cat 类
class Cat:
# age, name, color 是属性
age = None # 年龄属性
name = None # 名字属性
color = None # 颜色属性
# 通过 Cat 类,创建实例(实例对象/对象)
cat1 = Cat()
# 通过对象名.属性名 可以给各个属性赋值
cat1.name = "小白"
cat1.age = 2
cat1.color = "白色"
# 通过对象名.属性名,可以访问到属性
print(f "cat1 的信息为:name: {cat1.name} age {cat1.age} color {cat1.color}")
# 小结:通过上面的 oop 解决问题,可以更好地管理小猫的属性
类和对象的区别和联系
- 类是抽象的,概念的,代表一类事物,比如人类,猫类,…,即它是数据类型。
- 对象是具体的,实际的,代表一个具体事物,即是实例。
- 类是对象的模板,对象是类的一个个体,对应一个实例。
对象在内存中的存在形式
- 内存分析图
属性/成员变量
- 基本介绍
- 类中定义的属性(变量),我们成为:成员变量。
- 属性是类的一个组成部分,一般是字符串、数值,也可以是其它类型(list、dict等),比如前面定义Cat类的name、age就是属性。
- 注意事项和细节说明
- 属性的定义语法同变量,实例:
属性名 = 值
,如果没有值,可以赋值None。- None 是python的内置常量,通常被用来代表空值的对象。
- 如果给属性指定的有值,那么创建的对象属性就有值。
- 属性的定义语法同变量,实例:
# 定义 Cat 类
class Cat:
# age, name, color 是属性
age = 2 # 年龄属性
name = "小白" # 名字属性
color = "白色" # 颜色属性
# 创建对象
cat1 = Cat()
print(f "age:{cat1.age}, name:{cat1.name}, color:{cat1.color}")
类的定义和使用
- 如何定义类
class 类名:
属性...
行为...
# class 是关键字,表示后面定义的是类。
# 属性:定义在类中的变量(成员变量)
# 行为:定义在类中的函数(成员方法)
- 如何创建对象
对象名 = 类名()
# 举例
cat = Cat()
- 如何访问属性
对象名.属性名
# 举例
cat.name
对象的传递机制
class Person:
age = None
name = None
p1 = Person()
p1.age = 10
p1.name = "小明"
p2 = p1
print(p2.age)
print(f "id(p1.name): {id(p1.name)}, id(p2.name): {id(p2.name)}")
a = Person()
a.age = 10
a.name = "jack"
b = a
print(b.name)
b.age = 200
b = None
print(a.age)
print(b.age) # AttributeError: 'NoneType' object has no attribute 'age'
对象的布尔值
- Python一切皆为西,所有对象都有一个布尔值,可以通过内置函数
bool()
可以获取对象的布尔值。 - 下面对象的布尔值为False
- False、数值0、None、空字符串、空列表、空字典、空元组、空集合。
print("---下面对象的布尔值为 False---")
print(bool(False))
print(bool(0))
print(bool(None))
print(bool(""))
print(bool([]))
print(bool(()))
print(bool({}))
print(bool(set()))
# 因为所有对象都有一个布尔值,所有有些代码直接使用对象的布尔值做判断
content = "hello"
if content:
print(f "hi {content}")
else:
print("空字符串")
lst = [1, 2]
if lst:
print(f "lst {lst}")
else:
print("空列表")
成员方法
基本介绍
- 类出来有一些属性外,还会有一些行为,比如人类有年龄、姓名等属性,我们人类还有一些行为,比如:可以说话、跑步、…,通过学习,还可以做算术题。这时就要用成员方法才能完成。
class 类名:
属性...
行为...
# 类中定义的行为(函数),我们成为:成员方法/方法
成员方法的定义和使用
- 成员方法的定义
- 在类中定义成员方法和前面学习过的定义函数,基本是一样的(原理和运行机制是一样的),但是还是有点不同(形式上有不同)。
def 方法名(self, 形参列表):
方法体
# 在方法定义的参数列表中,有一个 self
# self 是定义成员方法时,需要写上的
# self 表示当前对象本身
# 当我们通过对象调用方法时,self 会隐式的传入
# 在方法内部,需要使用 self,才能访问到成员变量
- 案例演示
class Person:
age = None
name = None
# 成员方法
def hi(self):
print("hi, python")
def cal01(self):
result = 0
for i in range(1, 1001):
result += i
print(f "result: {result}")
def cal02(self, n):
result = 0
for i in range(1, n + 1):
result += i
print(f "result: {result}")
def get_sum(self, n1, n2):
return n1 + n2
# 测试
p = Person()
p.hi()
p.cal01()
p.cal02(10)
print(p.get_sum(10, 20))
使用细节
- python也支持对象动态的添加方法
# 函数
def hi():
print("hi, python")
# 定义类
class Person:
age = None
name = None
def ok(self):
pass
# 创建对象 p、p2
p = Person()
p2 = Person()
# 动态地给 p 对象添加方法 m1,注意:只是针对 p 对象添加方法
# m1 是你新增加的方法的名称,由程序员指定名称
# 即 m1 方法和函数 hi 关联起来,当调用 m1 方法时,会执行 hi 函数
p.m1 = hi
# 调用 m1(即 hi)
p.m1()
print(type(p.m1), type(hi)) # <class 'function'> <class 'function'>
print(type(p.ok)) # <class 'method'>
# 因为没有动态的给 p2 添加方法,会报错
p2.m1() # AttributeError: 'Person' object has no attribute 'm1'
self
访问对象的属性/成员变量
class Cat:
name = "波斯猫"
age = 2
def info(self, name):
print(f "name: {name}") # 加菲猫
# 通过 self.属性名 可以访问对象的属性/成员变量
print(f "属性 name:{self.name}") # 波斯猫
cat = Cat()
cat.info("加菲猫")
基本介绍
- 基本语法
def 方法名(self, 形参列表):
方法体
# 在方法定义的参数列表中,有一个 self
# self 是定义方法时,需要写上的,如果不写,则需要使用 @staticmethod 标注,否则会报错
# 将方法转换为静态方法:https://docs.python.org/zh-cn/3/library/functions.html#staticmethod
class Dog:
name = "藏獒"
age = 2
def info(self, name):
print(f "name: {name}")
# @staticmethod 可以将普通方法转换为静态方法。
# 如果是一个静态方法,可以不带 self
# 静态方法的调用形式有两种:通过对象调用、通过类名调用
@staticmethod
def ok():
print("ok()...")
dog = Dog()
dog.info("德牧")
# 通过对象调用
dog.ok()
# 通过类名调用
Dog.ok()
- self 表示当前对象本身,简单的说,哪个对象调用,self 就代表哪个对象。
class Dog:
name = "藏獒"
age = 2
def hi(self):
print(f "hi self: {id(self)}")
dog2 = Dog()
print(f "dog2: {id(dog2)}")
dog2.hi()
dog3 = Dog()
print(f "dog3: {id(dog3)}")
dog3.hi()
-
当我们通过对象调用方法时,self 会隐式的传入。
-
在方法内部,要访问成员变量和成员方法,需要使用 self。
# 在方法内部,要访问成员变量和成员方法,需要使用 self。
class Dog:
name = "藏獒"
age = 2
def eat(self):
print(f "{self.name} 饿了...")
def cry(self, name):
print(f "{name} is crying")
print(f "{self.name} is crying")
self.eat()
# 不能直接调用
# eat()
dog = Dog()
# 修改 dog 对象的属性 name
dog.name = "中华田园犬"
dog.cry("金毛")
- 练习题
class Person:
name = None
age = None
def compare_to(self, other):
# 名字和年龄都一样,就返回 True,否则返回 False
return self.name == other.name and self.age == other.age
p1 = Person()
p1.name = "jack"
p1.age = 3
p2 = Person()
p2.name = "jack"
p2.age = 3
print(p1.compare_to(p2))
对象作为参数传递
- 对象的传参机制
class Person:
name = None
age = None
# 分析对象作为参数传递到函数/方法的机制
def f1(person):
print(f "②person 的地址:{id(person)}")
person.name = "james"
person.age += 1
# 创建对象 p1
p1 = Person()
p1.name = "jordan"
p1.age = 21
print(f "①p1 的地址:{id(p1)} p1.name: {p1.name} p1.age: {p1.age}")
f1(p1)
print(f "③p1 的地址:{id(p1)} p1.name: {p1.name} p1.age: {p1.age}")
- 示意图
作用域
- 在面向对象编程中,主要的变量就是成员变量(属性)和局部变量。
class Cat:
# 属性(成员变量)
name = None
age = None
# n1, n2, result 就是局部变量
def cal(self, n1, n2):
result = n1 + n2
print(f "result = {result}")
- 我们说的局部变量,一般指在成员方法中定义的变量。
- 作用域的分类:属性作用域为整个类,比如 Cat类:cry eat 等方法使用属性。
class Cat:
# 属性
name = None
age = None
# n1, n2, result 就是局部变量
def cal(self, n1, n2):
result = n1 + n2
print(f "cal() 使用属性 name {self.name}")
def cry(self):
print(f "cry() 使用属性 name {self.name}")
def eat(self):
print(f "eat() 使用属性 name {self.name}")
cat = Cat()
cat.cal(10, 20)
cat.cry()
cat.eat()
- 局部变量:也就是方法中定义的变量,作用域是它在方法中。
- 属性和局部变量可以重名,访问时带上 self,表示访问的属性,没有带 self,则是访问局部变量。
class Cat:
# 属性
name = None
age = None
def hi(self):
name = "皮皮"
print(f "name is {name}")
print(f "self.name is {self.name}")
cat = Cat()
cat.name = "小咪"
cat.hi()
构造方法
基本介绍
def __init__(self, 参数列表):
代码...
- 在初始化对象时,会自动执行
__init__
方法 - 在初始化对象时,传入的参数,自动传递给
__init__
方法。 - 构造方法是python预定义的,名称是
__init__
,注意init
前后都有两个_
。
# 在初始化对象时,会自动执行 __init__ 方法
class Person:
name = None
age = None
# 构造方法/构造器
# 构造方法是完成对象的初始化任务
def __init__(self, name, age):
print(f "__init__ 执行了 {name} {age}")
# 把接收到的 name 和 age 赋给属性(name, age)
# self 就是你当前创建的对象
print(f "self id: {id(self)}")
self.name = name
self.age = age
# 创建对象
p1 = Person("kobe", 20)
print(f "p1 id: {id(p1)}")
print(f "p1 的信息: {p1.name} {p1.age}")
p2 = Person("tim", 30)
print(f "p2 id: {id(p2)}")
print(f "p2 的信息: {p2.name} {p2.age}")
注意事项和使用细节
- 一个类只有一个
__init__
方法,即使你写了多个,也只有最后一个生效。
class Person:
name = None
age = None
def __init__(self, name, age):
print(f "__init__ 执行了... 得到了{name} {age}")
self.name = name
self.age = age
def __init__(self, name):
print(f " __init__ 执行了~~ 得到了{name}")
self.name = name
# TypeError: Person.__init__() takes 2 positional arguments but 3 were given
# p1 = Person("tim", 20)
# 后面的 __init__()生效
p1 = Person("tim")
print(f "p1 的 name ={p1.name} age ={p1.age}")
- python实现多个构造方法。
- python可以动态的生成对象属性。
# 为了代码简洁,我们也可以通过 __init__ 动态的生成对象属性
# python 可以动态的生成对象属性。
class Person:
def __init__(self, name, age):
print(f "__init__ 执行了... 得到了{name} {age}")
# 将接收到的 name 和 age 赋给当前对象的 name 和 age 属性
# python 支持动态生成对象属性
self.name = name
self.age = age
p1 = Person("tim", 30)
print(f "p1 的 name ={p1.name} age ={p1.age}")
- 构造方法不能有返回值。
class Person:
def __init__(self, name, age):
print(f "__init__ 执行了... 得到了{name} {age}")
self.name = name
self.age = age
return "hello" # TypeError: __init__() should return None, not 'str'
练习
1、编写A01,定义方法max_lst,实现求某个float 列表list = [1.1, 2.9, -1.9, 67.9]的最大值,并返回。
# 1、编写 A01,定义方法 max_lst,实现求某个 float 列表 list = [1.1, 2.9, -1.9, 67.9] 的最大值,并返回。
"" "
思路分析
1. 类名:A01
2. 方法:max_lst(self, lst), 功能:返回列表的最大值
"" "
class A01:
def max_lst(self, lst):
return max(lst)
# 测试
a = A01()
print("最大值:", a.max_lst([1.1, 2.9, -1.9, 67.9]))
2、编写类Book,定义方法update_price,实现更改某本书的价格,具体:如果价格>150,则更改为150,如果价格>100,更改为100,否则不变。
# 2、编写类 Book,定义方法 update_price,实现更改某本书的价格,具体:如果价格 > 150,则更改为 150,如果价格 > 100,更改为 100,否则不变。
"" "
思路分析:
类名:Book
属性:name, price
构造器:__init__(self, name, price)
方法:update_price, 功能:如果价格 > 150,则更改为 150,如果价格 > 100,更改为 100,否则不变。
"" "
class Book:
def __init__(self, name, price):
self.name = name
self.price = price
def update_price(self):
# 如果价格 > 150,则更改为 150,如果价格 > 100,更改为 100,否则不变。
if self.price > 150:
self.price = 150
elif self.price > 100:
self.price = 100
def info(self):
# 输出书籍的信息
print(f "书的信息:{self.name} {self.price}")
book = Book("天龙八部", 99)
book.info()
book.update_price()
book.info()
3、定义一个圆类Circle,定义属性:半径,提供显示圆周长功能的方法,提供显示圆面积的方法。
# 定义一个圆类 Circle,定义属性:半径,提供显示圆周长功能的方法,提供显示圆面积的方法。
"" "
思路分析:
类名:Circle
属性:radius
构造器:__init_(self, radius)
方法:len(self) 显示圆周长
方法:area(self) 显示圆面积
"" "
import math
class Circle:
def __init__(self, radius):
self.radius = radius
def len(self):
len = 2 * math.pi * self.radius
print("周长:", round(len, 2))
def area(self):
area = math.pi * (self.radius ** 2)
print("面积:", round(area, 2))
# 测试
circle = Circle(5)
circle.len()
circle.area()
4、编程创建一个Cal计算类,在其中定义2个成员变量表示两个操作数,定义四个方法实现求和、差、乘、商(要求除数为0的话,要提示)并创建对象,分别测试。
# 编程创建一个 Cal 计算类,在其中定义 2 个成员变量表示两个操作数,定义四个方法实现求和、差、乘、商(要求除数为 0 的话,要提示)并创建对象,分别测试
"" "
思路分析:
类名:Cal
属性:num1, num2
构造器/构造方法:__init__(self, num1, num2)
定义四个方法实现求和 def sum(), 求差 def minus(), 求积 def mul(), 求商 def div()
商(要求除数为 0 的话,要提示)
"" "
class Cal:
def __init__(self, num1, num2):
self.num1 = num1
self.num2 = num2
def sum(self):
return self.num1 + self.num2
def minus(self):
return self.num1 - self.num2
def mul(self):
return self.num1 * self.num2
def div(self):
if self.num2 == 0:
print("num2 不能为 0")
else:
return self.num1 / self.num2
cal = Cal(1, 0)
print("和 =", cal.sum())
print("差 =", cal.minus())
print("积 =", cal.mul())
print("商 =", cal.div())
5、定义Music类,里面有音乐名name,音乐时长times属性,并有播放play功能,和返回本身属性信息的方法get_info。
# 定义 Music 类,里面有音乐名 name,音乐时长 times 属性,并有播放 play 功能,和返回本身属性信息的方法 get_info
"" "
思路分析:
类名:Music
属性:name, times
构造器:__init__(self, name, times)
方法:play, get_info
"" "
class Music:
def __init__(self, name, times):
self.name = name
self.times = times
def play(self):
print(f "音乐名 {self.name} 正在播放中... 时长为 {self.times}")
def get_info(self):
return f "音乐的信息: name:{self.name} times:{self.times}"
# 测试
music = Music("月光曲", 300)
music.play()
print(music.get_info())
6、分析下列代码输出结果。
class Demo:
i = 100
def m(self):
self.i += 1
j = self.i
print("i =", self.i)
print("j =", j)
d1 = Demo()
d2 = d1
d2.m()
print(d1.i)
print(d2.i)
"" "
输出结果:
i = 101
j = 101
101
101
"" "
7、石头剪刀布游戏,0表示石头,1表示剪刀,2表示布。
import random
class Tom:
def __init__(self):
self.wins = 0
self.losses = 0
self.choices = ['石头', '剪刀', '布']
def play(self):
user_choice = int(input("请输入你的选择(0 = 石头,1 = 剪刀,2 = 布):"))
if user_choice not in [0, 1, 2]:
print("输入错误,请输入 0、1 或 2。")
return
computer_choice = random.randint(0, 2)
print(f "Tom 的选择是:{self.choices [user_choice]},电脑的选择是:{self.choices [computer_choice]}")
if user_choice == computer_choice:
print("平局!")
elif (user_choice == 0 and computer_choice == 1) or \
(user_choice == 1 and computer_choice == 2) or \
(user_choice == 2 and computer_choice == 0):
print("Tom 赢了!")
self.wins += 1
else:
print("Tom 输了!")
self.losses += 1
def show_scores(self):
print(f "Tom 的赢的次数:{self.wins},输的次数:{self.losses}")
# 使用示例
tom = Tom()
tom.play()
tom.play()
tom.show_scores()
欢迎关注我的博客,如有疑问或建议,请随时留言讨论。