Python基础:面向对象

本文介绍了Python中的面向对象概念,涵盖封装实例、类方法、静态方法的区别,以及继承、多态的应用实例。通过部门与员工、学校与学生、老师类的演示,展示了面向对象的实战技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面向过程

title = 'Python入门'
price = 39.02
author = 'prter'


def search_book0(title):
    pass


'''面向过程,都是些很松散的变量、表达式、函数
所以要想办法将松散的字段(有关联的)封装到一个类/对象里,将一些行为封装到函数里也是封装'''

使用Python内置的对象进行代码封装

1、将这些字段放入列表

book = [title, price, author, search_book0]

2、用字典表的方法模拟面向对象,字典表是初期没有学习面向对象时作为封装的最佳选择

def search_book(title):
    print('搜索包含关键词[{}]的图书:'.format(title))


book = {
    'title': 'Python入门',
    'price': 39.02,
    'author': 'prter',
    'search_book': search_book
}

book.get('search_book')('啦啦啦')   # 间接调用了search_book这个函数,委托
book['search_book']('lalala')
print(book['title'])
print(book.get('price', 0.0))

面向对象:基础

定义类 和 实例化对象

class Book:         # 定义类的时候类名要大写
    pass            # 什么不写放个占位符就行


book = Book()       # 实例化

# 实例化后 同时定义对象的属性和值
book.title = 'Python入门'
book.price = 39.02
book.author = '旧人'

print(book.title)
print(book.price)
print(book.author)

# 这种方式还是很松散

面向对象1

定义类 实例化对象 真正符合语法的

import datetime     # 导入这个处理时间的模块


class Book:         # __init__(self)构造函数    初始化类成员
    def __init__(self, title, price=0.0, author='', publisher=None, pubdate=datetime.date.today()):
        self.title = title  # 定义了五个成员属性 分别指向上面的形参 实例化的时候传递的实参是它实际的值
        self.price = price  # 如果属性名是两个_开头的是私有成员属性 如:self.__price
        self.author = author
        self.publisher = publisher
        self.pubdate = pubdate
        # self类似其他语言的this 但是有些编程语言self和this有区别
        # 会有很多不同的实例来通过self调用这些属性
        # self不能理解为class Book的本身  谁调用它 它就指向谁 跟this很像

    # 定义在交互式提示符下 输入实例后的对象的显示
    # 不定义默认输出:<main3.Book object at 0x03224D30> 对于用户和开发人员来说没什么意义
    def __repr__(self):
        return '<图书 {} 定价 {} at 0x{}>'.format(self.title, self.price, id(self))
    # self.title 是获取当前图书的书名
    # self获取当前图书 使用id这个全局函数得到当前图书在内存里的id
    # 现在输出的就是 <图书 C#精典 定价 22.9 at 0x51488496> 这种样子

    def __str__(self):
        return '[图书:{} 定价:{}]'.format(self.title, self.price)
    # __repr__ 是定义开发者在控制台上直接输入实例后的对象名称时打印的结果
    # __str__ 是用print()打印时显示的结果 本质上一样的 不定义这个默认拿__repr__代替

    def print_info(self):       # 在类里定义一个自己的打印图书信息的方法
        print('当前书的信息如下:')
        print('书名:{}'.format(self.title))
        print('定价:{}'.format(self.price))
        print('作者:{}'.format(self.author))
        print('出版社:{}'.format(self.publisher))
        print('出版时间:{}'.format(self.pubdate))


# 实例化对象   Python不需要用new
book1 = Book('C#精典', 22.9, 'Tom', '清华大学出版社', datetime.date(2016, 3, 1))
print(book1.title)   # 打印book1的书名和定价
print(book1.price)


book2 = Book('Python入门到放弃')    # 后面几个是默认参数,这里只要传第一个位置参数也可以
book2.author = 'Tom'               # 对象创建之后 可以修改默认参数
book2.publisher = '清华大学出版社'  # 修改默认参数

