从零学习python - 12面向对象Object之一(从类到多继承)

class 类名[(object)]:  默认继承object类
    多个对象相同的特征可以抽取出来,就是这个类的属性
    多个对象相同的动作行为抽取出来,就是这个类的方法
例如: 手机的属性: 颜色,型号,大小,价格  手机的方法:打电话,发短信,打游戏
就可以将手机抽取出来一个类

类的定义 

# 定义类
class Phone:
    # 属性
    pass
    # 方法
# python有个特点,可以使用空类(class)去构建
# 当python解释器遇到类时,就会将这个类(Phone)当成'模型'存入内存,后面使用这个模型去创建对象 'xx = Phone()'
# 类名后加()表示创建对象 'xx = Phone()'  xx会在内存一块地址中保存
# 调用对象内的属性和方法 xx.prop   xx.func
# 使用类创建对象
# Phone() 动作: 1-找到Phone在内存中的空间地址 
#       2-根据Phone类向内存申请一块内存空间
#       3-如果没有__init__(self)方法则对象创建结束 
#       4-如果有则执行此方法,将申请的内存空间地址赋值给__init__(self)的self,再把地址赋值给对象
xxx = Phone()
print(Phone)  # 
print(xxx)  # <__main__.Phone object at 0x0000023C7D2E74C0>

类与属性

# 当对象调用类属性时,首先会在自己的内存空间中去找,如果没有这个属性才会去类空间中去找.
class Person:
    name = 'bot01'
    age = 18
    gender = 'male'


bot = Person()
print(bot.name)  # bot01
print(bot.age)  # 18
print(bot.gender)  # male

# 在对象的操作是不会更改掉类本身的属性的,如果想要更改类当中的属性初始值则需要 类名.变量名 = new value
Person.name = 'bot02'
print(bot.name)  # bot02 默认初始值已经被修改了

类与方法

# 类与方法 ->写在类里面的函数
# 方法种类: 普通方法 类方法 静态方法 魔术方法
# 普通方法:
class Car:
    brand = 'five'
    price = 10000
    type = 'five_001'

    # 普通方法 self:表示当前调用这个方法的对象的内存地址
    def run(self):
        print(f'self = {self}')     # self = <__main__.Car object at 0x00000202C17D3E80>
        print('正在出发,请系好安全带!')
        # 对象传来的属性并不能保证每个调用此方法的对象都有这个属性
        print(self.repair)      # VIP车辆专修!
# 当对象在创建时会在内存空间开辟出一块内存空间,当对象调用类中的方法时-car1.run()-因为对象本身的内存空间中没有这个方法,
# 所以会带着自己的内存空间地址去访问-类模型-的内存地址,并且调用执行类中的-run()-方法 def run(self)中self就是来承接对象的内存地址的
# self的好处是:当对象自身新增某些属性时,可以使用self在类中方法调用这个属性 (感觉有点类似java中的this关键字)
car1 = Car()
car1.repair = 'VIP车辆专修!'
print(car1)     # <__main__.Car object at 0x00000202C17D3E80>
car1.run()      # self = <__main__.Car object at 0x00000202C17D3E80>    正在出发,请系好安全带!
# 但对象传来的属性,并不能保证每个调用此方法的对象都有这个属性,所以当遇到没有这个属性的对象调用方法时,就会报错并结束运行
car2 = Car()
car2.run()      # AttributeError: 'Car' object has no attribute 'repair' 程序运行报错,因为car2和类中都有没repair属性

 

# 既然方法无法保证每个对象都能有repair这个自定义属性,那么我们应该怎么解决这个问题呢?
# 使用魔术方法: def__init__(self):    init-初始化
# init方法是在创建对象之前执行的,self会先拿到分配给对象的内存地址,这里的self就代表每个使用类的对象,使用self调用对象达到给属性赋值的功能
# init方法可以让每个对象达到统一性,对象也可以再自定义属性.说白了就是个属性的初始化
class Car:
    brand = 'five'
    price = 10000
    type = 'five_001'

    # 添加初始化方法解决这个问题
    def __init__(self):
        self.repair = '统一售后检修'

    # 普通方法 self:表示当前调用这个方法的对象的内存地址
    def run(self):
        print(f'self = {self}')     # self = <__main__.Car object at 0x00000202C17D3E80>
        print('正在出发,请系好安全带!')
        # 对象传来的属性并不能保证每个调用此方法的对象都有这个属性
        print(self.repair)      # 日常维修车辆!


