Python基础学习(十)面向对象编程(基础)

代码获取:https://github.com/qingxuly/hsp_python_course

完结版:Python基础学习(完结版)

面向对象编程(基础)

类与对象

类与实例的关系
  • 类与实例的关系示意图
快速入门---面向对象的方式解决养猫问题
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的内置常量,通常被用来代表空值的对象。
    • 如果给属性指定的有值,那么创建的对象属性就有值。
python 复制代码
# 定义 Cat 类
class Cat:
    # age, name, color 是属性
    age = 2  # 年龄属性
    name = "小白"  # 名字属性
    color = "白色"  # 颜色属性


# 创建对象
cat1 = Cat()

print(f "age:{cat1.age}, name:{cat1.name}, color:{cat1.color}")
类的定义和使用
  • 如何定义类
python 复制代码
class 类名:
	属性...
    行为...
    
# class 是关键字,表示后面定义的是类。
# 属性:定义在类中的变量(成员变量)
# 行为:定义在类中的函数(成员方法)
  • 如何创建对象
python 复制代码
对象名 = 类名()

# 举例
cat = Cat()
  • 如何访问属性
python 复制代码
对象名.属性名

# 举例
cat.name
对象的传递机制
python 复制代码
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)}")
python 复制代码
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、空字符串、空列表、空字典、空元组、空集合。
python 复制代码
print("---下面对象的布尔值为 False---")
print(bool(False))
print(bool(0))
print(bool(None))
print(bool(""))
print(bool([]))
print(bool(()))
print(bool({}))
print(bool(set()))
python 复制代码
# 因为所有对象都有一个布尔值,所有有些代码直接使用对象的布尔值做判断
content = "hello"
if content:
    print(f "hi {content}")
else:
    print("空字符串")


lst = [1, 2]
if lst:
    print(f "lst {lst}")
else:
    print("空列表")

成员方法

基本介绍
  • 类出来有一些属性外,还会有一些行为,比如人类有年龄、姓名等属性,我们人类还有一些行为,比如:可以说话、跑步、...,通过学习,还可以做算术题。这时就要用成员方法才能完成。
python 复制代码
class 类名:
    属性...
    行为...
    
# 类中定义的行为(函数),我们成为:成员方法/方法
成员方法的定义和使用
  • 成员方法的定义
    • 在类中定义成员方法和前面学习过的定义函数,基本是一样的(原理和运行机制是一样的),但是还是有点不同(形式上有不同)。
python 复制代码
def 方法名(self, 形参列表):
    方法体

# 在方法定义的参数列表中,有一个 self
# self 是定义成员方法时,需要写上的
# self 表示当前对象本身
# 当我们通过对象调用方法时,self 会隐式的传入
# 在方法内部,需要使用 self,才能访问到成员变量
  • 案例演示
python 复制代码
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也支持对象动态的添加方法
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

访问对象的属性/成员变量
python 复制代码
class Cat:
    name = "波斯猫"
    age = 2

    def info(self, name):
        print(f "name: {name}")  # 加菲猫
        # 通过 self.属性名 可以访问对象的属性/成员变量
        print(f "属性 name:{self.name}")  # 波斯猫


cat = Cat()
cat.info("加菲猫")
基本介绍
  • 基本语法
python 复制代码
def 方法名(self, 形参列表):
    方法体

# 在方法定义的参数列表中,有一个 self
# self 是定义方法时,需要写上的,如果不写,则需要使用 @staticmethod 标注,否则会报错
# 将方法转换为静态方法:https://docs.python.org/zh-cn/3/library/functions.html#staticmethod
python 复制代码
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 就代表哪个对象。
python 复制代码
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。

python 复制代码
# 在方法内部,要访问成员变量和成员方法,需要使用 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("金毛")
  • 练习题
python 复制代码
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))

对象作为参数传递

  • 对象的传参机制
python 复制代码
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}")
  • 示意图

作用域

  • 在面向对象编程中,主要的变量就是成员变量(属性)和局部变量。
python 复制代码
class Cat:
    # 属性(成员变量)
    name = None
    age = None
    
    # n1, n2, result 就是局部变量
    def cal(self, n1, n2):
        result = n1 + n2
        print(f "result = {result}")
  • 我们说的局部变量,一般指在成员方法中定义的变量。
  • 作用域的分类:属性作用域为整个类,比如 Cat类:cry eat 等方法使用属性。
python 复制代码
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,则是访问局部变量。
python 复制代码
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()

构造方法

基本介绍
python 复制代码
def __init__(self, 参数列表):
    代码...
  • 在初始化对象时,会自动执行__init__方法
  • 在初始化对象时,传入的参数,自动传递给__init__方法。
  • 构造方法是python预定义的,名称是__init__,注意init前后都有两个_
python 复制代码
# 在初始化对象时,会自动执行 __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__方法,即使你写了多个,也只有最后一个生效。
python 复制代码
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 复制代码
# 为了代码简洁,我们也可以通过 __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}")
  • 构造方法不能有返回值。
python 复制代码
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]的最大值,并返回。

python 复制代码
# 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,否则不变。

python 复制代码
# 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,定义属性:半径,提供显示圆周长功能的方法,提供显示圆面积的方法。

python 复制代码
# 定义一个圆类 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的话,要提示)并创建对象,分别测试。

python 复制代码
# 编程创建一个 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。

python 复制代码
# 定义 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、分析下列代码输出结果。

python 复制代码
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表示布。

python 复制代码
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()

欢迎关注我的博客,如有疑问或建议,请随时留言讨论。

相关推荐
Theodore_10223 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书3 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
----云烟----5 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024065 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·5 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神6 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式