学习笔记

Python 类

print(1)
'''
类和对象都是面向对象中的重要概念。面向对象是一种编程思想,即按照真实世界的思维方式构建软件系统。
例如,在真实世界中的学校里,有老师和学生,学生有学号、姓名、班级等属性(数据),还有学习、提问、吃饭、走路等动作(方法)。
如果我们要开发一个校园管理系统,那么在构建软件系统时,也会有学生和老师等“类”。
张同学、李同学是学生类的个体,被称为“对象“,对象也被称为”实例“。

#定义类:
class 类名[(父类)]:
    类体
    pass

pass语句的作用是维持程序结构的完整,若不想马上编写某代码,又不想有语法错误,可以使用pass语句占位
'''



'''
类的成员包括:成员变量、构造方法、成员方法、属性(property)

成员变量包含:实例变量、类变量
成员方法包含:实例方法、类方法

成员变量也被称为数据成员,保存了类或对象的数据,比如学生的姓名和学号
构造方法是一种特殊的函数,用于初始化类的成员变量
成员方法是在类中定义的函数
属性是对类进行封装而提供的特殊方法

实例变量和实例方法属于对象,通过对象调用
而类变量和类方法属于类,通过类调用


实例变量就是个体特有的数据,如狗狗的名称和年龄等



'''

print('-------------构造方法----------------------')
#__init__() 方法是构造方法,构造方法用来初始化实例变量
#注意init前后各两个下划线,一共是4个下划线_ _init_ _,,写起来是__init__
class Dog:
    def __init__(self,name,age,sex='雌性'):
        self.name=name  #创建和初始化实例变量name
        self.age=age    #创建和初始化实例变量age
        self.sex=sex


d=Dog('狗',3)    #创建对象
print('{0}{0}{1}岁了,它的性别是{2}'.format(d.name,d.age,d.sex))
#创建对象时只写了两个参数,但sex参数已经在类中定义了,所以也能有输出



'''
类中的__init__()方法是一个非常特殊的方法,用来创建和初始化实例变量,这个方法就是“构造方法”。
在定义__init__()方法时,它的第一个参数应该是self,之后的参数用来初始化实例变量。
调用构造方法时不需要传入self参数
'''



print('-------------实例方法----------------------')
'''实例方法与实例变量一样,都是某个实例(或对象)个体特有的方法
定义实例方法时,它的第一个参数也应该是self,这会将当前实例与该方法绑定起来,这也说明该方法属于实例。
在调用方法时不需要传入self,类似于构造方法'''


class Cat:
    #构造方法
    def __init__(self,name,sex):
        self.name=name
        self.sex=sex    #创建和初始化实例变量

    #实例方法
    def run(self):
        print('{}在跑'.format(self.name))

    #实例方法
    def speak(self,sound):
        print('{}在叫,"{}"!'.format(self.name,sound))

猫=Cat('猫','公')  #创建对象调用构造方法,省略默认值
猫.run() #调用时采用【对象.实例方法()】形式,没有传递参数
猫.speak('喵喵喵')




print('-------------类变量----------------------')
'''
类变量属于类的变量,不属于单个对象。
例如,有个Account(银行账户)类,它有3个成员变量:amount(账户金额)、interest_rate(利率)、owner(账户名)。
amount和owner对于每个账户都是不同的,而interest_rate对于所有账户都是相同的。
前者是实例变量,后者是所有账户实例共享的变量,它属于类,被叫做“类变量”
'''

class Account:
    interest_rate=0.03  #这是一个类变量(设置利率)

    def __init__(self,owner,amount):
        self.owner=owner    #创建并初始化实例变量
        self.amount=amount  #创建并初始化实例变量


账户= Account('李灵杰',1000000000)   #创建对象调用构造方法

print('账户名:{}'.format(账户.owner))
print('账户金额:{}'.format(账户.amount))
print('账户利率:{}'.format(Account.interest_rate))



print('-------------类方法----------------------')
'''类方法与类变量类似,属于类,不属于实例个体。
在定义类方法时,它的第一个参数不是self,而是类本身'''

class 账户类:
    interest_rate=0.03  #类变量

    def __init__(self,owner,amount):
        self.owner=owner    #定义实例变量
        self.amount=amount  #定义实例变量

    #类方法
    @classmethod    #定义类方法需要的装饰器,装饰器以@为开头修饰函数、方法和类,用来约束他们
    def interest_by(cls,amt):   #cls代表自身,即前面定义的”账户类“
        return cls.interest_rate*amt

interest=账户类.interest_by(1000000000)
#print('计算利息:{0:.4f}'.format(interest))     #返回计算利息:30000000.0000
print('计算利息:{}'.format(interest))   #返回计算利息:30000000.0

'''注意,类变量可以访问类变量和其他类方法,但不能访问其他实例方法和实例变量。
在以上实例中,cls.interest_rate用于 访问“账户类”变量interest_rate。
如果在类方法interest_by中添加访问实例变量的owner语句  ,则会发生错误

#类方法
@classmethod
def interest_by(cls,amt):
    print(self.owner)
    return cls.interest_rate*amt

'''





