python3.6-类和对象-类方法20180513

传参的方式可以写在初始化函数形参中,也可以self. xx,以定义人类为例,初始化函数中涵盖name,age:

通常习惯会将形参name,age放进__init__中,格式如下:

class Person:    #定义了一个名字叫Person的类
    def __init__(self,name,age):    #下面需要的有2个参数,name和age,放进__init__中备用
        self.name = name            #self将会传入下面创建的实例luna所需的name值和age值
        self.age = age
    def show(self):
        print('姓名:'+ self.name +'年龄:',self.age)   #show函数的动作

if '__main__'==__name__:
    luna = Person('Luna',20)        #创建实例并传参
    luna.show()

上面的例子中,初始化函数中是灵活的,可以通过luna的传参来更改打印的结果

下面的例子中,是在初始化时,就将值赋好,作为默认值

class Person:
    def __init__(self):
        self.name = 'Jack'
        self.age = 50
    def show(self):
        print('姓名:'+ self.name +'年龄:',self.age)

if '__main__'==__name__:
    luna = Person()
    luna.show()                  #打印结果为   姓名:Jack年龄: 50   luna并没有给值,所以为默认值jack 50
class Person:
    def __init__(self):
        self.name = 'Jack'
        self.age = 50
    def show(self):
        print('姓名:'+ self.name +'年龄:',self.age)

if '__main__'==__name__:
    luna = Person()
    luna.name = 'Luna'
    luna.age = 20
    luna.show()             #打印结果为  姓名:Luna年龄: 20    luna.name和luna.age重新赋值,会打印出新赋的值

此外,语法也允许在外面赋值,但只能自身调用:

class Person:
    def __init__(self):
        self.name = 'Jack'
        self.age = 50
    def show(self):
        print('姓名:'+ self.name +'年龄:',self.age)

if '__main__'==__name__:
    luna = Person()
    luna.name = 'Luna'
    luna.age = 20
    luna.gender = 'female'   #单独给luna一个gender属性并赋值female          
    luna.show()
    print('luna.gender;',luna.gender)   #打印时正常,自己内部的赋值可以自身调用

    candy = Person()
    candy.name = 'candy'
    candy.age = 30
    candy.show()
    print('candy gender:',candy.gender)    #这样会报错!!!!  不是自己的,也不是类的,不可以调用!

类属性: 属于类的成员,对象共有的

class Person:
    x = '123'
    def __init__(self,name,age):
        pass
    @classmethod
    def Clsmth(cls):
        print('aaa')

lili = Person('lili',20)
lili.__class__.Clsmth()     #打印结果aaa
Person.Clsmth()             #打印结果aaa

lili.__class__的类就是Person,__class__属性与对象属性的区别是:当需要全局的调用时,就用__class__,(例如:lili.__class__.phone)如果只需要自己赋值自己调用的时候,就用对象属性(例如:lili.phone)

类方法:   @classmethod

def class_method(cls):

可以通过类方法调用类属性,也可以通过对象调用类属性

类方法更倾向于工具方法,不需要重复创建对象,不是以对象的形式去调用

静态方法:  @staticmethod 

不关乎类,也不关乎对象,而是服务于程序

一般情况下,静态方法会单独放在一个模块中

对象不需要new,不是已经存在的对象

class Person:
    def __init__(self):
        pass
    @staticmethod
    def SayHi():        #无参也可以
        print('hi...')

Person.SayHi()     #打印结果hi...
class Person:
    def __init__(self):
        self.CallName = 'coco'
    @staticmethod
    def SayHi(name):   #有参也可以
        print(name+'你好!')

luna = Person()
Person.SayHi('luna')     #打印结果 luna你好!

继承:

子类继承父类,子类可以使用父类的属性和方法,简化代码,当生成子类对象时,先初始化父类对象

所以如果父类有__init__()方法,并且有属性时,要通过子类的构造赋值,一个类可以有多个子类

super().__init__(属性)

或self.属性
或父类.__init__(self,参数)==>父类.__init__(self)-->调用无参
super(子类,self).__init__(参数) 
用子类的父类的 __init__

class Pet:
    def __init__(self):
        self.name = ''
        self.love = 0
        self.health = 100
    def show(self):
        print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health))

class Dog(Pet):
    def __init__(self):
        super().__init__()        #子类常使用super().__init__()调用父类的初始化方法
        self.strain = '拉布拉多'
    def eat(self):
        print('品种;'+ self.strain + '正在吃饭...')

#代表程序主入口是从这里进入的
if __name__ == '__main__':
    dog = Dog()
    dog.eat()
    dog.show()               #子类dog调用父类的show方法,需要有super().__init__()
class Pet:
    def __init__(self):
        self.name = ''
        self.love = 0
        self.health = 100
    def show(self):
        print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health))