book2.print_info()  # 调用上面自己定义的打印图书方法,打印book2对应的信息


# 一般在控制台上输入一个列表,返回的就是一个列表,输入元组,返回的就是元组
# 如果是range()、字典表的keys()这些返回的就不一样了,这些都是对象在定义的时候设定的
# 我们自己定义的对象一般可以使用 __repr__() 和 __str__() 这两个特殊方法来设置这些
print(book1)        # 打印实例后的对象book1   输出:[图书:C#精典 定价:22.9]
print(book2)        # 打印实例后的对象book1   输出:[图书:Python入门到放弃 定价:0.0]

面向对象2

实例方法 类方法 静态方法 静态属性

class Book:
    # count写在构造函数外面,是跟实例化无关的东西,没有self,不同于书名,价格,作者
    # count放在Book类的外面(全局变量)也行,但是就不属于图书的逻辑关系了,没有类的意义了
    count = 0       # 静态成员属性  只属于图书类Book的信息,跟实例化后的每一本图书无关

    def __init__(self, title, price=0.0, author=''):   # 初始化执行   构造函数
        self.title = title                             # 定义成员属性
        self.price = price
        self.author = author
        Book.count += 1     # 每创建一个对象(实例化),count都会自动+1

    def __del__(self):      # 删除对象执行
        Book.count -= 1     # 每删除一个对象 变量count -1

    def __repr__(self):
        return f'<图书:{self.title} at 0x{id(self)}>'

    def __str__(self):
        return f'[图书:{self.title},定价:{self.price}]'

    def print_info(self):
        print(self.title, self.price, self.author)    # 定义一个打印图书信息的方法()

    @classmethod   # 如果不加装饰器的话就是实例方法,所以调用它的时候就要传递一个实例
    def cls_method(cls):    # cls可以随便取名字,但是约定成俗一般用cls
        print('类方法:第一个参数cls长什么样不重要,都是指类本身,调用时将类作为对象隐式地传入方法'
              f',可以通过cls.count调用到静态属性count,图书的数量:{cls.count}')
    # 类方法可以调用静态属性和静态方法(cls.属性 cls.方法()),不能调用实例属性和实例方法。
    # 类方法通过cls()可以调用到实例方法,但是类里面必须没有实例属性,
    # 也就是__init__(self)方法里不能有形参,具体参考后面的一个案例:类方法的一种特殊情况

    @staticmethod
    # 加上这个装饰器就是跟实例有关的静态方法了,可以被类和对象调用
    # 类和实例都可以调用它,但是它不可以调用别人,它没有cls、self参数
    def static_method():
        print(f'静态方法:可以通过Book.count调用到静态属性count,图书的数量:{Book.count},'
              '因为静态属性是可以直接用类本身调用的,虽然可以,但是这并不是静态方法自己来调用的'
              ',失去了面向对象的意义,静态对象没有cls、self参数,是调用不了别人的')

    # 静态方法通过类.属性、类.方法()这样就可以像类方法、实例方法一样调用到静态属性和静态方法了
    # 还可以通过实例后的对象 来调用实例属性、实例方法 (这样想 类方法也可以通过这种方式调用实例了)
    # 这种方式调用实际上是通过类或者对象调用的,跟静态方法、类方法都没关系,一般不会这样操作,无任何意义
    # 调用静态属性和实例属性就用实例方法,只需要调用静态属性就用类方法,不调用任何属性就用静态方法

    def method():
        # 不加装饰器的话就是伪静态方法(普通函数),与实例无关,只可以被类调用
        print('没有加装饰器,也没有self、cls,所以只是普通的函数')


if __name__ == '__main__':    # 入口,判断如果是在当前脚本文件里执行当前类
    book1 = Book('Python', price=29.0, author='tmo')      # 图书1实例化对象
    book1.print_info()      # 调用打印图书的方法