car3 = Car()
car3.repair = 'VIP车辆精修'
car3.run()      # VIP车辆精修

car4 = Car()
car4.run()      # 统一售后检修
# 普通方法: 在类中定义的方法,只有通过对象才能调用的方法
# 我们知道,在类中封装的是公共的特征与公共的行为动作,那当我们需要使用对象不同个体的动作方法或特征时,应该怎么办呢?
# 上面我们使用了__init__()初始化方法保证了我们每个对象的统一性,这里也可以使用这个方法解决这个问题 (有点像java类的构造函数)
# 再来一遍流程:在p1 = Person(xx,xx)时,Person()的动作:
#   1-先在内存中找到Person类的地址 
#   2-为p1按Person的模子划分一块内存地址
#   3-将p1划分的内存地址先传递给init的self中,完成初始化函数的运行 
#   4-将划分的内存地址再传递给p1变量
class Person:
    # 初始化函数 将创建对象传递的参数赋值    这里的self相当于不同的调用的对象的内存空间 **p1\p2...
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def self_introduction(self):
        print(f'我的名字是{self.name},我今年{self.age}岁了!')

    # 方法中我们也可以定义传参运行
    def eat(self, food):
        print(f'今天想吃{food}')


# 通过上面我们初始化函数的定义,我们就可以根据对象个体不同的方法特征进行不同的传值
p1 = Person('bob', 25)
p1.self_introduction()  # 我的名字是bob,我今年25岁了!
p1.eat('红烧茄子')  # 今天想吃红烧茄子

p2 = Person('coc', 26)
p2.self_introduction()  # 我的名字是coc,我今年26岁了!
p2.eat('鱼香茄子')  # 今天想吃鱼香茄子
类方法

# 类方法特点: 1-在方法上加上装饰器@classmethod 2-类方法的参数时cls类而不是self对象
#           3-类方法中不能使用self的对象属性和方法,只能使用类属性和类方法
# 类方法作用: 1-可以完成一些在对象创建之前需要完成的动作
class Dog:
    def __init__(self, name):
        self.name = name

    @classmethod
    def class_test(cls):
        print(cls)  # 
        print('类方法运行')

    def eat(self):
        print(f'{self.name}开吃')


d1 = Dog('aoa')
d1.eat()    # aoa开吃
d1.class_test()     # 
# 可以直接使用类调用类方法,无需对象参与
Dog.class_test()    # 类方法运行
# 假如上面的Dog类我们需要加入私有属性__age 代表默认狗狗都是初始年龄 但要在后续更改这个年龄怎么办呢?
# __变量:表示私有变量 只能在类中被访问
# 定义类方法访问类中的私有属性
class Dog:
    __age = 1

    @classmethod
    def update_age(cls):
        cls.__age = 2
        print(f'修改后的age:{cls.__age}')

    @classmethod
    def show_age(cls):
        print(f'dog的年龄为{cls.__age}')


d2 = Dog()
d2.show_age()  # dog的年龄为1
d2.update_age()  # 修改后的age:2
d2.show_age()  # dog的年龄为2
静态方法
# 静态方法: 
# 1-需要装饰器@staticmethod 
# 2-静态方法def staticmethod()中没有任何参数
# 3-使用类名调用静态方法 
# 4-静态方法只能调用类属性和类方法 
# 5-随着类的加载,静态方法和类方法会一同加载进内存,所以可以直接使用类名调用
class Student:
    @staticmethod
    def study():
        print('提高一分,干掉千人!')


s1 = Student()
s1.study()  # 提高一分,干掉千人!
Student.study()  # 提高一分,干掉千人!
# 普通方法总结: 
        1-没有装饰器
        2-需要依赖对象使用
# 静态方法和类方法总结: 
        1-装饰器不同 
        2-参数类方法有静态方法没有 
        3-只能访问类属性和类方法 
        4-都可以通过类名调用 
        5-都可以在创建对象之前使用

魔术方法 

# 魔法方法: 是类/对象中的方法,和普通方法不同,魔术方法不需要调用,而是在特定的时刻自动触发
# __new__(cls, *args, **kwargs): 在对象实例化时触发,底层主要是申请内存开辟空间后,为__init__(self)对象分配这块内存空间.
# self=new返回的内存空间地址  __init__(self)拿到这块地址后执行init方法的操作,执行完后再将这块内存地址分配给实例化的对象变量
# 类中重写__new__()方法,需要添加return super().__new__(cls)语句,返回开辟的内存地址才能正常运行下去

