python王者归来—学习笔记(14)

第十二章 类-面向对象程序设计(类定义与初始化、类的私有属性和方法、类的继承)

在Python中其实所有的数据类型皆是对象,Python也允许程序设计师自创数据类型,这种自创的数据类型就是本章的主题类(class)。

一、类的语法定义如下:

class Classname():  #类名称第一个字母必须大写
    statement1
    ...
    statement2

在类中可以定义属性和方法。类内定义方法(method)的方式与定义函数的方式相同,但是不可以称之为函数(function),必须称之为方法(method),在程序设计时我们可以随时调用函数,但是只有属于该类的对象(object)才可调用相关的方法。若是想操作类的属性与方法首先需定义该类的对象(object)变量,可以简称对象,然后使用下列方式操作:object.类的属性、object.类的方法():

#类定义
class Banks():
    #定义银行类别
    title = "China Bank"  #定义属性
    def motto(self):      #定义方法
        return "财富人生"

userbank = Banks()         #定义类对象
print(userbank.title)
print(userbank.motto())

建立类很重要的一个工作是初始化整个类,所谓的初始化类是在类内建立一个初始化方法(method),这是一个特殊方法,当在程序内定义这个类的对象时将自动执行这个方法。初始化方法有一个固定名称是“__init__( )”,写法是init左右皆是2个底线字符,init其实是initialization的缩写,通常又将这类初始化的方法称构造函数(constructor)。在这初始化的方法内可以执行一些属性变量设定。

class Banks():
    #定义银行类
    title = "China Bank"  #定义属性
    def __init__(self, uname, money): #初始化方法
        self.name = uname       #设定存款者名称
        self.balance =  money   #设定所存金额

    def save_money(self, money):  #设计存款方法
        self.balance += money
        print("存款 ", money, " 完成")

    def withdraw_money(self, money): #设计取款方法
        self.balance -=money
        print("取款 ", money, " 完成")
        
    def get_balance(self):      #获得当前存款余额方法
        print(self.name, "目前余额是: ", self.balance)

userbank = Banks('huang', 100)  #定义类对象
userbank.get_balance()    #打印存款余额
userbank.save_money(300)  #存款300
userbank.get_balance()
userbank.withdraw_money(200)  #取款200
userbank.get_balance()
clientbank = Banks('lin', 200) #定义另一个类对象
clientbank.get_balance()

上述程序中定义Banks类的userbank对象和clientbank对象时,Banks类会自动启动__init__()初始化函数,在这个定义中self是必需的,同时需放在所有参数的最前面(相当于最左边),Python在初始化时会自动传入这个参数self,代表的是类本身的对象,未来在类内想要参照各属性与函数执行运算皆要使用self。在程序中还有一个get_balance(self)方法,在这个方法内只有一个参数self,所以调用时可以不用任何参数。

在先前程序的Banks类中title是设为“China Bank”,其实这是初始值的设定,通常Python在设初始值时是将初始值设在__init__( )方法内:

class Banks():
    #定义银行类
    title = "China Bank"  #定义属性
    def __init__(self, uname, money): #初始化方法
        self.name = uname       #设定存款者名称
        self.balance =  money   #设定所存金额
        self.title = "China Bank"  #设定属性初始默认值

二、类的封装。类内的属性可以让外部引用的称公有(public)属性,而可以让外部引用的方法称公有方法。其实前面所使用的Banks类内的属性与方法皆是公有属性与方法。但是程序设计时可以发现,外部直接引用时也代表可以直接修改类内的属性值,这将造成类数据不安全。因此Python也提供一个私有属性与方法的观念,这个观念的主要精神是类外无法直接更改类内的私有属性,类外也无法直接调用私有方法,这个观念又称封装(encapsulation)。Python对于类内的属性增加了私有属性(private attribute)的概念,应用方式是定义时在属性名称前面增加__(2个底线),定义为私有属性后,类外的程序就无法引用了。类的私有方法(private method)与私有属性类似,只要在方法前面加上__(2个底线)符号即可,类外的程序就无法调用。

class Banks():
    #定义银行类
    
    def __init__(self, uname):       #初始化方法
        self.__name = uname          #设定私有属性客户名称
        self.__balance =  0          #设定私有属性存款余额
        self.__title = "China Bank"  #设定私有属性银行名称
        self.__rate = 6.5            #设定私有属性汇率
        self.__charge = 0.01         #设定私有属性换汇服务费

    def save_money(self, money):       #设计存款方法
        self.__balance += money
        print("存款 ", money, " 完成")

    def withdraw_money(self, money):   #设计取款方法
        self.__balance -=money
        print("取款 ", money, " 完成")
        
    def get_balance(self):             #获得当前存款余额方法
        print(self.__name, "目前余额是: ", self.__balance)

    def usa_to_rmb(self, usa_dollar):   #美元兑人民币方法
        self.result = self.__cal_rate(usa_dollar)  #调用私有方法
        return self.result

    def __cal_rate(self, usa_dollar):   #定义换汇私有方法
        return int(usa_dollar * self.__rate * (1 - self.__charge))
    

userbank = Banks('huang')  #定义类对象
userbank.get_balance()     #打印存款余额
userbank.balance = 1000    #尝试在类外直接修改私有属性,实际无效
userbank.get_balance()

usa_dollar = 50
print(usa_dollar, " 美元可以兑换 ", userbank.usa_to_rmb(usa_dollar), " 人民币")