# 类的静态成员属性
    # Book.count += 1
    book2 = Book('Flask')          # 图书2实例化对象
    # Book.count += 1
    book3 = Book('Asp.net')        # 图书3实例化对象
    # Book.count += 1
    # 因为上面在类成员里有了Book.count += 1,所以不需要单独每次+1了,实例化一个对象会自动+1

    del(book3)   # 使用全局函数del()删除一本书(对象)
    # 直接这样删除的话图书数量count这个变量不会-1,但是上面定义了删除对象执行就可以了

    print('图书的数量:', Book.count)
    # 这里打印出来的就是总数了 如果上面的count不是放在上面,而是放在里面 是一个实例属性的话,
    # 每次实例化一个对象后就只能book1.count += 1 book2.count += 1 ... 这样按照实例来增加,
    # 调用的时候也只能book1.count book2.count ... 这样通过实例来调用,
    # 最后打印出来的永远是1,因为他们依附的对象不是一个,每创建一个对象都是独立的

    print('图书的数量:', book1.count)     # 这样通过实例来调用静态属性也行;尽量不要这样用
    book1.count = 99                      # 而且还可以修改
    print('图书的数量:', Book.count)      # 修改后静态属性的没变化
    print('图书的数量:', book1.count)     # 而通过实例对象调用就是修改后的值了
    # 静态成员变量可以通过实例去调用它,只是调用的话,值就是静态属性的值,
    # 但是如果调用并把值改了话,那么它就不属于静态属性了,而是属于实例后的对象自己的成员属性了,
    # 就像是直接给一个不存在的实例属性赋值,就会创建这个实例属性一样[参考前面说得],
    # 跟函数的作用域有点像:函数外的变量和函数里定义的变量同名,如果不指定globa,会是一个新的局部变量


# 类方法
    Book.cls_method()       # 加上@classmethod装饰器后就可以直接通过类调用了
    book2.cls_method()      # 加上@classmethod装饰器后依然还可以通过实例调用

    # Book.cls_method(book1)
    # 类方法如果不加@classmethod装饰器,看起来是个类方法,实际上跟实例方法没区别,
    # 所以通过类.方法()调用这个(伪.类)方法的时候必须要传一个实例
    # 具体可以参考后面的一个例子:用类调用一个实例方法


# 静态方法
    Book.static_method()
    book1.static_method()
    # 定义的时候不写cls或self
    # 加@staticmethod装饰器后,可以通过类和实例调用
    # 不加的话是伪静态方法(普通函数),只可以被类调用

类方法的一种特殊情况:使用cls()调用实例

class A(object):
    # 属性默认为类属性(可以给直接被类本身调用)
    num = "类属性"

    # def __init__(self, a):
    #     self.a = a
    # 这里如果有a这样的参数,下面在类方法里就不能用cls().func1()这种方式调用一个实例方法了
    # 因为这个a是放在__init__(self)里的,是要实例化并传值的

    def __init__(self):
        self.b = 123
        # 像这样就可以在类方法里用cls().func1()这种方式调用一个实例方法

    # 实例方法(必须实例化类之后才能被调用)
    def func1(self):  # self : 表示实例化类后的地址id
        print("func1")
        print(self)

    # 类方法(不需要实例化类就可以被类本身调用)
    @classmethod
    def func2(cls):  # cls : 表示没有被实例化的类本身
        print("func2")
        print(cls)
        print(cls.num)
        cls().func1()

    # 不传递传递默认self参数的方法(该方法也是可以直接被类调用的,但是这样做不标准)
    def func3():   # 伪静态方法,普通函数
        print("func3")
        print(A.num)  # 类属性是可以直接用类本身调用的


# A.func1()   # 没有实例化无法通过类调用实例方法
# 这样调用是会报错:因为func1()调用时需要默认传递实例化类后的地址id参数,如果不实例化类是无法调用的

A.func2()
A.func3()

用类调用一个实例方法

class Demo:
    def __init__(self, a):
        self.a = a

    def deme(self, b):
        print(self.a, b)