class Dog(Pet):
    def __init__(self):
        super(Dog, self).__init__()     #方法二:super(子类,self).__init__(参数) 子类调用父类的初始化方法
        self.strain = '拉布拉多'
    def eat(self):
        print('品种;'+ self.strain + '正在吃饭...')

#代表程序主入口是从这里进入的
if __name__ == '__main__':
    dog = Dog()
    dog.eat()
    dog.show()
class Pet:
    def __init__(self,name,love,health):     #形参 3-1
        self.name = name
        self.love = love
        self.health = health
    def show(self):
        print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health))

class Dog(Pet):
    def __init__(self,name,love,health):     #形参 3-2
        super().__init__(name,love,health)   #形参 3-3,不需要加self
        self.strain = '拉布拉多'
    def eat(self):
        print('品种;'+ self.strain + '正在吃饭...')

#代表程序主入口是从这里进入的
if __name__ == '__main__':
    dog = Dog('可乐',33,99)                 #传参
    dog.eat()
    dog.show()

可以迭代:(下↓)

打印结果:

品种;拉布拉多正在吃饭...

name:可乐亲密度:43健康值:99

class Pet:
    def __init__(self,name,love,health):
        self.name = name
        self.love = love
        self.health = health
    def show(self):
        print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health))

class Dog(Pet):
    def __init__(self,name,love,health):
        super().__init__(name,love,health)
        self.strain = '拉布拉多'
    def eat(self):
        print('品种;'+ self.strain + '正在吃饭...')

#代表程序主入口是从这里进入的
if __name__ == '__main__':
    dog = Dog('可乐',33,99)
    dog.eat()
    dog.love +=10     #执行eat后,love值增加10
    dog.show()

当需要打印父类的方法show(),同时也需要子类的方法strain(),   在子类中重新建立一个showInfo()方法,调用父类的show()

class Pet:
    def __init__(self,name,love,health):
        self.name = name
        self.love = love
        self.health = health
    def show(self):
        print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health))

class Dog(Pet):
    def __init__(self,name,love,health):
        super().__init__(name,love,health)
        self.strain = '拉布拉多'
    def eat(self):
        print('品种;'+ self.strain + '正在吃饭...')
    def showInfo(self):
        super().show()
        print('品种:',self.strain)

#代表程序主入口是从这里进入的
if __name__ == '__main__':
    dog = Dog('可乐',33,99)
    dog.eat()
    dog.showInfo()

总结:

当子类继承父类时,子类的构造方法应该包含父类和子类共同的属性,在子类的初始化__init__()方法中,将父类的属性传递给父类,子类的属性赋值给子类

方法重写:子类继承父类时,子类的方法签名和父类一样,此时子类重写了父类的方法,当生成子类对象时,调用的是子类重写的方法

小练习:

交通工具类:属性:名称 方法:行驶
子类:卡车,属性:载重,重写行驶的方法
子类:火车,属性:车箱个数,重写行驶的方法

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

    def run(self):
        print('交通工具名称:'+ self.name + '正在行驶...' )

class Truck(traffic):
    def __init__(self,name,weight):
        super().__init__(name)
        self.weight = weight
    def run(self):
        print('卡车' + self.name + '载重' + str(self.weight)+ '在行驶')

class Train(traffic):
    def __init__(self,name,num):
        super().__init__(name)
        self.num = num
    def run(self):
        print('卡车' + self.name + '个数' + str(self.num)+ '在行驶')

if __name__ == '__main__':
    dongfeng = Truck('东风',50)
    dongfeng.run()

    hexie = Train('和谐001',100)
    hexie.run()
卡车东风载重50在行驶
卡车和谐001载重100在行驶


三代继承:

子类初始化方法需要祖父、父类及自己的属性,可以调用父类的初始化方法传参,可以重写父类的方法

构造的顺序依然先构造祖父类,再构造父类,最后构造自己
类根源顶级父类-->继承object
方法重写:
如果子类重写的方法想调用父类的方法时,在子类方法中:
父类.方法(self)或super().父类方法()
私有属性、私有方法:均不能在类外面被调用
多继承:类同时继承多个父类,class C(A,B),
当有AB均有相同方法,而子类又重写时,调用谁的方法,(子类)
如果子类重写没有方法,则调用哪个父类的方法?(左侧,优先继承的类)


类名.mro(),可以看到所有父类,即搜索顺序
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子


小练习:

----DVD管理系统----:
1.查询所有DVD
2.增加DVD
3.借出DVD
4.归还DVD
5.退出

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

