python小练习--面向对象

一、第一部分

练习1:对象可以直接添加实例
#第一个类对象的测试
class Student:

    def __init__(self,name,age):
         self.name = name
         self.age = age

    def get_score(self):
        print("{0}分数是:{1}".format(self.name,self.age))

s1 = Student("Clichong",18)
s1.get_score()

s1.salary = 100000		#直接添加实例salary与score
s1.score = 41
print(s1.salary)

s2 = Student("Xioaqi",41)
print(s2.age)

在这里插入图片描述

练习2:实例对象
#以下两行代码运行得出的结果是相同的
a.say_score()
Student.say_score(a)

在这里插入图片描述

print(dir(s2))
print(type(s2))
print(s2.__dict__)
print(isinstance(s2,Student))

在这里插入图片描述

练习3:类属性
#第一个类对象的测试
class Student:
    company = "sxt"     #类属性
    pname = "aic"

    def __init__(self,name,age):
         self.name = name
         self.age = age

    def get_score(self):
        print("{0}分数是:{1}".format(self.name,self.age))

print(Student.company)
print(Student.pname)

在这里插入图片描述

练习4:类方法
#第一个类对象的测试
class Student:
    company = "sxt"     		#类属性
    pname = "aic"

    @classmethod				#类方法
    def PrintCompany(cls):
        print(Student.company)

    def __init__(self,name,age):
         self.name = name		#实例属性
         self.age = age

    def get_score(self):		#实例方法
        print("{0}分数是:{1}".format(self.name,self.age))

Student.PrintCompany()
练习5:静态方法
#第一个类对象的测试
class Student:
    company = "sxt"     #类属性
    pname = "aic"

    @staticmethod
    def reback(n):      #静态方法,但是无法实现递归
        if n == 0:
            return 1
        else:
            return n

    @classmethod		#类方法
    def PrintCompany(cls):
        print(Student.company)

    def __init__(self,name,age):	#构造函数
         self.name = name			#实例属性
         self.age = age

    def get_score(self):			#实例方法
        print("{0}分数是:{1}".format(self.name,self.age))

Student.PrintCompany()
print(Student.reback(5))

在这里插入图片描述

练习6:可调用对象

定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用

#测试可调用方法_call__()

class SalaryAccount:
    '''工资计算类'''

    def __call__(self, Salary):
        print("算工资啦....")
        yearSalary  = Salary*12
        daySalary = Salary//22.5
        hourSarlay = Salary//8
        monthSalary = Salary

        return dict(yearSalary = yearSalary,monthSalary = monthSalary,daySalary = daySalary,hourSarlay = hourSarlay)

    def __init__(self,name,salary):
        self.name = name
        self.salary = salary

    def Print(self):
        print("hello world")

print(help(SalaryAccount))     #打印出此文档的介绍

s1 = SalaryAccount("aa",2131)
s1.Print()

s2 = SalaryAccount("21",131)
s2.Print()
print(s2(10000))

s3 = SalaryAccount("Clichong",3000)
print(s3.salary)
print(s2.salary)
print(s1.name)

在这里插入图片描述
在这里插入图片描述

class SalaryAccount:
    def __call__(self):				#可调用对象设置
        return 100

    def __init__(self,salary):		#构造函数
        self.salary = salary

    def Print(self):				#实例方法
        print(self.salary)

s1 = SalaryAccount(1)
s1.Print()

s2 = SalaryAccount(2)
s2.Print()
print(s2())	#调用可调用对象,打印100

在这里插入图片描述

练习7:动态的改变函数
#测试可调用方法_call__()

class SalaryAccount:
    def __call__(self):
        return 100

    def __init__(self,salary):
        self.salary = salary

    def Print(self):
        print(self.salary)

def Print01(self):
#要注意,此处要带一个参数,否则会报错,因为SalaryAccount累中的Print函数也是带一个参数的
    print("好好学习,天天向上")

s1 = SalaryAccount(1)
s1.Print()

s2 = SalaryAccount(2)
s2.Print()
print(s2())

