1. 初识面向对象

想要通过面向对象去实现某个或某些功能时需要2步:

  • 定义类,在类中定义方法,在方法中去实现具体的功能
  • 通过类实例化出一个对象,通过对象去调用并执行方法
class Message:  # 类名称首字母大写,多个单词用驼峰式命名
    def send_email(self, email, content):  # 在类中编写的函数称为方法,每个方法的第一个参数是self
        text = "给{}发邮件,内容: {}".format(email, content)
        print(text)

    def send_wechat(self, vid, content):
        text = "给{}发微信,内容: {}".format(vid, content)
        print(text)


# 类的实例化,即在某个类下创建某个对象 (实例名=类名)
msg_object = Message()  # 创建对象并实例化赋值给msg_object,创建了一块区域

# 调用类的方法 (实例名.方法)
msg_object.send_email("xxxx@.com", '注册成功')
msg_object.send_wechat('xxx', '注册成功')

1.1 初始化方法、对象、self

初始化方法:在每个类中都可以定义个特殊的__init__初始化方法,在实例化类创建对时自动执行

  • 当每个实例对象创建时,初始化方法的代码无须调用就会自动运行
  • 利用这个特性,在编写习惯上,我们会在初始化方法内部完成实例属性的创建,为实例属性设置初始值,这样类中的其他方法就能直接、随时调用
  • 除了设置固定常量,初始化方法同样可以接收其他参数,让传入的这些数据能作为属性在类的方法之间流转。

self:代表类的实例,是通过类创建的实例(注意:在定义类时这个实例我们还没有创建,它表示我们使用类时创建的那个实例)

  • self本质上就是一个参数,这个参数是Python内部会提供,其实本质上就是调用当前方法的那个对象
  • 会接收实例化过程中传入的数据,当实例对象创建后,实例便会代替self,在代码中运行
  • 只要在类中用 def 创建方法时,就必须把第一个参数位置留给 self,并在调用方法时忽略它 (不用给self传参)
  • 内部使用:当在类的方法内部想调用类属性或其他方法时,要采用 self.属性名self.方法名 的格式
  • 外部使用:类中的方法需要由这个类的对象来触发并执行( 对象.方法名 ),且在执行时会自动将对象当做参数传递给self,以供方法中获取对象中已封装的值。

对象:让我们可以在它的内部先封装一部分数据,以后想要使用时,再去里面获取。

  • 基于类实例化出来"一块内存",默认里面没有数据;经过类的__init__方法,可以在内存中初始化一些数据
class Message:  # 类名称首字母大写或驼峰式命名
    flag = 'send'  # 类变量 

    def __init__(self, content):  # 初始化方法,为实例进行数据的初始化
        self.data = content  # 实例变量,默认指向了当前的实例对象

    def send_email(self, email):  # 在类中编写的函数称为方法,每个方法的第一个参数是self
        data = "给{}发邮件,内容: {}".format(email, self.data)
        print(data)

    def send_wechat(self, vid):  # 在类中编写的函数称为方法,每个方法的第一个参数是self
        data = "给{}发微信,内容: {}".format(vid, self.data)
        print(data)


# 类的实例化,即在某个类下创建某个对象 (实例名=类名)
# 1. 根据类创建一个对象(内存的一块区域)
# 2. 执行 __init__ 方法,默认会将创建的那块区域的内存地址当做self参数传递进去,往区域中放入(data = "注册成功")
msg_object = Message("注册成功")  # 对象 = 类名(), 自动执行类中的 __init__ 方法

# 调用类的方法(实例名.方法)
msg_object.send_email("xxxx@.com")  # 给xxx@xx.com发邮件,内容: 注册成功
msg_object.send_wechat("xxx")  # 给xxx发微信,内容: 注册成功

# 类可以创建多个对象并执行其中的方法
login_object = Message("登录成功")
login_object.send_email("xxxx@.com")  # 给xxxx@.com发邮件,内容: 登录成功
login_object.send_wechat("xxx")  # 给xxx发微信,内容: 登录成功

image-20220406225212803.png

  • 面向对象的思想:实例化对象时将一些数据封装到对象中,在执行方法时,再去对象中获取。
  • 函数式的思想:函数内部需要的数据均通过参数的形式传递。

1.2 常见成员

  • 类变量:属于类,可以被实例变量调用,也可以被类变量调用 (类似全局变量)
  • 实例变量:属于对象,只能被实例对象调用,不能被类对象调用
  • 实例方法(绑定方法的一种):属于类,通过对象调用 或 通过类调用