# __init__(self): 在对象初始化时触发,为对象进行初始化操作 创建完空间之后调用的第一个方法(构造方法)

# __call__(self, *args, *kwargs): 将对象当作函数调用时会触发 ->对象名() 如果需要将对象当作函数调用时需要手动重写__call__()方法

# __del__(self): delete的缩写,析构魔术方法 python解释器在程序运行结束时会回收本次执行所开辟的所有内存空间
# 在对象内存被删除回收时自动触发__del__(self)方法,当一块内存空间没有了任何引用,就会默认执行__del__()方法
# 1-对象创建后没有引用,会在创建后立即删除,执行__del__()方法
# 2-对象创建后一直使用变量引用,则会在所有代码执行完毕后删除所有对象,执行__del__方法
# 3-对象创建并使用变量引用保存,主动使用del关键字删除变量引用,当对象的所有引用变量都被删除,对象也相当于被删除,执行__del__()方法

# __str__(self): 有点类似于java的toString()方法,对象的变量名打印出来是内存地址,重写__str__()方法后,打印对象变量名会按你定义的方式做返回,在打印对象引用的变量名时自动触发,需要在__str__(self)方法中添加return,return的内容就是打印对象变量名时看到的数据!
class Person:
    def __new__(cls, *args, **kwargs):
        print('----> __new__()执行')
        address = super().__new__(cls)
        print('new开辟空间地址:', address)  # new开辟空间地址: <__main__.Person object at 0x000001A3B3A757E0>
        return address

    def __init__(self, name):
        self.name = name
        print('____> __init__()执行')
        print('init初始化地址:', self)  # init初始化地址: <__main__.Person object at 0x000001A3B3A757E0>

    def __call__(self, *args, **kwargs):
        print('当对象被当作函数调用时--->触发call()')

    def __del__(self):
        print('对象内存地址被回收时触发的__del__()方法!')

    def __str__(self):
        return f'当前对象引用变量名地址'


p1 = Person('bob')
print('对象p1地址:', p1)  # 对象p1地址: <__main__.Person object at 0x000001A3B3A757E0>
p1()  # 当对象被当作函数调用时--->触发call()
print(p1)  # 当前对象引用变量名地址

 

 面向对象实例练习

class Cat:
    type = '猫科猫属动物'

    # 对象初始化调用
    def __init__(self, name, age, color):
        self.name = name
        self.age = age
        self.color = color

    def catch_mouse(self, color, weight):
        print(f'{self.name},抓到了{color}颜色,重{weight}kg的老鼠!')

    def eat(self, food):
        print(f'{self.name}爱吃{food}')

    def sleep(self, hour):
        if hour < 5:
            print(f'{self.name}还没睡够5小时,可以接着睡!')
        else:
            print(f'可以去抓老鼠了,睡了{hour}个小时了!')

    def show_info(self):
        print(f'{self.name}是一只{self.color}的猫,今年{self.age}岁了!')


c1 = Cat('旺财', 5, '白色')
c1.catch_mouse('黑色', 5.5)  # 旺财,抓到了黑色颜色,重5.5kg的老鼠!
c1.sleep(4)  # 旺财还没睡够5小时,可以接着睡!
c1.sleep(6)  # 可以去抓老鼠了,睡了6个小时了!
c1.eat('极品猫粮')  # 旺财爱吃极品猫粮
c1.show_info()  # 旺财是一只白色的猫,今年5岁了!

私有化 

# 私有化: 在类内将属性私有化,再通过公有的方法进行私有属性的修改(很像Java的getter和setter)
# 私有化其实就是封装,通过'__属性名'形式定义属性以确保该私有化属性只能在本类中进行访问,不对外提供
# 如果想得到和修改私有化属性,我们可以定义公共方法供外界使用(get - set方法) 
class Student:
    # 通过init初始化方法在对象内存空间中定义私有化属性
    def __init__(self, name, age, scores):
        self.__name = name
        self.__age = age
        self.__scores = scores

    def __str__(self):
        return f'姓名:{self.__name},年龄:{self.__age},考试成绩:{self.__scores}'


s1 = Student('沃得发', '25', 88)
print(s1)   # 姓名:沃得发,年龄:25,考试成绩:88