SalaryAccount.Print = Print01
s2.Print()      #要注意,此处不可以加参数,因为本来已经存在一个隐含的参数self

在这里插入图片描述
补充:

class Myfunction:
    pass

class MyAddfunction:

    mynum = None

    def __call__(self, num):    #使得对象可以像函数一样被调用
        self.mynum = num
        return self.mynum


    def __init__(self,num):     #构造函数,需要初始化的时候需要使用这个函数
        self.mynum = num

    def __add__(self, other):   #重载+运算符
        if isinstance(other,MyAddfunction):
            print("myadd_function...")
            return self.mynum*other.mynum
        else:
            print("不是同类,不能相加")

    def __mul__(self, other):   #重载*运算符
        if isinstance(other,MyAddfunction):
            print("mymul_function...")
            return self.mynum+other.mynum
        else:
            print("不是同类,不能相乘")


def mywork(s):          #在类之外定义两个方法
    print("mywork")

def mygame(s):
    print("myganme")

MyAddfunction.work = mywork     #动态的增加类方法
MyAddfunction.game = mygame

p = MyAddfunction(20)
p.work()        #可以正常进行工作
p.game()

在这里插入图片描述

练习8:私有属性
  1. 测试1
class Clichong:

    def __init__(self,name,salary):
        self.name = name
        self.salary = salary

    def Print(self):
        print(self.name)
        print(self.salary)

a = Clichong("Tom",10000)
a.Print()
print(dir(a))

在这里插入图片描述
2. 测试2

class Clichong:

    def __init__(self,name,salary):
        self.__name = name      #定义私有属性
        self.__salary = salary  #定义私有属性

    def Print(self):
        pass
  #      print(self.name)
   #     print(self.salary)

a = Clichong("Tom",10000)
#a.Print()
print(dir(a))

在这里插入图片描述
3. 测试三

class Clichong:

    def __init__(self,name,salary):
        self.__name = name      #定义私有属性
        self.__salary = salary  #定义私有属性

    def Print(self):
        print(self.name)
        print(self.salary)

a = Clichong("Tom",10000)
a.Print()
print(dir(a))

在这里插入图片描述
4. 测试4

class Clichong:

    def __init__(self,name,salary):
        self.__name = name      #定义私有属性
        self.__salary = salary  #定义私有属性

    def Print(self):
        print(self._Clichong__name)     #由于已经转变为私有属性,改为指定格式才可以打印
        print(self._Clichong__salary)

a = Clichong("Tom",10000)
a.Print()
print(dir(a))

在这里插入图片描述

练习9:私有办法,私有类变量,私有属性

class Clichong:

    __myvar = "今年是2020年"    #定义私有类变量

    def __init__(self,name,salary):
        self.__name = name      #定义私有属性
        self.__salary = salary  #定义私有属性

    def Print(self):
        print(self._Clichong__name)     #由于已经转变为私有属性,改为指定格式才可以打印
        print(self._Clichong__salary)

    def __myprivate(self):      #定义私有方法
        print("hello Clichong")

    def PrintMyvar(self):
        print("__myvar:",Clichong.__myvar)  #内部调用私有类变量,不需要写成_Clichong__myvar的形式,只需要Clichong.__myvar便可

a = Clichong("Tom",10000)

#私有属性的测试
a._Clichong__salary = 200000    #可以直接修改室友属性
print("a._Clichong__salary:",a._Clichong__salary)   #还可以打印出来

#私有类变量的测试
print("a._Clichong__myvar:",a._Clichong__myvar)
a.PrintMyvar()
a._Clichong__myvar = "今年是2021年"         #外部直接调用私有的类变量,需要写成_Clichong__myvar的形式,与私有属性一样,与私有方法也一样
print("a._Clichong__myvar:",a._Clichong__myvar)
a.PrintMyvar()

#打印私有属性测试
a.Print()
print(dir(a))

#使用私有方法测试
# a.__myprivate()           #会失败
a._Clichong__myprivate()    #成功打印

