python基础 第七八课 类与对象

面向对象程序设计方法的基本思想是将任何事物都当做对象,是其所属对象类的一个实例。

定义:类是具有相同属性和方法的对象的集合。类的属性,实际上就是类内部的变量;类的方法是在类内部定义的函数。

         对象是具体的事物,是类实例化 的结果。每个对象的属性值可能不同,但所有由同一个类实例化的来的对象拥有共同的属性和方法。

格式:使用类之前,先定义类。类定义后就产生一个名字空间,与函数类似,在类内部使用的属性,相当于函数中的变量名。

class Myclass:
    '''
    一个简单实例类
    '''
    i=1235
    def f(self):
        return('hello word')
    #实例化类
x=Myclass()
#访问类的属性和方法
print('myclass类的属性i为:',x.i)
print('myclass类的方法f()输出为',x.f())
#很多类都倾向于将对象创建为有初始状态的,因此类可能会定义一个名为__init__()
#的特殊方法(构造方法,如下)
def __init__(self):
    self.data=[]
#类定义了__init__()方法的话,类的实例化操作会自动调用__init__()方法。所以,
#在下例中,可以创建一个这样新的实例
x=Myclass()
#__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上,如
class Complex:
    def __init__(self,realpart,imagpart):
        self.r=realpart
        self.i=imagpart#对象属性
x=Complex(3.0,-4.5)
print(x.r,x.i)

#self代表类的实例,而非类
# 类的方法和普通函数只有一个区别--必须有一个额外的参数,self
class Test:
    def prt(sel):
        print(sel)
        print(sel.__class__)
t=Test()
t.prt()
#从执行结果可看出,self代表的是类的实例,代表当前对象的地址
#self.class则指向类。self不是关键字,换成其他字符也是可以的


类的方法: 在类的内部,使用 def 关键字来定义一个方法,必须包含 self 为第一个参数, self 代表是类的实例

class People2:
    #定义基本属性
    name=''
    age=0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight=0
    #定义构造方法
    def __new__(cls,*args,**kwargs):
        print('执行__new__',args[0],args[1])
        return object.__new__(cls)
    def __init__(self,n,a,w):
        self.name=n
        self.age=a
        self.__weight=w
    def speak(self):
        print("%s说他%d岁,%d斤"%(self.name,self.age,self.__weight))
p=People2('小明',20,80)
p.speak()
__new__(cls,*agrs,**kwargs):在类调用init方法时,new方法决定是否要用init方法,因为new可以调用其他类的方法,或者返回别的对象来作为本类的实例;
class Student:
    def __new__(cls, *args, **kwargs):
        print("执行__new__",args[0],args[1]);
        return object.__new__(cls);#固定语法
    def __init__(self,name,age):
        print("执行__init__",name,age);
        self.name=name;
        self.age=age;
    def showName(self):
        print("姓名:{}".format(self.name));
zhangsan=Student("张三",22);
zhangsan.showName();
对象属性:私有    共有
 如果有一些属性不想给外部权限来访问或者修改,可以在属性或者方法的名字前加两个下划线 ,声对象属性明为私有属性。则在外部调用该属性时抛出错误.

class Person(object):
    def __init__(self, name):
        self.name = name;
        self._title = 'Mr';
        self.__job = 'Student';#"__"声明为私有属性
p = Person('Bob');
print (p.name);
print (p._title);
print (p.__job);
封装:将属性和方法封装,外部是不可见的,只有类提供的接口才能与属于类的实例进行信息交换。

 步骤分2步:先将属性私有化,在用get set 方法

更好的解决方法是用@property注解

__del__():自动销毁方法

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __del__(self):
        print("对象张三被销毁")
zhangsan = Person("张三", 20)
zhangsan.__del__();

测试一个对象被引用多少次:import sys,位置在第一行

语法:sys.getrefcount(t)返回 从2开始

import sys#此行代码需写在编辑器头部
class Person:
    def __init__(self,name,age):
        self.name=name;
        self.age=age;
