美文网首页
详解抽象之类

详解抽象之类

作者: Python百事通 | 来源:发表于2021-05-21 21:48 被阅读0次

    相较于函数,类则是更高级别的抽象结构,类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。类是一种用户定义类型,也称类类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象,类的实质是一种数据类型。

    类的定义

    与其它面向对象编程语言类似,在 Python 中,类具有多态、封装、继承。不过,Python 中没有重载,类的定义细节也具有明显差异。定义类的一般形式如下:

    class ClassName:

    <statement-1>

    .

    .

    .

    <statement-N>

    上面提到,类的本质是一种数据结构,一个类通常包含数据成员和函数成员。数据成员用于刻画类所描述的一类事物的属性,如描述人,一般用姓名、年龄、性别、学历等属性进行刻画,这就是数据成员;函数成员用于完成具体的任务,如查询、设置人名、打印基本信息等。如下实例:

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义类的数据成员:姓名,年龄

    name=''

    age=0

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('person-info:{name:%s, age:%d}'%(self.name,self.age))

    #定义一个简单的函数

    defhello(self):

    print("hello world!")

    #实例化,创建一个对象

    p1 = Person()

    #访问类的属性:数据成员,访问语法obj.X

    print("name:",p1.name)

    print("age:",p1.age)

    #访问类的函数

    p1.printPersonInfo()

    p1.hello()

    执行结果:

    name: 

    age: 0

    person-info:{name:, age:0}

    helloworld!

    self 参数

    上述实例中,Person 类定义了两个函数,其定义形式与上一篇介绍的函数存在明显区别:类中的函数必须有一个额外的参数 self,并且 self 参数必须放在第一个参数的位置。

    那么,对于一个实例化的对象,self 参数代表什么呢?来看一个例子。

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义类的数据成员:姓名,年龄

    name=''

    age=0

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('name:',self.name)

    print('self:',self)

    print('self class:',self.__class__)

    #实例化,创建一个对象

    p1 = Person()

    #访问类的函数

    p1.printPersonInfo()

    执行结果:

    name:

    self:<__main__.Person object at 0x00000000067B5F98>

    selfclass:

    从执行结果可以看出,self 的内容是一个地址,它代表当前实例,也就是当前对象的地址。需要说明的是,self 参数并不是 Python 的保留关键字,而是为了便于理解,按照惯例命名而来。事实上,换做其它名字也可以(须遵循规则:必须是类函数的第一个参数)。

    实例化

    上面小节实例中,我们创建了一个 Person 类的对象:p1=Person(),通过对象可以访问类的属性和调用类的函数,语法形式为:obj.name,其中 name 代表类的属性名或函数名。

    上述例子中存在一个疑点,不知读者是否注意到,例子中实例化对象的操作并不是显式调用构造函数完成的,如下代码:

    p1= Person()

    类中并没有定义名为 Person() 的函数,Person 是类名,在进行实例化创建对象的时候,会自动调用__init()__函数。该函数用于创建对象,并赋予所创建对象初始状态。

    上述例子中,做了很多简化,创建的对象的所有属性都是默认值,在实际应用中,通常会采取更有效的方式来赋予对象初始状态。如下实例:

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义类的数据成员:姓名,年龄

    name=''

    age=0

    #定义构造函数,用于创建一个类实例,也就是类的具体对象

    #通过参数传递,可以赋予对象初始状态

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('person-info:{name:%s, age:%d}'%(self.name,self.age))

    #实例化,创建两个对象,默认调用构造函数:__init__()

    p1 = Person("Zhang San",12)

    p2 = Person("Li Si",13)

    #访问类的属性:数据成员,访问语法obj.X

    print("name:",p1.name)

    print("age:",p1.age)

    #调用函数

    p1.printPersonInfo()

    p2.printPersonInfo()

    运行结果:

    name: Zhang San

    age: 12

    person-info:{name:Zhang San, age:12}

    person-info:{name:Li Si, age:13}

    Python 中类定义与 Java、C++ 的差别

    从上面的例子中可以发现,Python 中类的定义与 Java 和 C++ 的区别:

    定义形式,Python 没有修饰符,只有关键词 class,Java 和 C++ 则有修饰符(非必须);

    构造函数,Python 没有重载特性,只能定义一个构造函数,且函数名为__init__,若不定义构造函数,则默认为__init__(self),Java、C++ 则具有重载特性,可定义多个构造函数,且构造函数名必须与类名一致;

    形参定义形式不同,Python 类的方法,self 参数为必须参数;

    不必声明域,上面的例子中,声明了域 (name,age),事实上,Python 可以不声明域,例子如下

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义构造函数,用于创建一个类实例,也就是类的具体对象

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('person-info:{name:%s, age:%d}'%(self.name,self.age))

    继承

    继承可谓一种带有褒义的懒惰行为,一个最直观的好处就是减少编写重复代码,通过继承,子类可以重用父类中的函数和数据成员。当然,继承的意义远不止于此,这里就不展开了。

    关于继承,通常将实施继承行为的类称为子类(Child Class)或者派生类(Derived Class),被继承的类称为父类(Parent Class)或者基类(Base Class)。与 Java、C++ 相比,Python 中继承的一般形式颇为简洁:

    classchildClassName(parentClassName):

    .

    .

    .

    下面结合实例来看一下,定义一个类 Occupation 和一个继承 Occupation 的类 Person,继承的定义形式为:Person(Occupation),无需关键词声明。

    #定义一个类Occupation,描述职业

    classOccupation:

    #定义构造函数

    def__init__(self,salary,industry):

    self.salary = salary

    self.industry = industry

    defprintOccupationInfo(self):

    print('Occupation-info:{salary:%d, industry:%s}'%(self.salary,self.industry)) 

    #定义一个简单的类Person,继承自类Occupation 

    classPerson(Occupation):

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('person-info:{name:%s, age:%d}'%(self.name,self.age))

    #创建一个子类对象

    temp = Person('Wu-Jing',38)

    #访问父类的数据成员

    temp.salary = 21000

    temp.industry = "IT"

    #分别调用本身和父类的函数

    temp.printOccupationInfo()

    temp.printPersonInfo()

    执行结果:

    Occupation-info:{salary:21000, industry:IT}

    person-info:{name:Wu-Jing, age:38}

    多继承

    一些场景下,一个子类可能需要继承多个父类,

    举个例子:有三个类分别描述职

    业信息,购物信息,银行账户信息,现在定义一个类

    Person来描述一个人,

    显然,Person涉及上述三个类的信息,为了重复利用

    代码,降低开发难度,可以直接继承上述三个类,这便是多继承的应用。

    如上所述,

    多继承定义形式如下:

    classchildClassName(parentClassName1,parentClassName2,…):

    .

    .

    .

    关于多继承,实例如下:

    #定义一个类BankAccount,描述银行账户

    classBankAccount:

    def__init__(self,number, balance):

    self.number = number

    self.balance = balance 

    #计算并返回年利息

    defgetAnnualInterest(self):

    returnself.balance*0.042

    #定义一个类Occupation,描述职业

    classOccupation:

    def__init__(self,salary,industry):

    self.salary = salary

    self.industry = industry

    defprintOccupationInfo(self):

    print('Occupation-info:{salary:%d, industry:%s}'%(self.salary,self.industry)) 

    #定义一个类Person,继承自类BankAccount和BankAccount 

    classPerson(Occupation,BankAccount):

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    #定义一个函数:打印类实例的基本信息 

    defprintPersonInfo(self):

    print('person-info:{name:%s, age:%d}'%(self.name,self.age))

    #创建一个子类对象

    temp = Person('Wu-Jing',38)

    #访问父类数据成员

    temp.number = 622202050201

    temp.balance = 1000000.99

    temp.salary = 21000

    temp.industry = "IT"

    #分别调用本身和父类的函数

    temp.printOccupationInfo()

    temp.printPersonInfo()

    print('Annual interest:',temp.getAnnualInterest())

    执行结果:

    Occupation-info:{salary:21000, industry:IT}

    person-info:{name:Wu-Jing, age:38}

    Annualinterest: 42000.041580000005

    需要注意的是,多继承中,子类继承了不同父类中的属性和函数,这些属性和函数可能存在同名的情况,在子类使用这些同名的函数或属性时,在没有指定的情况下,Python 将根据一定顺序进行搜索:首先搜索子类,如果未找到则根据多继承定义的顺序,从左至右在父类中查找。

    如下实例:

    #定义一个类 BankAccount,描述银行账户

    classBankAccount: 

    defprintInfo(self):

    print('BankAccount-info') 

    #定义一个类 Occupation,描述职业

    classOccupation:

    defprintInfo(self):

    print('Occupation-info') 

    #定义一个类 Person,继承自类 BankAccount 和 BankAccount 

    classPerson(Occupation,BankAccount):

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    defprintPersonInfo(self):

    print('person-info')

    #创建一个子类对象

    temp = Person('Wu-Jing',38)

    #调用父类中的函数

    temp.printInfo()

    执行结果:

    Occupation-info

    很明显,根据定义顺序,优先调用父类 Occupation 中的 printInfo()。

    函数的重写

    一些场景下,从父类继承来的函数并不能完全满足需求,需要在子类中对其进行修改,这就是重写的概念:在子类中重写父类中的函数,当子类对象调用该名称的函数时,会调用子类中重写的函数,父类中的同名函数将被覆盖。

    实例如下:

    #定义一个类Occupation,描述职业

    classOccupation:

    #定义构造函数

    def__init__(self,salary,industry):

    self.salary = salary

    self.industry = industry

    defprintInfo(self):

    print('salary:%d, industry:%s}'%(self.salary,self.industry)) 

    #定义一个简单的类Person,继承自类Occupation 

    classPerson(Occupation):

    def__init__(self,name,age):

    self.name = name

    self.age = age 

    #定义一个函数:打印类实例的基本信息 

    defprintInfo(self):

    print('name:%s, age:%d'%(self.name,self.age))

    print('salary:%d, industry:%s'%(self.salary,self.industry))

    #创建一个子类对象

    temp = Person('Wu-Jing',38)

    #访问父类的数据成员

    temp.salary = 21000

    temp.industry = "IT"

    #分别调用函数printInfo()

    temp.printInfo()

    执行结果

    name:Wu-Jing, age:38

    salary:21000, industry:IT

    私有属性与私有方法

    前面几节的实例中,类的属性和函数都是“公有”的,可以通过类对象直接访问。

    但是,在某些场景下,我们并不希望对外暴露类的内

    部细节,为了限制外部访问,我们可以将对应的属性和函数设置为私有。

    将类的属性和函数设置为私有的一般形

    式为以下两种。

    1.定义私有属性

    __attribute:属性名前面加两个下划线,

    即声明该属性为私有,不能在类的外部直接访问,

    在类内部访问时用

     self.__attribute。

    2.定义私有函数

    __function:函数名前面加两个下划线,即声明该函数为私有,不能在类的外部直

    接访问,在类内部访问时用 self.__ function。

    实例如下:

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义两个私有属性name,age

    def__init__(self,name,age):

    self.__name = name

    self.__age = age 

    #定义公有函数,在类外部可以访问 

    defgetName(self):

    self.__fun()

    returnself.__name

    defgetAge(self):

    returnself.__age

    #定义一个私有函数,只能在类内部使用

    def__fun(self):

    print('hello')

    #实例化

    p1 = Person("Zhang San",12)

    #访问类的私有属性和私有函数,将会报错

    print("name:",p1.__age)

    print("age:",p1.__name)

    p1.__fun()

    对于私有属性和私有函数,如果需要在类外访问,可以通过公有函数实现,这与

    Java 和 C++ 是一致的。

    如下实例:

    #定义一个简单的类,描述一个人的基本信息 

    classPerson:

    #定义两个私有属性name,age

    def__init__(self,name,age):

    self.__name = name

    self.__age = age 

    #定义公有函数,在类外部可以访问 

    defgetName(self):

    self.__fun()

    returnself.__name

    defgetAge(self):

    returnself.__age

    #定义一个私有函数,只能在类内部使用

    def__fun(self):

    print('hello')

    #实例化

    p1 = Person("Zhang San",12)

    #访问类的公有函数

    print("name:",p1.getName())

    执行结果:

    hello

    name: Zhang San

    相关文章

      网友评论

          本文标题:详解抽象之类

          本文链接:https://www.haomeiwen.com/subject/uoxgjltx.html