if __name__ == '__main__':
    d = Demo('第一个实例对象:')
    d.deme('用对象调用')
    Demo.deme(d, '用类调用')   # 第一个参数要给实例,相当于调self

    c = Demo('第二个实例对象:')
    c.deme('用对象调用')
    Demo.deme(c, '用类调用')   # 第一个参数要给实例,相当于调self

    print(type(d))
    print(type(c))
    print(type(Demo))

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

静态方法、类方法、实例方法区分

复制网上的 加上自己总结

# 定义在类中的代码块叫方法,Python的方法分为『实例方法』、『类方法』、『静态方法』
# 按照从前到后的顺序它们和实例对象的依赖程度依次降低


class Demo:

    sfield = '静态属性'    # 静态属性(类属性)

    def __init__(self, value):
        """初始化方法"""
        self.value = value   # 实例属性

    def ixmethod(self):      # self:表示实例化类后的地址id
        """实例方法,测试能否调用实例属性"""
        print('ixmethod ->', self.value)

    def iymethod(self):      # self:表示实例化类后的地址id
        """实例方法,测试能否调用静态属性"""
        print('iymethod ->', self.sfield)

    def cxmethod1(cls):
        """伪·类方法,测试能否调用实例属性"""
        print('cxmethod ->', cls.value)

    def cxmethod2(cls):
        """伪·类方法,测试能否调用静态属性"""
        print('cxmethod1 ->', cls.sfield)

    @classmethod
    def cymethod(cls):                       # cls:表示没有被实例化的类本身
        """真·类方法,测试能否调用静态属性"""  # 真.类方法只能调用到静态属性,调用实例属性直接报错函数错误
        print('cymethod ->', cls.sfield)

    def sxmethod():
        """伪·静态方法,尝试打印一条语句"""
        print('伪·静态方法,尝试打印一条语句')
    """
自己没有cls或者self,所以不能像它们那样调用属性,只能打印一条语句了   可怜0.0

直接通过类.属性、对象.属性或类.方法()、对象.方法()、也可以访问到静态属性、实例属性或者其他属性/方法
如果按照这种想法:不管是实例方法、类方法、静态方法都可以直接通过这种方式调用任何想调用的属性/方法,
就不存在能不能调用了,所以为了体现面向对象编程的概念,一般不这样操作,无任何意义
调用静态属性和实例属性就用实例方法,只需要调用静态属性就用类方法,不调用任何属性就用静态方法
所谓的能不能调用是指通过第一个参数cls或self来调用(cls、self叫什么无所谓,一般约定成俗)
    """
    @staticmethod
    def symethod():
        """真·静态方法,尝试打印一条语句"""
        print('真·静态方法,尝试打印一条语句')


d = Demo('实例属性')     # 实例化对象,传入实例属性


d.ixmethod()        # 实例方法,能调用实例属性:对象.方法()
d.iymethod()        # 实例方法,能调用静态属性:对象.方法()
"""实例方法可以调用实例属性也可以调用静态属性(类属性)
但是在调用这个方法的时候只能通过对象.方法()来调用这个方法
因为实例方法只能被实例来调用,这个跟能不能访问属性无关,是实例方法的特性
"""
# Demo.ixmethod()   # 实例方法,不能调用实例属性:类.方法()
# Demo.iymethod()   # 实例方法,不能调用静态属性:类.方法()
# 会报错,这跟ixmethod()、iymethod()调用什么属性、方法无关,
# 类本来就不能调用实例,非要调用的话,传入一个实例即可:Demo.ixmethod(d)


d.cxmethod1()        # 伪·类方法,能调用实例属性:对象.方法()
d.cxmethod2()        # 伪·类方法,能调用静态属性:对象.方法()
# Demo.cxmethod1()   # 伪·类方法,不能调用实例属性:类.方法()
# Demo.cxmethod2()   # 伪·类方法,不能调用静态属性:类.方法()
"""伪.类方法跟实例方法一样
这也说明了类方法的cls只是一个名字,不加@装饰器跟实例方法没什么区别
"""