# 如果我们想通过对象名直接获取属性的话是不行的,我们需要添加方法(get\set方法)
print(s1.name)  # 'Student' object has no attribute 'name'

class Student:
    # 通过init初始化方法在对象内存空间中定义私有化属性
    def __init__(self, name, age, scores):
        self.__name = name
        self.__age = age
        self.__scores = scores

    def __str__(self):
        return f'姓名:{self.__name},年龄:{self.__age},考试成绩:{self.__scores}'

    def get_name(self):
        return self.__name

    def set_name(self, name):
        self.__name = name

    def get_age(self):
        return self.__age

    def set_age(self, age):
        self.__age = age

    def get_scores(self):
        return self.__scores

    def set_scores(self, scores):
        self.__scores = scores


s2 = Student('王德梅', '26', 59)
print(s2)  # 姓名:王德梅,年龄:26,考试成绩:59
# 通过get()方法得到对象的私有属性
print(s2.get_name())  # 王德梅
print(s2.get_age())  # 26
print(s2.get_scores())  # 59
# 通过set()方法修改对象的私有属性
s2.set_name('李得胜')
s2.set_age('36')
s2.set_scores(66)
print(s2)  # 姓名:李得胜,年龄:36,考试成绩:66 修改成功!
# 使用get,set方法的好处,可以在修改属性值的时候加入逻辑判断,私有属性不被外界随意修改
*知识延展
# dir(对象) list形式返回对象内部的属性和方法
print(dir(Student))
print(dir(s2))
print(s2.__dir__())   # 如果对象可以调用__dir__()方法,这个方法和dir(对象)作用相同
# 通过dir方法,我们可以在s2对象中找到这三个属性名    '_Student__age', '_Student__name', '_Student__scores',
# 这三个属性名就是属性私有化的原因,我们无法通过s2.__age得到这个属性,是因为底层会自动为私有属性名前拼接'_类名'
# [_类名 + __age = '_Student__age'],原本的属性名经过底层的修改变成了'_Student__age',可以访问但不建议 -防君子不防小人-
print(s2._Student__age)  # 36 其实通过这个变形拼接后的名字还是可以访问到的 可以访问但不建议 -防君子不防小人-

@property装饰器 

# @property功能1:
# 前面通过属性的私有化定义,get\set方法得到\修改对象的私有化属性其实已经搞得不丑了,只是没法通过 对象.属性名 的方法直接访问修改罢了
# 那么如果我们想要像普通属性那种形式访问修改的话,应该怎么做呢? 这里就需要使用这个装饰器: @property
class Student:
    # 通过init初始化方法在对象内存空间中定义私有化属性
    def __init__(self, name, age, scores):
        self.__name = name
        self.__age = age
        self.__scores = scores

    def __str__(self):
        return f'姓名:{self.__name},年龄:{self.__age},考试成绩:{self.__scores}'

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age <= 120:
            self.__age = age
        else:
            print('年龄赋值失败!')

    @property
    def scores(self):
        return self.__scores

    @scores.setter
    def scores(self, scores):
        self.__scores = scores
# 还是相同的类,我们只不过需要在这几个私有属性上面加上我们的装饰器 get()方法需要加 @property私有属性名 set()方法需要加@私有属性名.setter
# 这样我们就可以直接通过[对象名.私有属性名]对私有属性进行打印和修改了
s3 = Student('刘彪', '36', 77)
print(s3)  # 姓名:刘彪,年龄:36,考试成绩:77
print(s3.name)  # 刘彪
print(s3.age)  # 36
print(s3.scores)  # 77
# 得到私有属性值打印是没什么问题了,试试修改怎么样
s3.name = '张彪'
s3.age = 46
s3.scores = 88
print(s3)  # 姓名:张彪,年龄:46,考试成绩:88   修改测试也成功 由此可见 @property装饰器可以实现我们想要的功能!
# 可能有些同学到这里有点疑问了,既然这种方式访问修改和原本没什么区别,那为什么要搞个私有化呢?这个私有化还有什么意义呢?
# 这里我就不得不提一嘴了,我们加上@property装饰器只是为了使用起来和之前一样,但我们还可以在get\set方法体种加入逻辑代码,这是非私有化属性不具备的!
# 我们可以age判断,如果大于120岁则显示赋值失败试试
s3.age = 125  # 年龄赋值失败!   测试成功!
print(s3)  # 姓名:张彪,年龄:46,考试成绩:88
# @property 装饰器功能2: 可以与所定义的属性配合使用,让属性不被修改.变为只读属性.
class PropertyTest:
    def __init__(self):
        self._name = '张三'  # Property 'name' cannot be set
        self._age = '25'  # Property 'age' cannot be set

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age