在这里插入图片描述
总结:

  • 在外部调用私有属性,私有类变量和私有方法的操作都是一样的,均是增添为_Clichong__myvar = " "的形式,然后直接p._Clichong__myvar直接调用就可以了。
  • 在内部调用私有类变量,只需要Clichong.__myvar = “”便可
练习10:property修饰器的使用
#property装饰器的使用
# @property 修饰的属性,如果没有加 setter 方法,则为只读属性。此处修改报错
#@property 主要用于帮助我们处理属性的读操作、写操作。

class Employee:

    def __init__(self,name,salary):
       self.name = name
       self.__salary = salary

    @property
    def salary(self):
       print("salary:",self.__salary)
       return self.__salary


    @salary.setter
    def salary(self,salary):
       if(0 < salary < 100000):
           self.__salary = salary
       else:
           print("录入错误")


a = Employee("Clichong",1000)
print(a.salary)

a.salary = -1433
print(a.salary)

在这里插入图片描述

练习11:重写object类中的__str__()函数
class Person:
    "Class name is Person"

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

    def __str__(self):
        return "Today is 2020/11/15"

a = Person("Clichong")
print(a)

在这里插入图片描述

作业1:类方法的小测试

设计一个名为 MyRectangle 的矩形类来表示矩形。这个类包含:
(1) 左上角顶点的坐标:x,y
(2) 宽度和高度:width、height
(3) 构造方法:传入 x,y,width,height。如果(x,y)不传则默认是 0,如果 width
和 height 不传,则默认是 100.
(4) 定义一个 getArea() 计算面积的方法
(5) 定义一个 getPerimeter(),计算周长的方法
(6) 定义一个 draw()方法,使用海龟绘图绘制出这个矩形


import turtle

pen = turtle.Pen()
pen.width(5)
pen.color("blue")
pen.showturtle()

class MyRectangle:

    def __init__(self,x = 0,y = 0,width = 100,height = 100):
        self.x = x
        self.y = y
        self.width = width
        self.height = height

    def getData(self):
        print("x:",self.x)
        print("y:",self.y)
        print("width:",self.width)
        print("height:",self.height)

    def getArea(self):
        area = self.height*self.width
        print("are:",area)

    def getPerimeter(self):
        perimeter = 2*(self.width+self.height)
        print("perimeter:",perimeter)

    def draw(self):
        pen.penup()
        pen.goto(self.x,self.y)
        pen.pendown()
        pen.goto(self.x+self.width,self.y)
        pen.goto(self.x+self.width,self.y-self.height)
        pen.goto(self.x,self.y-self.height)
        pen.goto(self.x,self.y)
        pen.penup()

#a = MyRectangle(width = 100,height = 200,x = 20,y = 10)
a = MyRectangle(width = 100,height = 200)	#直接命名参数
a.getData()
a.getArea()
a.getPerimeter()
a.draw()

while True:
    pass

测试结果:
在这里插入图片描述
在这里插入图片描述

二、第二部分

练习1:多重继承与多态的实现,super函数的使用
#测试多态的实现
class Animal:
    def shout(self):
        print("动物叫")

class Dog(Animal):
    def shout(self):
        print("动物叫,狗也叫")

class Cat(Animal):
    def shout(self):
        print("动物叫,猫也叫")

class Man(Animal):
    def shout(self):
        super().shout()         #调用父类的shout方法
        print("动物叫,人也叫")

class Kid(Dog,Cat,Man):     #python语言中额可以一次性继承多个父类
    def shout(self):
        print("动物叫,小孩叫")

class Child:
    def shout(self):
        print("小屁孩叫,全都叫")

def DefWhoScout(myobject):      #多态的实现
    if isinstance(myobject,Animal):
        myobject.shout()
    else:
        print("原来是个小孩叫")

print(Man.mro())    #由于super函数,会打印父类的方法;还会打印自己的方法
print(Dog.mro())
print(Kid.mro())    #验证python中的多重继承