d.cymethod()        # 真·类方法,能调用静态属性:对象.方法()
Demo.cymethod()     # 真·类方法,能调用静态属性:类.方法()
"""真.类方法只能调用静态属性(类属性)
类方法调用实例属性直接报错函数错误,因为它的存在就是为了要跟实例分开的,所以类方法不能调用实例属性

类方法可以被类调用(因为类方法里面没有调用实例属性,所以不需要实例化类就可以被类本身调用),
也可以被对象调用(因为没加装饰器之前就是实例方法,加了装饰器只是为了让它可以被类调用)
"""


# d.sxmethod()       # 伪·静态方法,尝试打印一条语句:对象.方法()
Demo.sxmethod()      # 伪·静态方法,尝试打印一条语句:类.方法()
""""静态方法不可以调用任何属性(没有第一个参数self或cls)

伪.静态方法可以被类调用(因为静态方法里面没有调用实例属性,所以不需要实例化类就可以被类本身调用)
伪.静态方法就相当于是一个普通函数
"""


d.symethod()         # 真·静态方法,尝试打印一条语句:对象.方法()
Demo.symethod()      # 真·静态方法,尝试打印一条语句:类.方法()
""""静态方法不可以调用任何属性(没有第一个参数self或cls)

真.静态方法可以被类调用(因为静态方法里面没有调用实例属性,所以不需要实例化类就可以被类本身调用),
也可以被对象调用(因为加了装饰器,就等于跟实例关联上了,不加装饰器就是伪.静态方法,只可以被类调用)
"""

结论如下:

1)类方法和静态方法必须要在方法头部加上@开始的修饰符,否则不能视为完全的类方法或静态方法

  • 特别是类方法,如果没有加@开始的修饰符,效果和实例方法等价,因为self不是关键字,如果仅仅写下cls编译器并不能识别

2)按照实例方法、类方法、静态方法的顺序,它们对该类的依赖性逐渐降低:

  1. 实例方法既可以方法实例属性,也可以方法静态属性(通过self.属性来调用)
  2. 类方法只能调用静态属性(通过cls.属性来调用),如果调用实例属性,直接报错函数错误
  3. 而静态方法因为没有参数绑定到该类所以仅仅提供函数功能,不能调用实例属性或静态属性,加了@装饰器的真.静态方法就等于把它跟实例关联上了(虽然我没有cls和self不能调用别人,但是现在谁都可以调用我),伪.静态方法因为没有@装饰器,只能通过类调用这个伪静态方法

3)类的实例对象在调用类中定义的方法时,会把自身作为第一个参数传进去(self cls)
这也是为什么不写@classmethod的伪·类方法实际上还是实例方法的本质原因

类方法:第一个参数必须要默认传类,一般习惯用cls
实例方法:第一个参数必须要默认传实例对象,一般习惯用self
静态方法则没有要求

捋一捋:

这个例子的目的是告诉我们哪种方法能调用静态属性/方法,哪种方法能调用实例属性/方法
哪种方法能用类调用、哪种方法能用实例后的对象调用

调用:函数内通过self、cls来调用一些属性/方法(一般调用属性)
被调用:通过类或对象来调用这些方法

对象能调用实例方法类方法(cls)、真.静态方法(因为加了装饰器,不加的话就是个普通函数,只能被类调用)

类能调用真.类方法(因为加了装饰器,跟类相关联了,加了装饰器就不能用过cls调用实例属性了,所以类可以调用)、静态方法(因为没有cls self,函数里面没有调用任何参数,所以类可以调用)

@property装饰器,把方法改变成属性

import math     # 数学模块


class Circle:
    def __init__(self, radius):
        self.radius = radius

    def get_area(self):     # 行为   方法()
        return math.pi * self.radius ** 2

    @property       # 加@property 就可以像属性那样调用了
    def area(self):
        return math.pi * self.radius ** 2