if __name__ == '__main__':
    Lily = DVD('Lily',10,0)
    Candy = DVD('Candy',20,1)
    Jack = DVD('Jack',30,0)
    dvds = {Lily.name:Lily,Candy.name:Candy,Jack.name:Jack}
    while True:
        print('-----------------')
        num = int(input('请输入执行编号:'))
        if num ==5:
            print('谢谢使用!')
            break
        if num == 1:
            print('名字\t价格\t状态')
            for key in dvds.keys():
                if dvds.get(key).state ==0:
                    print(key + '\t' + str(dvds.get(key).price) + '\t借出')
                else:
                    print(key + '\t' + str(dvds.get(key).price) + '\t未借出')

        if num == 2:
            name = input('请输入DVD的名字:')
            while name in dvds.keys():
                name = input('名字已存在,请重新输入DVD的名字:')
            price = input('请输入价格:')
            new_dvd = DVD(name,price,1)
            dvds[name] = new_dvd
            print('添加成功!')

        if num == 3:  #借出DVD
            name = input('请输入DVD名字:')
            while name not in dvds.keys():
                name = input('DVD不存在,请重新输入DVD的名字:')
            if dvds.get(name).state == 0:
                print(name + '已借出')
            else:
                dvds.get(name).state = 0
                print(name + '借出成功!')

        if num == 4:
            name = input('请输入要归还的DVD名字:')
            while name not in dvds.keys():
                name = input('DVD不存在,请重新输入;')
            if dvds.get(name).state == 1:
                print('DVD 未借出')
            else:
                days = int(input('请输入借出天数:'))
                print('请刷卡:',int(dvds.get(name).price)*days,'元')
                dvds.get(name).state = 0
                print('归还成功!')


单例模式:

该模式的主要目的是确保某一个类只有一个实例存在,避免内存浪费。

(程序如果并发量大的话,内存里就会存在非常多功能上一模一样的对象。存在这些对象肯定会消耗内存,对于这些功能相同的对象可以在内存中仅创建一个,需要时都去调用)


工厂类:

在一个类中生成很多对象,   简单工厂模式(Simple Factory Pattern)
是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类 并且重写父类方法。

#四则运算的父类,接收用户输入的数值 Operation
OperationAdd OperationSub OperationMul   OperationDiv  OperationFactory(object)

class Operation:
    def __init__(self,numA,numB):
        self.numA = numA
        self.numB = numB
    def yunsuan(self):
        pass

class OperationAdd(Operation):
    def __init__(self,numA,numB):
        super().__init__(numA,numB)
    def yunsuan(self):
        return self.numA + self.numB

class OperationSub(Operation):
    def __init__(self, numA, numB):
        super().__init__(numA, numB)
    def yunsuan(self):
        return self.numA - self.numB

class OperationMul(Operation):
    def __init__(self, numA, numB):
        super().__init__(numA, numB)
    def yunsuan(self):
        return self.numA * self.numB

class OperationDiv(Operation):
    def __init__(self, numA, numB):
        super().__init__(numA, numB)
    def yunsuan(self):
        return self.numA // self.numB


#工厂类
class OperationFactory(object):
    @classmethod
    def getOperation(cls,fu,numA,numB):
        if '+'.__eq__(fu):
            return OperationAdd(numA,numB)
        elif '-'.__eq__(fu):
            return OperationSub(numA,numB)
        elif '*'.__eq__(fu):
            return OperationMul(numA,numB)
        elif '/'.__eq__(fu):
            return OperationDiv(numA,numB)

if '__main__'==__name__:

    numA = int(input('请输入第一个操作数:'))
    numB = int(input('请输入第二个操作数:'))
    fu = input('请输入操作符:')

    #返回与操作符对应的 运算对象
    Opera = OperationFactory.getOperation(fu,numA,numB)
    jg = Opera.yunsuan()
    print('运算结果;',jg)



isinstance()函数 判断是否 继承关系 某一个变量是否是某一个数据类型(例子接上面)
getattr(类名/对象名)、setattr(类名/对象名)以及hasattr(类名/对象名,'属性名'),
类名/对象名有 __getattribute__ __setattr__   没有__hasattr__()

if isinstance(Oper,OpreationAdd)
    print('创建的为加法类型')
Oper = OperationFactory.getOpreation('+',6,9)
print(Oper.__getattribute__('numA'))   #打印6
如果不能获取__getattribute__,可以通过setattr增加属性和值

Oper.__setattr__('numC',7)
print(Oper.__getattribute__('numC'))
可以通过print(dir(Opre)),打印出所有可以用的内置函数

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'n1', 'n2', 'suan']


可以直接操作一个对象的 形态-
给类动态添加函数,只能在类级别添加,所有对象都能用,给某一个对象添加
def set_score(self, score):
      self.score = score
Student.set_score = set_score


动态语言的灵活性:
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,
来限制该class实例能添加的属性 
class 类名:
_slots__ = ('name', 'age') #第一句



@property 注解优化getter setter--> @函数名.setter

__call__ 直接在实例本身上调用  s = Student('Michael') s()
通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。


总结:

不同的类对同一个信息/动作,做出不同的解释,执行不一样的代码:

3个必要条件:

1. 发生继承关系

2.子类重写父类

3.里氏代换原则

使用方式:

以父类类型为形参

好处:节省代码,更符合现实逻辑


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值