print('-------------封装性----------------------')

'''
封装性是面向对象重要的基本特性之一。封装隐藏了对象的内部细节,只保留有限的对外接口,外部调用者不用关心对象的内部细节,使得操作对象变得简单。

例如,一台计算机内部极其复杂,有主板、处理器、硬盘、内存等,而一般人不需要了解它的内部细节。计算机厂商用机箱把计算机内部封装起来,对外提供了一些接口,如鼠标、键盘和显示器等 ,使用计算机就变得非常简单。
'''


print('-------------私有变量----------------------')
'''
为了防止外部调用者随意存取类的内部数据 (成员变量),内部数据(成员变量)会被封装为“私有变量”,外部调用者只能通过方法调用私有变量。
在默认情况下,Python中的变量是公有的,可以在类的外部访问它们。如果想让它们成为私有变量,则在变量前加上双下划线(__)即可。


'''


class Account2:
    __interest_rate=0.06    #加上了双下划线__后变成了私有类变量     利率

    def __init__(self,owner,amount):
        self.owner=owner    #创建并初始化公有实例变量owner
        self.__amount=amount    #创建并初始化私有实例变量__amount

    def desc(self): #在类的内部可以访问私有变量
        print('{0}金额:{1}利率{2}。'.format(self.owner,self.__amount,Account2.__interest_rate))

account=Account2('Tony',9000000)
account.desc()

print('账户名'+account.owner)
#print('账户金额'+account.__amount)  #因为私有变量无法被读取,因此这条会报错
#print('利率'+Account.__interest_rate) #类的外部无法访问私有变量,因此会报错


print('-------------私有方法----------------------')
'''
私有方法与私有变量的分装是类似的,在方法前面加上双下划线【__】就是私有方法了
'''
class Account3:
    __interest_rate=0.06    #类变量利率

    def __init__(self,owner,amount):
        self.owner=owner
        self.__amount=amount

    def __get_info(self):
        return '{0}金额:{1} 利率:{2}'.format(self.owner,self.__amount,Account3.__interest_rate)

    def desc(self):
        print(self.__get_info())

account=Account3('Tony',10000000)
account.desc()
#account.__get_info()   #会报错


print('-----------------使用属性----------------------')
'''为了实现对象的封装,在一个类中不应该有公有的成员变量,这些成员变量应该被设计为私有的,然后通过公有的set(赋值)和get(取值)方法访问'''

class Dog2:
    #构造方法
    def __init__(self,name,age,sex='雌性'):
        self.name=name  #创建和初始化实例变量name
        self.__age=age    #创建和初始化私有实例变量__age

    #实例方法
    def run(self):
        print(self.name,'在跑')

    #get方法
    def get_age(self):  #定义get方法,返回私有实例变量__age
        return self.__age

    #set方法
    def set_age(self,age):  #定义set方法,通过age参数与更新私有实例变量__age
        self.__age=age

dog=Dog2('汪汪',2)
print('狗狗年龄',dog.get_age())

dog.set_age(3)
print('修改后的狗狗年龄:',dog.get_age)



'''在上面的示例中,当外部调用者通过两个公有方法访问被封装的 私有成员变量时,会比较麻烦
我们可以在类中定义属性,属性可以替代get()和set()这两个公有方法,在调用时比较简单'''

class Dog3:
    #构造方法
    def __init__(self,name,age,sex='雌性'):
        self.name=name  #创建和初始化实例变量
        self.__age=age  #创建和出事啊私有实例变量__age
        #私有变量__age,对应的属性名应该去除前面双下划线之后的名称,即age

    #实例方法
    def run(self):
        print(self.name,'在跑')

    @property   #定义age属性的get()方法,使用@property装饰器进行修饰,方法名就是属性名,即age
    def age(self):  #替代get__age(self):
        return self.__age

    @age.setter
    def age(self,age):  #替代set_age(self,age)
        self.__age=age

dog=Dog('汪汪汪',2)
print(dog.name,'的年龄是',dog.age)  #可以通过属性取值,访问形式为【实例.属性】
dog.age=3   #dog.set_age(3) #可以通过属性赋值,访问形式为【实例.属性】
print('修改后的',dog.name,'年龄是',dog.age)    #可以通过属性取值,访问形式为【实例.属性】

'''属性在本质上就是两个方法,在方法前加上装饰器使方法成为属性。
属性使用起来类似于公有变量,可以在赋值符【=】左边或右边,左边被赋值,右边取值'''



print('------------继承性---------------')
'''继承性也是面向对象重要的基本特性之一。
在显现实世界中继承关系无处不在,例如猫与动物之间的关系,猫是一种特殊与的动物,具有动物的全部特征和行为,即数据和操作。
在面向对象中,动物一般是类,被称为“子类”。特殊类拥有一般类的全部数据和操作,可称为子类继承父类
'''