c = Circle(4.0)
print('圆的面积是:{}'.format(c.get_area()))
print('圆的面积是:{}'.format(c.area))

@property装饰器 使用场景

import datetime     # 操作时间的模块


class Student:
    def __init__(self, name, birthdate):
        self.name = name
        # self.age = age              # 从习惯是来说传入年龄更合适,
        self.birthdate = birthdate   # 但是从逻辑上来说出生日期更合适

    def get_age(self):
        return datetime.date.today().year - self.birthdate.year   # 今天减去出生日期

    # 把方法转换成了属性,同时又有了其他功能。装饰器的作用就可以在不改函数里的代码的同时强化代码
    @property   # 加装饰器后,调用的时候就不用对象.get_age()这样了,更简洁
    def age(self):
        return datetime.date.today().year - self.birthdate.year    # 今天减去出生日期

    @age.setter             # @函数名.setter 设置器   @property装饰器里的方法
    def age(self, value):   # value参数 是用户传的值(形参)
        raise ArithmeticError('禁止赋值年龄')   # 抛出禁止赋值年龄异常

    @age.deleter        # @函数名.deleter 删除器   @property装饰器里的方法
    def age(self):      # 因为是删除 所有没有参数
        raise ArithmeticError('禁止删除年龄')  # 抛出禁止删除年龄异常


if __name__ == '__main__':
    s = Student('Tom', datetime.date(1995, 5, 4))
    print(s.birthdate)
    # print(s.get_age())
    print(s.age)   # 属性的方式调用,不用s.get_age()这样调用了,更简洁,都可以输出年龄

    '''禁止赋值年龄'''
    s.birthdate = datetime.date(1982, 8, 6)
    print(s.birthdate)   # 这里生日是可以重新赋值的
    # s.age = 20
    # print(s.age)   # 但是由于上面的设置,年龄不可以赋值的,会抛出上面设置好的异常

    # 目的就是让别人不可以填写age
    # 如果没有上面的装饰器,即使构造函数__init__()里面没有age属性
    # 通过s.age=20这种方式依然可以添加age属性

    '''禁止删除年龄'''
    # del(s.name)
    # print(s.name)   # 姓名是可以删除的 删除后会抛出异常说对象没有name这个属性
    del(s.age)
    print(s.age)     # 同样由于上面的装饰器设置  年龄是不可以删除的 抛出定义的异常

面向对象:封装 继承 多态

类是为了描述对象而存在的[模板]

封装 继承 多态综合例子1

"""
多态:属于同一类型的不同实例,对同一消息做出不同响应
"""


import datetime


class Department:
    # 单独给部门再写个类,丰富部门属性,这个时候部门就不是简单的一个成员属性了
    def __init__(self, department, phone, manager):
        self.department = department  # 部门名称
        self.phone = phone            # 部门电话
        self.manager = manager        # 部门经理

    def __repr__(self):
        return f'<部门:{self.department}>'


# 员工类和部门类属于包含的关系

# : Department只是为了说明这个属性传参的时候接收Department这个类型的,只是为了便于查看代码,
# 实际上department这个属性在实例化的时候还是什么都可以传入,因为Python是动态类型的,
# 并不是说加了之后就只能传入自己定义的Department这个类型的值了,所以不加也一样。
class Employee:                     # 基类   Employee  员工类
    def __init__(self, name, department: Department, birthdate, salary):
        self.name = name
        self.department = department
        self.birthdate = birthdate
        self.salary = salary

    def __repr__(self):
        return f'<员工:{self.name}>'

    @property           # 员工类的属性,计算年龄(age)
    def age(self):
        return datetime.date.today().year - self.birthdate.year

    def give_raise(self, percent, bonus=.0):  # 员工类的的方法,提成和奖金,按基本工资百分比加
        self.salary = self.salary * (1 + percent + bonus)

    def working(self):   # 员工类的的方法,正在做某件事
        print('员工:{},正在工作...'.format(self.name))