DefWhoScout(Man())		#注意,此处的类对象Man是有括号的Man()
DefWhoScout(Dog())		#注意,此处的类对象Dog是有括号的Dog()
DefWhoScout(Kid())
DefWhoScout(Child())    #因为其没有继承Animal类,故其会执行else语句,而不是自己的shout函数

在这里插入图片描述

练习2:重载运算符的简单探讨
#重载运算符的实现

#原本的+运算符的用法
num1 = 10
num2 = 20
result = num1 + num2
print("[+]no change result:",result)

class Myfunction:
    pass

class MyAddfunction:

    def __init__(self,num):
        self.num = num

    def __add__(self, other):       #重载+运算符
        if isinstance(other,MyAddfunction):
            return self.num*other.num   #[+]的运算规则是相乘
        else:
            print("不是同类,不能相加")

    def __mul__(self, other):       #重载*运算符
        if isinstance(other, MyAddfunction):
            return self.num + other.num  # [*]的运算规则是相加
        else:
            print("不是同类,不能相加")

t0 = Myfunction()
t1 = MyAddfunction(10)
t2 = MyAddfunction(20)
print("t1:",t1.num,"   t2:",t2.num)

#测试重载后的+运算符
t = t1+t2
print("{0}+{1}={2}".format("t1","t2",t))

#测试重载后的*运算符
t = t1*t2
print("{0}*{1}={2}".format("t1","t2",t))

在这里插入图片描述
补充:想法是让类变成一个对象然后使用重载运算符去调用,但是结果失败了。

#重载运算符的实现
class Myfunction:
    pass

class MyAddfunction:

    mynum = None

    def __call__(self, num):    #使得对象可以像函数一样被调用
        self.mynum = num
        return self.mynum


    def __init__(self,num):     #构造函数,需要初始化的时候需要使用这个函数
        self.mynum = num

    def __add__(self, other):   #重载+运算符
        if isinstance(other,MyAddfunction):
            print("myadd_function...")
            return self.mynum*other.mynum
        else:
            print("不是同类,不能相加")

    def __mul__(self, other):   #重载*运算符
        if isinstance(other,MyAddfunction):
            print("mymul_function...")
            return self.mynum+other.mynum
        else:
            print("不是同类,不能相乘")


'''''''''
t1 = MyAddfunction()
t2 = MyAddfunction()
t = t1(10)+t2(20)       #由于运算符是返回之后再相加,所以没有使用重载的功能
print(t)
'''''''''

t1 = MyAddfunction(10)
t2 = MyAddfunction(20)
t = t1 + t2             #使用了重载的功能
print(t)

在这里插入图片描述
总结:表明了__call__函数是无法与重载运算符一起使用的。

练习3:浅拷贝与深拷贝的探讨
  • 变量的赋值操作
    只是形成两个变量,实际还是指向同一个对象。
  • 浅拷贝
    Python 拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。因此,源对象
    和拷贝对象会引用同一个子对象。
  • 深拷贝
    使用 copy 模块的 deepcopy 函数,递归拷贝对象中包含的子对象。源对象和拷贝对象
    所有的子对象也不同。

总结:
复制操作没有拷贝任何的内容,只是进行地质的赋值也就是指向了同一个的内容。而浅拷贝是拷贝了对象,但是对象的子对象内容不拷贝,只是指向了相同的内容。而深拷贝既拷贝了对象,还拷贝了对象的子对象。

import copy

class MobilePhone:
    def __init__(self,cpu,screen):
        self.cpu = cpu
        self.screen = screen

class CPU:
    def calculate(self):
        print("CPU对象",self)

class Screen:
    def show(self):
        print("屏幕对象",self)

c = CPU()
s = Screen()
m = MobilePhone(c,s)

m.cpu.calculate()
m.screen.show()

#赋值操作
p1 = m
print("p1:",p1," m:",m) #对象地址没有改变
p1.cpu.calculate()      #对象的子对象地址也没有改变,说明还是同一个地址
p1.screen.show()