class Person:
    # 类变量
    env = 'cls_env'

    def __init__(self, n1, n2):
        # 实例变量
        self.name = n1
        self.age = n2
        self.env = 'instance_env'

    # 实例方法
    def show(self):
        msg = "我叫{},今年{}岁。".format(self.name, self.age)
        print(msg)


# 调用类变量
print(Person.env)  # cls_env

# 实例化对象
obj = Person('小明', 18)
# 调用实例变量
print(obj.env)  # instance_env
# 调用实例方法
obj.show()  # 我叫小明,今年18岁。


1.3 面向对象的作用示例

  1. 将数据封装到一个对象,便于以后使用
class UserInfo:
    def __init__(self, name, pwd):  # __init__方法,类实例化的初始化方法
        self.name = name  # 实例变量(实例属性)
        self.password = pwd  # 实例变量(实例属性)


def run():
    user_object_list = []
    # 用户注册
    while True:
        username = input("用户名: ")
        if username.upper() == "Q":
            break
        userpwd = input("密码: ")
        # 实例化出一个对象 user_object,对象中有 name/pwd实例变量(实例属性)
        user_object = UserInfo(username, userpwd)
        user_object_list.append(user_object)
    # 展示用户信息
    for obj in user_object_list:
        print(obj.name, obj.password)


run()
# 用字典也可以实现做封装,只不过字典在操作值时还需要自己写key,面向对象只需要"对象.实例变量" 即可获取对象中封装的数据
# 总结:
#      - 数据封装到对象,以后再去获取
#      - 规范(约束)数据
  1. 将数据封装到对象中,在方法中对原始数据进行加工处理
"""
user_list = ["用户-{}".format(num) for num in range(1, 3000)]

# 分页显示,每页显示10条
while True:
    page = int(input("输入页码: "))
    start_index = (page - 1) * 10
    end_index = page * 10
    page_data_list = user_list[start_index:end_index]
    for item in page_data_list:
        print(item)
"""


class Pagination:
    def __init__(self, current_page, per_page_num=5):
        self.per_page_num = per_page_num
        if type(current_page) != int:
            if not current_page.isdecimal():
                self.current_page = 1
                return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num


user_list = ["用户-{}".format(num) for num in range(1, 3000)]
while True:
    page = input("输入页码: ")
    if page.upper() == 'Q':
        break
    pg_obj = Pagination(page, 10)
    page_data_list = user_list[pg_obj.start:pg_obj.end]
    for item in page_data_list:
        print(item)
  1. 根据类创建多个对象,在方法中对对象中的数据进行修改
class Police:
    """警察"""

    def __init__(self, name, role):
        self.name = name
        self.role = role
        if role == "队员":
            self.hit_points = 200
        else:
            self.hit_points = 500

    def show_status(self):
        """ 查看警察状态 """
        message = "警察{}的生命值为:{}".format(self.name, self.hit_points)
        print(message)

    def bomb(self, terrorist_list):
        """ 投炸弹,炸掉恐怖分子 """
        for terrorist in terrorist_list:
            terrorist.blood -= 200
            terrorist.show_status()


class Terrorist:
    """ 恐怖分子 """

    def __init__(self, name, blood=300):
        self.name = name
        self.blood = blood

    def shoot(self, police_object):
        """ 开枪射击某个警察 """
        police_object.hit_points -= 5
        police_object.show_status()

        self.blood -= 2

    def strafe(self, police_object_list):
        """ 扫射某些警察 """
        for police_object in police_object_list:
            police_object.hit_points -= 8
            police_object.show_status()

    def show_status(self):
        """ 查看恐怖分子状态 """
        message = "恐怖分子{}的血量值为:{}".format(self.name, self.blood)
        print(message)


def run():
    # 1.创建3个警察
    p1 = Police("三壮", "队员")
    p2 = Police("二壮", "队员")
    p3 = Police("大壮", "队长")

    # 2.创建2个匪徒
    t1 = Terrorist("大傻蛋")
    t2 = Terrorist("小傻蛋")

    # 大傻蛋匪徒射击警察大壮
    t1.shoot(p3)

    # 大傻蛋匪徒扫射
    t1.strafe([p1, p2, p3])

    # 小傻蛋射击二壮
    t2.shoot(p2)

    # 三壮炸了那群匪徒
    p1.bomb([t1, t2])

    # 三壮又炸了一次匪徒大傻蛋
    p1.bomb([t1])


if __name__ == '__main__':
    run()


2. 三大特性

面向对象编程在很多语言中都存在,这种编程方式有三大特性:封装继承多态