zhangsan=Person("张三",20);
print(sys.getrefcount(zhangsan));
  • 访问私有属性可以通过 对象._类名__属性访问到,但不建议用
  • id()函数,用于的代对象的标识符
  • 类属性区别于对象属性
  • 类方法上添加@classmethod装饰器时,可以调用类属性,也可以通过对象调用类属性;
  • 修改类属性的2种方式:1.类名.类属性=... ; 2.实例对象__class__类属性=..
  • 静态方法:前面加@ataticmethod 可以有参数,和类,对象都没有关系,可通过类和对象调用dir() __dir__ 用于展示一个内容(类或对象)的内部数据
    print(dir(zhangsan));
    print(zhangsan.___dir___())
    # 由于Python是动态语言,根据类创建的实例可以任意绑定属性。
    # 给实例绑定属性的方法是通过实例变量,或者通过self变量:
    # class Student(object):
    #
    #     gender=''   #这个是类属性,下面两个是实例属性的定义方法
    #     def __init__(self,name):
    #         self.name=name  #通过self变量
    # s=Student('Bob')
    # print(s)
    # s.score=90 #通过实例变量
    #
    # class Student(object):
    #     name='Student'
    # s=Student()  #创建实例s
    # print(s.name)  #打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
    # print(Student)
    #
    # class Student(object):
    #     def __init__(self,name,score):
    #         self.name=name
    #         self.score=score
    # bart=Student('Bart',20)
    # print(bart.name)
    
    # 数据封装
    # 面向对象编程的一个重要特点就是数据封装。在上面的Student类中,每个实例就拥有各自的name和score这些数据。我们可以通过函数来访问这些数据,比如打印一个学生的成绩
    # class Student(object):
    #     def __init__(self,name,score):
    #         self.name=name
    #         self.score=score
    # bart=Student('Bart',20)
    # print(bart.name)
    # def print_score(std):
    #     print('%s:%s'%(std.name,std.score))
    #但是,既然Student实例本身就拥有这些数据,要访问这些数据,就没有必要从外面的函数去访问,可以直接在Student类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和Student类本身是关联起来的,我们称之为类的方法:
    # class Student(object):
    #
    #     def __init__(self, name, score):
    #         self.name = name
    #         self.score = score
    #
    #     def print_score(self):
    #         print('%s: %s' % (self.name, self.score))  #封装的类的方法
    
    #要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:
    # bart.print_score()
    # 这样一来,我们从外部看Student类,就只需要知道,创建实例需要给出name和score,而如何打印,都是在Student类的内部定义的,这些数据和逻辑被“封装”起来了,调用很容易,但却不用知道内部实现的细节。
    # 封装的另一个好处是可以给Student类增加新的方法,比如get_grade:
    # class Student(object):
    #     def get_grade(self):
    #         if self.score >= 90:
    #             return 'A'
    #         elif self.score >= 60:
    #             return 'B'
    #         else:
    #             return 'C'
    # 同样的,get_grade方法可以直接在实例变量上调用,不需要知道内部实现细节:
    # 小结
    # 类是创建实例的模板,而实例则是一个一个具体的对象,哥哥实例拥有的数据都相互独立,胡不影响
    #方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据
    # 通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现方式
    
    #继承和多态
    # 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
    class Animal(object):
        def run(self):
            print("Animal is running...")
    # 当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:
    # class Dog(Animal):
    #     pass
    # class Cat(Animal):
    #     pass
    # 对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
    # 继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:
    # dog=Dog()
    # print(dog.run())
    # 当然,也可以对子类增加一些方法,比如Dog类:
    class Dog(Animal):
        def run(self):
            print('Dog is running...')
        def eat(self):
            print('Eating meat...')
    dog=Dog()
    print(dog.run())
    print(dog.eat())
    # 继承的第二个好处需要我们对代码做一点改进。你看到了,无论是Dog还是Cat,它们run()的时候,显示的都是Animal is running...,符合逻辑的做法是分别显示Dog is running...和Cat is running...,因此,对Dog和Cat类改进如下:
    class Dog(Animal):
        def run(self):
            print('Dog is running...')
    class Cat(Animal):
        def run(self):
            print('Cat is running...')
    # 当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。
    # 这样,我们就获得了继承的另一个好处:多态。
    #要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
    a = list() # a是list类型
    b = Animal() # b是Animal类型
    c = Dog() # c是Dog类型
    # 判断一个变量是否是某个类型可以用isinstance()判断:
    print(isinstance(a,list))
    print(isinstance(b,Animal))
    print(isinstance(c,Dog))
    print(isinstance(c,Animal))
    # 看来a、b、c确实对应着list、Animal、Dog这3种类型。
    # 看来c不仅仅是Dog,c还是Animal!
    # 不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!
    # 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
    # 要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个  Animal类型  的变量:
    def run_twice(animal):
        animal.run()
        animal.run()
    # 当我们传入Animal的实例时,run_twice()就打印出:
    run_twice(Animal())
    # 当我们传入Dog的实例时,run_twice()就打印出:
    run_twice(Dog())
    # 看上去没啥意思,但是仔细想想,现在,如果我们再定义一个Tortoise类型,也从Animal派生:
    class Tortoise(Animal):
        def run(self):
            print('Torteise is running slowly')
    run_twice(Tortoise())
    # 你会发现,新增一个Animal的子类,不必对run_twice()做任何修改,实际上,任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
    # 多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作
    # 即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
    # 对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,
    # 这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
    # 对扩展开放:允许新增Animal子类;
    # 对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
    # 继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树
    
    
    # 静态语言 vs 动态语言
    # 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
    # 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:
    class Timer(object):
        def run(self):
            print('start...')
    # 这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
    