#浅拷贝操作
p2 = copy.copy(m)       
print("p2:",p2," m:",m) #对象地址发生变化,说明拷贝了一个对象
p2.cpu.calculate()      #对象的子对象没有改变,说明还是指向统一而个地址
p2.screen.show()

#深拷贝操作
p3 = copy.deepcopy(m)
print("p3:",p3," m:",m) #对象地址改变
p3.cpu.calculate()      #子对象的地址也改变,说明是完全拷贝了一个新的
p3.screen.show()

在这里插入图片描述

练习4:工厂模式简单例子

工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进
行统一的管理和控制。

# 工程设计模式
class CarFactroy:
    def createCar(self,brand):
        if brand == "Benz":
            return Benz()
        elif brand == "BWM":
            return BMW()
        elif brand == "BYD":
            return BYD()
        else:
            return "Error! Unknowd Brand!"

class Benz:
    pass

class BMW:
    pass

class BYD:
    pass


factory = CarFactroy()
c1 = factory.createCar("Benz")
c2 = factory.createCar("BYD")

print(c1)
print(c2)

在这里插入图片描述

练习5:单例模式简单例子

单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大的降低开销。
单例模式有多种实现的方式,我们这里推荐重写__new__()的方法。new()方法: 用于创建对象,但我们一般无需重定义该方法。

#单例模式的其中一种实现方法

class MySingleton:

    __obj = None
    __init_flag = True      #设置一个标志,指允许构造一次

    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:               #如果是空对象,则构建一个对象
            cls.__obj = object.__new__(cls) #创建一个新对象
        return cls.__obj

    def __init__(self,name):    #构造函数,希望只构造一次,所以再定义一个标志
        if MySingleton.__init_flag:
            print("init...")
            self.name = name
            MySingleton.__init_flag = False #之后永远不会再定义第二个标志

#可以看出,两个是同一个对象
a = MySingleton("Clichong")
print(a)
b = MySingleton("Kacura")
print(b)

在这里插入图片描述

class MySingle:

    object_flag = None

    def __new__(cls, *args, **kwargs):
        if cls.object_flag == None:
            cls.object_flag = object.__new__(cls)
        return cls.object_flag

    def __init__(self,number):	#不对构造函数作出限定,则其会不断地进行构造然后覆盖,不符合意思
        self.number = number

p3 = MySingle(10)
p4 = MySingle(20)
print(p3.number)
print(p4.number)

在这里插入图片描述

ps:

· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访 问这些成员。 ·
·xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外 部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)

作业2:组合的使用

定义发动机类 Motor、底盘类 Chassis、座椅类 Seat,车辆外壳类 Shell,并使用组合
关系定义汽车类。其他要求如下:
定义汽车的 run()方法,里面需要调用 Motor 类的 work()方法,也需要调用座椅
类 Seat 的 work()方法,也需要调用底盘类 Chassis 的 work()方法。

class Motor:
    def work(self):
        print("In Motor Work...")

class Chassis:
    def work(self):
        print("In Chassis Work...")

class Seat:
    def work(self):
        print("In Seat Work...")

class Shell:
    def work(self):
        print("In Shell Work...")

class Car:
    def __init__(self,motor,chassis,seat,shell):
        self.motor = motor
        self.chassis = chassis
        self.seat = seat
        self.shell = shell

    def run(self):
        self.motor.work()
        self.shell.work()
        self.seat.work()
        self.chassis.work()

Mo = Motor()
Sh = Shell()
Se = Seat()
Ch = Chassis()

mycar = Car(Mo,Sh,Se,Ch)
mycar.run()

在这里插入图片描述

作业3:使用工厂模式、单例模式实现如下需求

(1) 电脑工厂类 ComputerFactory 用于生产电脑 Computer。工厂类使用单例模式,
也就是说只能有一个工厂对象。
(2) 工厂类中可以生产各种品牌的电脑:联想、华硕、神舟
(3) 各种品牌的电脑使用继承实现:
(4) 父类是 Computer 类,定义了 calculate 方法
(5) 各品牌电脑类需要重写父类的 calculate 方法