2.1 封装

封装主要体现在两个方面:

  • 将同一类方法封装到了一个类中,例如上述示例中:匪徒的相关方法都写在Terrorist类中;警察的相关方法都写在Police类中。
  • 将数据封装到了对象中,在实例化一个对象时,可以通过__init__初始化方法在对象中封装一些数据,便于以后使用。

2.2 继承

传统的理念中有:儿子可以继承父亲的财产。

在面向对象中也有这样的理念,即:子类可以继承父类中的方法和类变量(不是拷贝一份,父类的还是属于父类,子类可以继承而已

class Base:                    # 父类 (基类)
    def func(self):
        print("Base.func")

class Son(Base):			   # 子类 (派生类)
    def show(self):
        print("Son.show")
        
s1 = Son()
s1.show()
s1.func() # 优先在自己的类中找,自己没有才去父类

s2 = Base()
s2.func()

image-20220407222518771.png

  • 继承的作用:代码复用
class Base:
    def f1(self):
        pass

class Foo(Base):

    def f2(self):
        pass
    
class Bar(Base):
    
    def f3(self):
        pass
    
obj1 = Foo()
obj1.f2()
obj1.f1()

练习题

class Base:
    def f1(self):
        print('base.f1')


class Foo(Base):
    def f2(self):
        print('before')
        self.f1()  # 调用了f1方法,自己没有,去父类找 
        print('foo.f2')


obj = Foo()
obj.f2()  
# 1. print('before') 
# 2. self.f1() -> obj.f1() -> print('base.f1')
# 3. print('foo.f2')
"""
输出:
before
base.f1
foo.f2
"""
class Base:
    def f1(self):
        print('base.f1')


class Foo(Base):
    def f2(self):
        print("before")
        self.f1()  # obj,Foo类创建出来的对象。 obj.f1
        print('foo.f2')

    def f1(self):
        print('foo.f1')


obj = Foo()
obj.f1()  # obj对象到底是谁?优先就会先去谁里面找
"""
foo.f1
"""
obj.f2()
"""
before
foo.f1
foo.f2
"""
class Base:
    def f1(self):
        print('before')
        self.f2()
        print('base.f1')

    def f2(self):
        print('base.f2')


class Foo(Base):
    def f2(self):
        print('foo.f2')


obj = Foo()
obj.f1()
# 1. 优先去Foo类中找f1,因为调用f1的那个对象是Foo类创建出来的,Foo自己的类中没有f1方法去父类找到 -> print('before')
# 2. self.f2() --> # 还是优先去Foo类中找f2,因为调用f2的那个对象是Foo类创建出来的 -->  print('foo.f2')
# 3. print('base.f1')

b1 = Base()
b1.f1()
# 1. print('before')
# 2. self.f2() 优先去Base类中找f2,因为调用f1的那个对象是Foo类创建出来的 -> print('base.f2')
# 3. print('base.f1')
# python支持多继承
# 多继承方法的优先级 - 从左到右

class TCPServer:
    def f1(self):
        print("TCPServer")


class ThreadingMixIn:
    def f1(self):
        print("ThreadingMixIn")


class ThreadingTCPServer(ThreadingMixIn, TCPServer):
    def run(self):
        print('before')
        self.f1()
        print('after')


obj = ThreadingTCPServer()
obj.run()
# 1. print('before')
# 2. self.f1() -> 优先去在自己的类找f1,自己的类中没有f1方法去父类找(从左到右-ThreadingMixIn) -> print("ThreadingMixIn")
# 3. print('after')
# 分析obj.serve_forever()流程

class BaseServer:
    def serve_forever(self, poll_interval=0.5):
        self._handle_request_noblock()
	def _handle_request_noblock(self):
        self.process_request(request, client_address)
        
	def process_request(self, request, client_address):
        pass
    
class TCPServer(BaseServer):
    pass

class ThreadingMixIn:
    def process_request(self, request, client_address):
        pass
    
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass

obj = ThreadingTCPServer()
obj.serve_forever()

小结:

  • 执行 对象.方法 时,优先去当前对象所关联的类中找,没有的话再取它的父类中查找。
  • Python支持多继承:先继承左边、再继承右边的
  • self到底是谁?(看对象是关于哪个类创建的,就先去那个类找,如没有再看继承关系)去self对应的那个类中去获取成员,没有就按照继承关系向上查找 。

2.3 多态

Python对数据类型没有任何限制,所以天生支持多态

在程序设计中,鸭子类型(duck typing)是动态类型的一种风格。在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型,例如:一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子

多态的核心思想:不同对象可以对相同的方法进行不同的实现,这样在运行时可以根据对象的类型来决定调用哪个实现,从而实现了灵活性和可复用性

class Email(object):
    def send(self):
        print("发邮件")


class Message(object):
    def send(self):
        print("发短信")


send_messages = [Email(), Message()]
for item in send_messages:
    item.send()

3. 再看数据类型

在初步了解面向对象之后,再来看看我们之前学习的:str、list、dict等数据类型,他们其实都一个类,根据类可以创建不同类的对象。

# 实例化一个str类的对象v1
v1 = str("小明") 

# 通过对象执行str类中的upper方法。
data = v1.upper()

print(data)

4. 练习题

  1. 简述面向对象三大特性
  • 封装:同种函数和数据的归类
  • 继承:提高代码复用性,子类继承父类方法,并子类可以将父类方法重写
  • 多态:一个形参的多种数据形式
  1. 以下代码体现 向对象的什么特性?
"""
class Person(object):
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

obj = Person('小明', 18, '男') # 封装
"""

"""
class Message(object):
    def email(self):
        pass

    def msg(self):
        pass

    def wechat(self):
        pass
    # 封装
"""
  1. 看代码写结果
class Foo:
    def func(self):
        print('foo.func')
        
obj = Foo()
result = obj.func() # print('foo.func')
print(result)       # None 没有return返回值
  1. 看代码写结果
class Base1:
    def f1(self):
        print('base1.f1')

    def f2(self):
        print('base1.f2')

    def f3(self):
        print('base1.f3')
        self.f1()


class Base2:
    def f1(self):
        print('base2.f1')


class Foo(Base1, Base2):
    def f0(self):
        print('foo.f0')
        self.f3()


obj = Foo()  # 实例化一个对象obj
obj.f0()
  1. 看代码写结果
class Base:
    def f1(self):
        print('base.f1')

    def f3(self):
        self.f1()
        print('base.f3')


class Foo(Base):
    def f1(self):
        print('foo.f1')

    def f2(self):
        print('foo.f2')
        self.f3()


obj = Foo()
obj.f2()
  1. 补充代码实现
user_list = []
while True:
    user = input("请输入用户名:")
    pwd = input("请输入密码:")
    email = input("请输入邮箱:")
    
"""
# 需求
1. while循环提示 户输 : 户名、密码、邮箱(正则满足邮箱格式)
2. 为每个用户创建一个对象,并添加到user_list中。
3. 当列表中的添加 3个对象后,跳出循环并以此循环打印所有用户的姓名和邮箱
"""

import re

class Message:
    def __init__(self, user, pwd, email):
        self.user = user
        self.pwd = pwd
        self.email = email

user_list = []
count = 1
while count <= 3:
    count += 1
    user = input("请输入用户名:")
    pwd = input("请输入密码:")
    email = input("请输入邮箱:")
    match_object = re.match("\w+@\w+\.(com|cn|net)", email)
    if not match_object:
        print("输入邮箱的格式不正确!")
        break
    user_info = Message(user, pwd, email)
    user_list.append(user_info)

for item in user_list:
    print(item.user, item.email)
  1. 实现用户注册和登录
class User:
    def __init__(self, name, pwd):
        self.name = name
        self.pwd = pwd


class Account:
    def __init__(self):
        # 用户列表,数据格式:[user对象,user对象,user对象]
        self.user_list = []

    def login(self):
        """
        用户登录,输入用户名和密码然后去self.user_list中校验用户合法性
        :return:
        """
        name = input("请输入用户名:")
        passwd = input("请输入密码:")
        for item in self.user_list:
            if name == item.name and passwd == item.pwd:
                print("登陆成功!")
                return
        else:
            print("登陆失败!")

    def register(self):
        """
        用户注册,没注册一个用户就创建一个user对象,然后添加到self.user_list中,表示注册成功。
        :return:
        """
        name = input("请输入用户名:")
        passwd = input("请输入密码:")
        user = User(name, passwd)
        self.user_list.append(user)
        self.login()

    def run(self):

        model_dic = {
            "1": ["注册用户", self.register],
            "2": ["登陆账户", self.login],
        }
        for key, value in model_dic.items():
            print(f'{key}-{value[0]}')
        choice = input("请输入您想要的功能序号:")
        model_dic[choice][1]()


if __name__ == '__main__':
    obj = Account()
    obj.run()
posted on 2023-10-20 16:49  龙泉寺老方丈  阅读(24)  评论(0)    收藏  举报