print('------------Python中的继承-----------------')
'''Python中声明子类继承父类,语法很简单,定义类时,在类的后面使用一对小括号指定它的父类就可以了'''

class Animal:   #定义父类动物(Animal)
    def __init__(self,name):
        self.name=name  #初始化父类的实例成员变量

    def show_info(self):
        return "动物的名字:{0}".format(self.name)

    def move(self):
        print('动一动...')

class Cat(Animal):
    def __init__(self,name,age):
        super().__init__(name)  #调用父类构造方法,初始化父类成员变量
        self.age=age    #实例变量age    #初始化子类的实例成员变量

cat=Cat('喵喵',2) #在创建cat对象时,调用Cat类构造方法
cat.move()
print(cat.show_info())

#子类继承父类时,只有公有的成员变量和方法才能被继承

#构造方法的作用是初始化类的实例成员变量,在初始化子类时,也初始化父类的实例成员变量


print('-------------------多继承--------------------------')

'''从面向对象的继承性理论上讲,一个子类可以有多个父类。
但是,在多个父类中有相同的方法,那么子类应该继承哪一个父类方法?这样会发生冲突。
所以很多计算机语言都不支持多继承,但Python支持!'''

'''在Python中,当子类继承多个父类时,如果在多个父类中有相同的成员方法或成员变量,
则子类优先继承左边父类中的成员方法或成员变量,从左到右继承级别从高到低'''


class Horse:
    def __init__(self,name):
        self.name=name  #实例变量name

    def show_info(self):
        return '马的名字:{0}'.format(self.name)

    def run(self):
        print('马跑')


class Donkey:
    def __init__(self,name):
        self.name=name  #实例变量name

    def show_info(self):
        return "驴的名字{0}".format(self.name)

    def run(self):
        print('驴跑')

    def roll(self):
        print('驴打滚')


class Mule(Horse,Donkey):
    def __init__(self,name,age):
        super().__init__(name)
        self.age=age    #实例变量age

m=Mule('罗暴利',1)
m.run() #继承父类Horse方法
m.roll()#继承父类Donkey方法
print(m.show_info())#继承父类Horse方法



print('-----------方法重写-----------------')
'''如果子类的方法名与父类的方法名相同,则在这种情况下,子类的方法会重写(Override)父类的同名方法'''

class Horse2:
    def __init__(self,name):
        self.name=name#实例变量name

    def show_info(self):
        return '马的名字:{0}'.format(self.name)

    def run(self):
        print('马跑')

class Donkey2:
    def __init__(self,name):
        self.name=name  #实例变量

    def show_info(self):
        return '驴的名字{0}'.format(self.name)

    def run(self):
        print('驴跑')

    def roll(self):
        print('驴打滚')

class Mule2(Horse2,Donkey2):
    def __init__(self,name,age):
        super().__init__(name)
        self.age=age#实例变量age
    def show_info(self):    #重写父类方法show_info
        return "骡:{0},{1}岁".format(self.name,self.age)

m2=Mule2('二驴',3)
m2.run()    #继承父类Monkey2方法
m2.roll()   #继承父类Donkey2方法
print(m2.show_info())   #子类Mule2自己的方法


print('-----------------多态性---------------------')
'''多态性也是面向对象重要的基本特性之一,堕胎是指对象可以表现出多种形态。
例如,猫、狗、鸭子都属于动物,它们有叫和动等行为,但叫的方式不同,动的方式也不同'''

#继承与多态

'''在多个子类继承父类,并重写父类方法后,这些子类所创建的对象之间就是多态的。这些对象采用不同的 方式实现父类方法。'''

class Animal2:
    def speak(self):
        print('动物叫,但不知道是哪种动物叫')

class Dog(Animal2):
    def speak(self):
        print('汪汪汪')

class Cat(Animal2):
    def speak(self):
        print('喵喵喵')



animal1=Dog()
animal2=Cat()

animal1.speak()
animal2.speak()


#鸭子类型测试与多态
'''Python的多态性更加灵活,支持鸭子类型测试。
鸭子类型测试指:一只鸟走起来像鸭子、游起来像鸭子、叫起来也像鸭子,那么这只鸟可以被称为鸭子'''

'''由于支持鸭子类型测试,所以Python解释器不检查发生多态的对象是否继承了同一个父类,只要它们有相同的行为(方法),它们之间就是多态的'''


#例如,我们设计一个函数start(),它接收具有叫speak()方法的对象
def start(obj): #接收的obj对象具有speak()方法
    obj.speak()


class Animal3:
    def speak(self):
        print('动物叫')

class Dog2(Animal3):
    def speak(self):
        print('汪汪汪')

class Cat2(Animal3):
    def speak(self):
        print('喵喵喵')

#start函数可以接收所有方法对象
start(Dog2())
start(Cat2())

发表回复