class ComputerFactory:

    __single_flag = None

    def __new__(cls, *args, **kwargs):      #设置成单例模式
        if cls.__single_flag == None:
            cls.__single_flag = object.__new__(cls)
        return cls.__single_flag

    def ProtectComputer(self,brand):        #工程模式,没有写构造函数
        if brand == "联想":
            return Lenovo()
        elif brand == "华硕":
            return HuaShuo()
        elif brand == "神舟":
            return ShenZhou()
        else:
            print("Error! Unknowed Brand!!!")

class Computer:     #父类
    Flag = 111200
    def calculate(self):
        pass

#定义三个子类继承父类
class ShenZhou(Computer):
    def calculate(self):
        print("Produce Shenzhou computer...:",self.Flag)

class Lenovo(Computer):
    def calculate(self):
        print("Produce Lenovo computer...:",self.Flag)

class HuaShuo(Computer):
    def calculate(self):
        print("Produce Huashuo computer...:",self.Flag)

#定义两个对象来测试单例模式
myfacture = ComputerFactory()
myotherfacture = ComputerFactory()
print(myfacture)
print(myotherfacture)

#生产不同的电脑测试工厂模式
c1 = myfacture.ProtectComputer("联想")        #更换了对象也是无所谓的,因为是同一个对象
c2 = myotherfacture.ProtectComputer("华硕")
c3 = myfacture.ProtectComputer("神舟")

#调用各自改写父类的方法
c1.calculate()
c2.calculate()
c3.calculate()

在这里插入图片描述

练习4:property 设置属性的 get 和 set 方法与重载的混合使用

定义一个 Employee 雇员类,要求如下:
(1) 属性有:id、name、salary
(2) 运算符重载+:实现两个对象相加时,默认返回他们的薪水和
(3) 构造方法要求:输入 name、salary,不输入 id。id 采用自增的方式,从 1000 开
始自增,第一个新增对象是 1001,第二个新增对象是 1002。
(4) 根据 salary 属性,使用@property 设置属性的 get 和 set 方法。set 方法要求输
入:1000-50000 范围的数字。

class Employee:

    employee_id = 1000

    def __init__(self,name,salary):     #构造函数
        self.name = name
        self.__salary = salary
        self.id = self.employee_id
        Employee.employee_id += 1       #实现id自增

    def __add__(self, other):           #重载+运算符,对象相加返回的是工资相加
        if isinstance(other,Employee):
            return self.__salary+other.__salary
        else:
            print("Error! 不是同一种类型")

    @property                   #将函数salary修饰为一个对象,返回的工资金额,也就是赋值与工资保存
    def salary(self):
        return self.__salary

    @salary.setter              #限制工资的录入范围
    def salary(self,salary):
        if(1000 < salary < 50000):
            self.__salary = salary
        else:
            print("Error! Salery Info Error!!!")

#定义了3个对象
emp1 = Employee("Clichong",35000)
emp2 = Employee("Kacura",15000)
emp3 = Employee("Lawrence",25000)

#id自增测试
print("id = {0} name = {1} salary = {2}".format(emp1.id,emp1.name,emp1.salary))
print("id = {0} name = {1} salary = {2}".format(emp2.id,emp2.name,emp2.salary))
print("id = {0} name = {1} salary = {2}".format(emp3.id,emp3.name,emp3.salary))

#重载了+运算符测试
emp = emp1+emp2
print("emp1+emp2=",emp)
emp = emp2+emp3
print("emp2+emp3=",emp)

#property 设置属性的 get 和 set 方法测试
print(dir(emp1))
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = 10500         #property修饰器使得salary函数变成了一个对象去使用
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = -1000         #会报错,因为超出了范围
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)
emp1.salary = 45000         #emp1的salary又重新被修改为45000
print("emp1.salary:",emp1.salary,"emp1._Employee__salary:",emp1._Employee__salary)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44751294/article/details/109503577