dvd管理系统

class dvd:

    def __init__(self,name,price,state):
        self.name=name;
        self.price=price
        self.state=state

    def __str__(self):
        stat='已借出';
        if self.state==1:
            stat='未借出'
        return  '名称:《%s》 单价:%d 状态:%s'%(self.name,self.price,stat)

class DVDManager:
    #存储 多个dvds 每一个元素 都是一个DVD
    dvds=[]
    def init(self):
        self.dvds.append(dvd('光辉岁月',10,0));
        self.dvds.append(dvd('绅士', 5, 1));
        self.dvds.append(dvd('海阔天空', 11, 1));

    def Menu(self):
        self.init()
        while(True):
            print('1.查询所有DVD')
            print('2.增加DVD')
            print('3.借出DVD')
            print('4.归还DVD')
            print('5.退出')
            choose=int(input('请选择:'));
            if choose==1:
                self.showAllDVD();
            elif choose==2:
                self.insertDVD();
            elif choose==3:
                self.jiechuDVD();
            elif choose==4:
                self.rollBackDVD();
            elif choose==5:
                print('5.谢谢使用')
                break;

    def showAllDVD(self):
        for d in self.dvds:
            print(str(d))
    def jiechuDVD(self):
        name = input('请输入DVD的名称:')
        ret = self.checkDVD(name);
        if ret != None:
            if ret.state==0:
                print('dvd 已经借出去了')
                #return;
            else:
                days=int(input('请输入借出天数:'))
                ret.state = 0;
                print('借出 %d 天,应还利息%d '%(days,ret.price*days))

        else:
            print('DVD 不存在!')

    def rollBackDVD(self):
        name = input('请输入归还DVD的名称:')
        ret = self.checkDVD(name);
        if ret == None:
            print('DVD 不存在!')
        else:
            if ret.state == 1:
                print('dvd 未借出!')
            else:
                days= int(input('请输入借出去了多少天?'))
                y_money=ret.price * days
                print('借出 %d 天,应还利息%d ' % (days, y_money))
                money= int(input())
                #带学生完成..
                if money<y_money:
                    print('不够!')
                    return;
                elif money>y_money:
                    print('找零:%d'%(money-y_money));

                ret.state=1;
                print('归还成功!')

    def insertDVD(self):
        name = input('请输入DVD的名称:')
        ret= self.checkDVD(name);
        if ret != None:
            print('DVD 已经存在!')
        else:
            price=int(input('请输入价格:'))
            new_dvd=dvd(name,price,1);
            self.dvds.append(new_dvd)
            print('存放成功!')
    def checkDVD(self,name):
         for d in self.dvds:
             if d.name==name:
                 return d;#返回当前对象-->内存地址
         else:
             return  None;

manager= DVDManager();
manager.Menu();













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值