三、类的继承。在面向对象程序设计中类是可以继承的,其中被继承的类称父类(parent class)或基类(base class),继承的类称子类(childclass)或衍生类(derived class)。类继承的最大优点是许多父类的公有方法或属性,在子类中不用重新设计,可以直接引用。在程序设计时,基类(base class)必须在衍生类(derived class)前面,衍生类继承了基类的公有属性与方法,同时也可以有自己的属性与方法。整个程序代码结构如下:

class BaseClassName():  #先定义基类
    baseclass statement

class DerivedClassName(BaseClassName):  #再定义子类
    derivedclass statement

基于保护原因,类外是无法直接取得类内的私有属性,即使是它的衍生类也无法直接读取,如果真要取得可以定义一个公有方法,使用return方式,传回私有属性内容。程序设计时,衍生类也可以有自己的初始化__init__( )方法,同时也有可能衍生类的属性与方法名称和基类重复,碰上这个状况Python会先找寻衍生类是否有这个名称,如果有则先使用,如果没有则使用基类的名称内容。

class Banks():
    #定义银行类
    def __init__(self, uname):       #初始化方法
        self.__name = uname          #设定私有属性客户名称
        self.__title = "China Bank"  #设定私有属性银行名称

    def bank_title(self):            #获得私有属性的公有方法
        return self.__title

class BeijingBanks(Banks):
    #定义银行子类
    def __init__(self, uname):       #子类有自己初始化方法
        self.__name = uname          ##子类定义同名属性客户名称
        self.__title = "China Bank -- Beijing"  #子类定义同名属性银行名称

    def bank_title(self):            #子类定义同名公有方法
        return self.__title    

userbank = Banks('huang')  #定义类对象
print("Banks: ", userbank.bank_title())

clientbank = BeijingBanks('lin')
print("BeijingBanks: ", clientbank.bank_title())

衍生类引用基类的方法时需使用super( ):

class Animals():
    """ 动物类 """
    def __init__(self, uname, age):     #初始化方法
        self.name = uname
        self.age = age

    def run(self):
        print(self.name, " is running")

class Dogs(Animals):                    #继承动物类
    """ 狗类 """
    def __init__(self, dog_name, dog_age):
        super().__init__("dog " + dog_name, dog_age)  #调用父类的初始化方法

    def dog_run(self):
        super().run()  #调用父类的方法
        print("it is a dog")

        
mycat = Animals('lucy', 5)
print(mycat.name, " is ", mycat.age, " years old.")
mycat.run()

mydog = Dogs('lily', 8)
print(mydog.name, " is ", mydog.age, " years old.")
mydog.run()
mydog.dog_run()

衍生类如果想引用基类的属性,要不就是在初始化方法中显示设置super.__init__(),代表将基类的属性复制到衍生类中,要不就是完全不写衍生类的初始化方法(即使写空的初始化方法def __init__() : pass 也不行),否则就无法引用到父类的属性:

class Animals():
    """ 动物类 """
    def __init__(self, uname, age):     #初始化方法
        self.name = uname
        self.age = age

    def run(self):
        print(self.name, " is running")

class Dogs(Animals):                    #继承动物类
    """ 狗类 """
    #完全不写子类的初始化方法
    #def __init__(self, dog_name, dog_age):  
    #    super().__init__("dog " + dog_name, dog_age)  #调用父类的初始化方法

    def dog_run(self):
        print(self.name, " is running") #引用父类的属性

        
mycat = Animals('lucy', 5)
print(mycat.name, " is ", mycat.age, " years old.")
mycat.run()

mydog = Dogs('lily', 8)
print(mydog.name, " is ", mydog.age, " years old.")
mydog.run()
mydog.dog_run()

下列是一个三代同堂的程序,在这个程序中有祖父(Grandfather)类,它的子类是父亲(Father)类,父亲类的子类是Son类。其实Ivan要取得父亲类的属性很容易,可是要取得祖父类的属性时就会碰上困难,解决方式是在Father类与Ivan类的__init__( )方法中增加下列设定:super.__init__()

class Grandfather():
    """ 祖父类 """
    def __init__(self):
        self.grandfathermoney = 10000    #祖父类资产
    def get_info1(self):
        print("grandfather's information")

class Father(Grandfather):
    """ 父类 """
    def __init__(self):
        self.fathermoney = 8000   #父类资产
        super().__init__()        #复制基类属性
    def get_info2(self):
        print("father's information")

class Son(Father):
    """ 子类 """
    def __init__(self):
        self.sonmoney = 500       #子类资产
        super().__init__()        #复制基类属性
    def get_info3(self):
        print("Son's information")
    def get_money(self):          #取得三代家庭资产明细
        print("\n儿子资产:", self.sonmoney,
              "\n父亲资产:", self.fathermoney,
              "\n祖父资产:", self.grandfathermoney)

son = Son()
son.get_info3()
son.get_info2()
son.get_info1()
son.get_money()

假设有一个父亲(Father)类,这个父亲类有2个儿子,分别是SonA类和SonB类,如果SonB类想取得SonA类的属性attu,可以使用下列方式:SonA().attu

class Father():
    """ 父类 """
    def __init__(self):
        self.fathermoney = 5000   #父类资产

class SonA(Father):
    """ 子类 """
    def __init__(self):
        self.sonamoney = 500       #子类资产
        super().__init__()         #复制基类属性

class SonB(Father):
    """ 子类 """
    def __init__(self):
        self.sonbmoney = 300       #子类资产
        super().__init__()         #复制基类属性
        
    def get_money(self):           
        print("\n父亲资产:", self.fathermoney,
              "\n大儿子资产:", SonA().sonamoney,  #取得兄弟类属性
              "\n小儿子资产:", self.sonbmoney)        

son = SonB()
son.get_money()

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值