p1 = PropertyTest()
print(p1.name)  # 张三
print(p1.age)  # 25

p1.name = '李四'  # can't set attribute 'name' 这样我们的私有化属性就通过装饰器变成只读属性了!

*知识扩展

# python中,单下划线属性类似于Java中的protected,双下划线类似于Java中的private,
# 但是python中的私有属性仍可以通过_ClassName__FileName这种名字访问到,所以python没有真正意义上的私有
# @property最大的好处就是在类中把一个方法变成属性调用,起到既能检查属性,还能用属性的方式来访问该属性的作用。

对象的组合与继承 

# 我们在这里要理解两个概念,一个是组合关系(has a)另一个是(is a)继承关系
# 什么是has a呢?(class A has a kind of class B.意为A类是B类的一部分)
#   在一个类中,通过创建另一个类的对象,调用其属性和方法完成某种操作或运算,称为组合关系(比如dog has a leg)
class Computer:
    def __init__(self, brand, color):
        self.brand = brand
        self.color = color

    def __str__(self):
        return f'电脑品牌:{self.brand},电脑颜色:{self.color}'


class Book:
    def __init__(self, book_name, book_num):
        self.book_name = book_name
        self.book_num = book_num

    def __str__(self):
        return f'书名:{self.book_name},数量:{self.book_num}'


class Student:
    def __init__(self, name, computer, book):
        self.name = name
        self.computer = computer
        self.books = []
        self.books.append(book)

    def borrow_book(self, borrow_book):
        for book in self.books:
            if book.book_name == borrow_book.book_name:
                print(f'已经有<{borrow_book.book_name}>这本书了')
                break
        else:
            self.books.append(borrow_book)
            print('没有这本书,现在添加成功!')

    def show_books(self):
        # 这里的book是传进来的Book对象
        for book in self.books:
            print(book.book_name)

    def __str__(self):
        return f'学生:{self.name}的电脑:{self.computer},书本有:{self.books}'


c1 = Computer('dell', '黑金色')
b1 = Book('乌合之众', 2)
b2 = Book('乌合麒麟', 8)
s1 = Student('李得胜', c1, b1)

print(c1)  # 电脑品牌:dell,电脑颜色:黑金色
print(b1)  # 书名:乌合之众,数量:2
print(b2)  # 书名:乌合麒麟,数量:8
print(s1)  # 学生:李得胜的电脑:电脑品牌:dell,电脑颜色:黑金色,书本有:[<__main__.Book object at 0x000001C790513E20>]

s1.show_books()  # 乌合之众
s1.borrow_book(b2)  # 没有这本书,现在添加成功!
s1.show_books()
# 在python中,除了python初始的系统类(str,list,tuple,dict,set..)之外,我们定义的每一个class都可以被python看作是一个自定义类型
# 在上面的例子中,我们s1(学生对象的内存空间)中,包含了传来的b1和c1这两个另外的自定义类型,这种就是组合关系(has a) -> 把另一个类的对象当成属性传递
# 学生类由电脑对象和书本对象组合而成 student has a computer - student has a book
# 什么是is a呢?(Is-a全称class A is a kind of class B.意为A类是B类的一种具体情况)
#   如果B类是基类,在B类中定义了很多基础属性和方法,A类作为其中一种情况,可以继承B类再添加自己的独有方法(比如Apple is a Fruit)
# 继承:一个类可以继承另一个类里的所有属性和方法,比如手机需要更新,设计师会直接继承老手机的设计图,在这个设计图上修修改改添加新功能.这就是一种继承!
# 当子类对象调用属性或方法时,因为在本类中没有找到,所以会往上去父类中找.
# 单继承: class 子类(父类)
# 作为2023年新产品的华威手机,我们加入了5G通话功能,在设计之初,我们不用将4G也取消掉,直接拿之前设计图来用就可以了
class Phone:
    producer = '华威'

    def __init__(self, brand, color, price):
        self.brand = brand
        self.color = color
        self.price = price

    def __str__(self):
        return f'{self.brand}:{self.color}:{self.price}'

    def call_4g(self):
        print('4G通话功能!')