class Programer(Employee):    # 派生类 子类   程序员类,继承员工类
    def __init__(self, name, department, birthdate, salary, specialty, project):
        self.specialty = specialty           # 程序员类自己的属性
        self.project = project               # 程序员类自己的属性

        super().__init__(name, department, birthdate, salary)
        """
        继承基类的属性,把基类的方法调用过来就相当于初始化了
        这种继承方法不好,因为没有明确指定调用的是哪个基类的属性,在多继承的时候含糊不清

        super(Programer, self).__init__(name, department, birthdate, salary)
        这里super()括号里可以接收两个参数,子类和self,参数只是说明当前是哪个子类在调用,
        在定义的方法里可以使用这种方式访问到基类的方法,
        在多态的时候,子类和基类的方法名一样,优先执行的是子类的方法,
        但是通过这种方式可以让它执行基类的,如:super(HR, self).working(),
        所以super不只是用于构造函数,还可以用于其他骚操作。
        """

    def working(self):          # 程序员类的的方法,正在做某件事
        # 程序员类的方法working()跟员工类的working()重写-重载:多态的概念
        print('程序员{}正在{}...'.format(self.name, self.project))


class HR(Employee):             # 派生类 子类    HR类,继承员工类
    def __init__(self, name, department, birtdate, salary, project, qualification_level=1):
        self.project = project                              # HR类自己的属性
        self.qualification_level = qualification_level      # HR类自己的属性

        Employee.__init__(self, name, department, birtdate, salary)
        # 这种继承方法比上面的好,直接明确的写明类型Employee,
        # 多继承的时候就不会含糊不清。多继承:HR(Employee, Abbbc):

    def working(self):           # 重写working方法
        print('人事{}正在{}...'.format(self.name, self.project))
        super(HR, self).working()


if __name__ == '__main__':
    '''程序员类'''
    p = Programer('Peter','技术部',datetime.date(1990,5,6),8000,'Flask','摸鱼')
    print(p)
    print('年龄:',p.age)
    print('部门:',p.department)
    print('底薪:',p.salary)
    p.give_raise(.2, .1)        # 给他加提成
    print('加提成后薪资:',p.salary)
    p.working()

    '''HR类'''
    hr = HR('铁锤','人事部',datetime.date(1994,5,4),4000,'看书',qualification_level=3)
    print(hr)
    print('年龄:',hr.age)
    print('部门:',hr.department)
    print('底薪:',hr.salary)
    hr.give_raise(.1)
    print('加提成后薪资:',hr.salary)
    hr.working()

    '''
    创建单独的部门类后
    '''
    dep = Department('技术部', '101-110120152', '张小三')  # 构造一个部门对象
    p = Programer('Peter', dep, datetime.date(1990, 5, 8), 8000, 'Python-Flask', 'XMall')
    print('底薪:', p.salary)
    p.give_raise(.2, .1)
    print('加提成奖金后薪资:', p.salary)
    print(p.department)
    # 这里相当于是 print(dep)  输出:<部门:技术部> ,这个是上面定义的__repr__()
    # 没定义之前是<__main__.Department object at 0x005DDD30>
    print('部门名称:', p.department.department)
    print('部门电话:', p.department.phone)
    print('部门经理:', p.department.manager)
    # 因为部门传入的是dep这个实例,所以调用的时候就调用p.department下的department、phone、manager等...

    '''
    把人事铁锤当做人事部经理
    '''
    hr = HR('铁锤', dep, datetime.date(1994, 5, 4), 4000, '看书', qualification_level=3)
    hr.department.department = '人事部'
    hr.department.phone = '010-1111111111111'
    hr.department.manager = hr.name
    print('部门名称:', hr.department.department)
    print('部门电话:', hr.department.phone)
    print('部门经理:', hr.department.manager)

    print(hr.__dict__)      # 查看对象里的成员和方法

封装 继承 多态综合例子2

import datetime