class Phone2023(Phone):
    def call_5g(self):
        print('5G通话功能!')


phone23 = Phone2023('华威', '远峰蓝', 9999)
print(phone23)  # 华为:远峰蓝:9999
phone23.call_4g()  # 4G通话功能!
phone23.call_5g()  # 5G通话功能!
# 在python中不支持重载,但可以多继承
# 多继承: class 子类(父类1,父类2...) 如果多个父类定义了同名属性,则谁先被继承(谁在左边)谁的优先级高
# 那么作为华威手机,我们还需要添加NFC读卡器功能,目前市面上有设计图纸,我们便一并拿来使用即可.这就是多继承!
class NFCReader:
    producer = '小蜜'

    def write_NFC(self):
        print('写入NFC功能!')

    def read_NFC(self):
        print('读取NFC功能!')


class Phone23Pro(Phone, NFCReader):
    def call_5g(self):
        print('5G通话功能!')


phone23pro = Phone23Pro('华威', '远峰蓝', 19999)
print(phone23pro)  # 华威:远峰蓝:19999
phone23pro.call_4g()  # 4G通话功能!
phone23pro.call_5g()  # 5G通话功能!
phone23pro.write_NFC()  # 写入NFC功能!
phone23pro.read_NFC()  # 读取NFC功能!
print(phone23pro.producer)  # 华威 当多继承的父类有同名属性,会继承第一个继承的父类内容 根据继承顺序,从左到右广度优先
# 方法重写与super()父类调用
# 如果子类对继承来的父类中的方法不满意,可以进行复写(在子类中定义同名的属性或方法即可).
class Phone23Mini(Phone):
    producer = '华伟'

    def call_4g(self):
        print('Mini残血芯片运行')
        print(f'父类厂商为:{super().producer}')
        print(f'本代工厂商为:{self.producer}')
        super().call_4g()
        print('Mini版本降低续航与通话信号')


phone23mini = Phone23Mini('华威', '黑色', 2999)
print(phone23mini)  # 华威:黑色:2999
phone23mini.call_4g()  # Mini残血芯片运行 父类厂商为:华威 本代工厂商为:华伟 4G通话功能! Mini版本降低续航与通话信号
# 通过对父类方法的重写,我们可以灵活的对不同业务需求进行修改,父类原本实现的逻辑如果我们想用,直接使用[super()]进行调用使用就可以了.

继承实例练习

# 工资管理系统,工人(worker) 销售员(salesman) 经理(manager) 销售经理(sales_manager)
# 所有员工(employee)都有工号,姓名,工资,有设置姓名,获取姓名,获取员工号,计算工资等方法
# 工人:工作小时数和时薪属性,工资为工作小时数*时薪
# 销售员:销售额和提成比例属性,工资为销售额*提成比例
# 经理:固定月薪属性,工资为固定月薪
# 销售经理:工资为销售额*提成比例+固定月薪
# 完成功能:添加所有类型成员 计算月薪 显示所有人工资情况
class Employee:

    def __init__(self, __id, __name):
        self.__id = __id
        self.__name = __name

    def __str__(self):
        return f'员工id:{self.__id},员工姓名:{self.__name}'

    # 获取员工号方法
    @property
    def id(self):
        return self.__id

    # 获取姓名方法
    @property
    def name(self):
        return self.__name

    # 设置姓名方法
    @name.setter
    def name(self, name):
        self.__name = name

    # 计算工资方法
    def get_salary(self):
        pass


class Worker(Employee):
    def __init__(self, __id, __name, __hour, __hourly_pay):
        super().__init__(__id, __name)
        self.__hour = __hour
        self.__hourly_pay = __hourly_pay

    # 重写计算工资方法
    def get_salary(self):
        count = self.__hour * self.__hourly_pay * 30
        return count


woker1 = Worker('001', '王大树', 8, 10)
# woker1.id = '002'   # can't set attribute 'id'
woker1.name = '王树'  # 员工id:001,员工姓名:王树
print(woker1)   # 员工id:001,员工姓名:王大树
print(woker1.get_salary())  # 80

# 首先使用一个员工基类将这些共同的属性和方法进行封装,随后我们如上,根据不同的用户类进行不同属性和方法的重写与修改就可以

 

你可能感兴趣的:(python学习,学习,python,开发语言,pycharm,经验分享)