class Xue_xiao():    # 基类:学校类
    def __init__(self, xing_ming, xing_bie, chu_sheng):
        self.xing_ming = xing_ming
        self.xing_bie = xing_bie
        self.chu_sheng = chu_sheng

    @property
    def nian_ling(self):
        return datetime.date.today().year - self.chu_sheng.year

    def zoumoujianshi(self, shi_qing):    # 学校类的方法:做某件事
        print(f'{self.xing_ming}正在{shi_qing}')


class Xue_sheng(Xue_xiao):  # 派生类:学生类,继承自学校类
    def __init__(self, xing_ming, xing_bie, chu_sheng, ban_ji="", ban_zhu_ren="", sf_ban_gan_bu=False, te_chang=None):
        self.ban_ji = ban_ji
        self.ban_zhu_ren = ban_zhu_ren
        self.sf_ban_gan_bu = sf_ban_gan_bu
        self.te_chang = te_chang
        super().__init__(xing_ming, xing_bie, chu_sheng)

    def zoumoujianshi(self, shi_qing):             # 学生类的方法:做某件事
        print(f'学生{self.xing_ming}的特长是{self.te_chang},但是他现在他正在{shi_qing}')

    def fw_ban_gan_bu(self):       # 学生类的方法:封为班干部
        self.sf_ban_gan_bu = True


class Lao_shi(Xue_xiao):    # 派生类:老师类,继承自学校类
    def __init__(self, xing_ming, xing_bie, chu_sheng, jiao_sm=[], sf_ban_zhu_ren=False):
        self.jiao_sm = jiao_sm
        self.sf_ban_zhu_ren = sf_ban_zhu_ren
        super().__init__(xing_ming, xing_bie, chu_sheng)

    def fw_ban_zhu_ren(self):       # 老师类的方法:封为班主任
        self.sf_ban_zhu_ren = True


if __name__ == '__main__':
    '''学校类'''
    xuexiao = Xue_xiao('李大大', '男', datetime.date(1992, 5, 12))
    print(xuexiao.xing_ming, xuexiao.xing_bie, xuexiao.nian_ling)
    xuexiao.zoumoujianshi('上厕所')

    '''学生类'''
    xuesheng =Xue_sheng('二狗子', '男', datetime.date(1995, 3, 25), '92班', '王老师', te_chang='打游戏')
    print(xuesheng.xing_ming, xuesheng.xing_bie, xuesheng.nian_ling,
          xuesheng.ban_ji, xuesheng.ban_zhu_ren, xuesheng.te_chang)
    print(xuesheng.xing_ming + '是不是班干部:', xuesheng.sf_ban_gan_bu)
    xuesheng.fw_ban_gan_bu()
    print(xuesheng.xing_ming + '是不是班干部:', xuesheng.sf_ban_gan_bu)
    xuesheng.zoumoujianshi('看书')

    '''老师类'''
    laoshi = Lao_shi('王二妞', '女', datetime.date(1990, 2, 10), ['语文', '政治'])
    print(laoshi.xing_ming, laoshi.xing_bie, laoshi.nian_ling, laoshi.jiao_sm)
    print(laoshi.xing_ming + '是不是班主任:', laoshi.sf_ban_zhu_ren)
    laoshi.fw_ban_zhu_ren()
    print(laoshi.xing_ming + '是不是班主任:', laoshi.sf_ban_zhu_ren)
    laoshi.zoumoujianshi('跟校长谈话')

    '''王二妞是学生二狗子的班主任'''
    xuesheng.ban_zhu_ren = laoshi
    print(xuesheng.ban_zhu_ren.xing_ming)



Python classmethod 修饰符
Python staticmethod() 函数
Python 中的 classmethod 和 staticmethod 有什么具体用途?
python中@classmethod @staticmethod区别
面对对象之@classmethod、@staticmethod用法
Python的类实例方法,类方法,类静态方法
python中的实例方法、静态方法、类方法、类变量和实例变量

Python 中的 if name == ‘main’ 该如何理解
if name == ‘main’ 如何正确理解?

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧人小表弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值