分享

Python自学知识点整理--类

 网海拾贝网络猪 2018-12-15

四、类:


1. 类中对象:类中对象其实是一种自定义的数据结构(类比于字符串、字典等),既包含变量(习惯称为特性、属性),也包含代码(函数,也称为方法)

#Python里的所有数据都是以对象形式存在,无论是简单的数据类型还是复杂的代码模块。然而,Python特殊的语法形式巧妙的将实现对象机制的大量

#细节隐藏了起来,输入num = 7 就可以创建一个值为7的整数对象,并且将这个对象赋值给变量num。在Python中,只有当你想要创建属于自己的对象或者

#需要修改已有对象的行为时,才需要关注对象的内部实现结构。

它是某一类具体事务的特殊实例。


类比概念:整数就是一个包含了加法、乘法之类方法的对象,属于一个公共的类。字符串也是Python对象,也有自己的字符串方法。

当你想要创建一个别人从来没有创建过的新对象时,首先必须定义一个类,用以表明该类型的对象所包含的特性和方法。


如果我们把对象比作塑料盒子,类则像制作盒子用的模具。


2. 根据类来创建对象被称为实例化 ,这让你能够使用类的实例。对象代表着一个独立的事物,它的方法则定义了它是如何与其他事物相互作用的。


3. 与模块不同,你可以同时创建许多同类的对象,它们的特性值可能各有不同。


3. 首字母大写的名称指的是类


例子1:创建Dog()类:

class Dog():

    '''一次模拟小狗的简单尝试'''

    def __init__(self, name, age): #_init_并不是必须的,只有当需要区分由该类创建的不同对象时,才需要指定_init_方法

        '''初始化属性name和age'''

        self.name = name

        self.age = age

    def sit(self):

        '''模拟小狗被命令时蹲下'''

        print(self.name.title() + ' is now sitting.')

    def roll_over(self):

        '''模拟小狗被命令时打滚'''

        print(self.name.title() + ' rolled over!')

类中的函数称为方法,前面学到的有关于函数的一切都适用于方法。


a. 解释一下_init_方法

类中的函数是方法,前面学习到的有关函数的一切都适用于方法,_init_方法是一个特殊的方法,每当你根据Dog类创建新实例的时候,

Python都会自动运行它。 


b.上面的例子中_init_包含了三个形参:self、name、age,形参self必不可少,还必须位于其他形参前面。


当后面创建实例调用类的时候,比如说obj1=Dog('xiaohuang', '23'),self等于obj1,实参‘xiaohuang’、‘23’分别传入到了形参name、age里。

当执行obj2 = Dog ('xiaohei', '12')时,self等于obj2. 


所以,内容其实被封装到了对象obj1和obj2中,每个对象都有name和age属性。


c. 那我们再解释一下对象和属性、类、方法、实例的含义和之间的关系

你可能经常听到一句话‘Python是面向对象的变成语言’,那这句话到底什么意思呢?Python里所有的数据-布尔值、整数、浮点数、字符串,甚至

大型数据结构、函数以及程序-都是以对象的形式存在。


Python是强类型的。


这里区分一下对象和变量,变量是在程序中为了方便的引用内存中的值而为它取的名字。变量是数据,不同类型的数据。


对象既包含数据(变量,或者特性,或者属性),也包含代码(函数,或者方法)。它是一类具体事物的特殊实例。


1)类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。


2)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。


3)实例变量:定义在方法中的变量,只作用于当前实例的类。


4)实例化:创建一个类的实例,类的具体对象。


5)方法:类中定义的函数。


6)对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法


#!/usr/bin/python

# -*- coding: UTF-8 -*-


class Employee:

   '所有员工的基类'

   empCount = 0


   def __init__(self, name, salary):

      self.name = name

      self.salary = salary

      Employee.empCount += 1

   

   def displayCount(self):

     print 'Total Employee %d' % Employee.empCount


   def displayEmployee(self):

      print 'Name : ', self.name,  ', Salary: ', self.salary

empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。

第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法

self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。


self代表类的实例,而非类

类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。



例子2:根据类创建实例:


class Dog():

    --snip--

❶ my_dog = Dog('willie', 6)

❷ print('My dog's name is ' + my_dog.name.title() + '.')

❸ print('My dog is ' + str(my_dog.age) + ' years old.')


这里使用的是前一个示例中编写的Dog 类。在❶处,我们让Python创建一条名字为'willie' 、年龄为6 的小狗。遇到这行代码时,Python使用实参'willie' 和6 调用Dog 类

中的方法__init__() 。方法__init__() 创建一个表示特定小狗的示例,并使用我们提供的值来设置属性name 和age 。方法__init__() 并未显式地包含return 语句,

但Python自动返回一个表示这条小狗的实例。我们将这个实例存储在变量my_dog 中。在这里,命名约定很有用:我们通常可以认为首字母大写的名称(如Dog )指的是类,而

小写的名称(如my_dog )指的是根据类创建的实例。




1)访问属性

my_dog.name

句点表示法在Python中很常用,这种语法演示了Python如何获悉属性的值。在这里,Python先找到实例my_dog ,再查找与这个实例相关联的属性name 。在Dog 类中引用这个属

性时,使用的是self.name 。我们使用同样的方法来获取属性age 的值。


2)调用方法

根据Dog 类创建实例后,就可以使用句点表示法来调用Dog 类中定义的任何方法

class Dog():

    --snip--

my_dog = Dog('willie', 6)

my_dog.sit()

my_dog.roll_over()


3)可创建多个实例


class Dog():

    --snip--

my_dog = Dog('willie', 6)

your_dog = Dog('lucy', 3)


print('My dog's name is ' + my_dog.name.title() + '.')

print('My dog is ' + str(my_dog.age) + ' years old.')

my_dog.sit()

print('\nYour dog's name is ' + your_dog.name.title() + '.')

print('Your dog is ' + str(your_dog.age) + ' years old.')

your_dog.sit()


4. 使用类和实例


你可以使用类来模拟现实世界中的很多情景。类编写好后,你的大部分时间都将花在使用根据类创建的实例上。你需要执行的一个重要任务是修改实例的属性。你可以直接修改

实例的属性,也可以编写方法以特定的方式进行修改。


例子1:编写一个表示汽车的类


class Car():

'''一次模拟汽车的简单尝试'''

❶     def __init__(self, make, model, year):

      '''初始化描述汽车的属性'''

        self.make = make

        self.model = model

        self.year = year

❷     def get_descriptive_name(self):

      '''返回整洁的描述性信息'''

        long_name = str(self.year) + ' ' + self.make + ' ' + self.model

        return long_name.title()

❸ my_new_car = Car('audi', 'a4', 2016)

print(my_new_car.get_descriptive_name())


在❶处,我们定义了方法__init__() 。与前面的Dog 类中一样,这个方法的第一个形参为self ;我们还在这个方法中包含了另外三个形参:make 、model 和year 。方

法__init__() 接受这些形参的值,并将它们存储在根据这个类创建的实例的属性中。创建新的Car 实例时,我们需要指定其制造商、型号和生产年份。


在❷处,我们定义了一个名为get_descriptive_name() 的方法,它使用属性year 、make 和model 创建一个对汽车进行描述的字符串,让我们无需分别打印每个属性的

值。为在这个方法中访问属性的值,我们使用了self.make 、self.model 和self.year 。在❸处,我们根据Car 类创建了一个实例,并将其存储到变量my_new_car

中。接下来,我们调用方法get_descriptive_name() ,指出我们拥有的是一辆什么样的汽车:


2016 Audi A4


例子2:给属性提供默认值


类中的每个属性都必须有初始值,哪怕这个值是0或空字符串。在有些情况下,如设置默认值时,在方法__init__() 内指定这种初始值是可行的;如果你对某个属性这样做

了,就无需包含为它提供初始值的形参。

下面来添加一个名为odometer_reading 的属性,其初始值总是为0。我们还添加了一个名为read_odometer() 的方法,用于读取汽车的里程表:


class Car():

    def __init__(self, make, model, year):

    '''初始化描述汽车的属性'''

        self.make = make

        self.model = model

        self.year = year

❶       self.odometer_reading = 0

    def get_descriptive_name(self):

        --snip--

❷    def read_odometer(self):

     '''打印一条指出汽车里程的消息'''

        print('This car has ' + str(self.odometer_reading) + ' miles on it.')


my_new_car = Car('audi', 'a4', 2016)

print(my_new_car.get_descriptive_name())

my_new_car.read_odometer()


现在,当Python调用方法__init__() 来创建新实例时,将像前一个示例一样以属性的方式存储制造商、型号和生产年份。接下来,Python将创建一个名

为odometer_reading 的属性,并将其初始值设置为0(见❶)。在❷处,我们还定义了一个名为read_odometer() 的方法,它让你能够轻松地获悉汽车的里程。


2016 Audi A4

This car has 0 miles on it.


例子3:修改属性的值

可以以三种不同的方式修改属性的值:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)。


1)直接通过实例进行修改

要修改属性的值,最简单的方式是通过实例直接访问它。下面的代码直接将里程表读数设置为23:


class Car():

    --snip--

my_new_car = Car('audi', 'a4', 2016)

print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23

my_new_car.read_odometer()


2016 Audi A4

This car has 23 miles on it.


2)通过方法进行设置

如果有替你更新属性的方法,将大有裨益。这样,你就无需直接访问属性,而可将值传递给一个方法,由它在内部进行更新。

下面的示例演示了一个名为update_odometer() 的方法:

class Car():

    --snip--

1    def update_odometer(self, mileage):

    '''彨棦掱昞.悢.抲.巜掕揑.'''

        self.odometer_reading = mileage

        my_new_car = Car('audi', 'a4', 2016)

        print(my_new_car.get_descriptive_name())


2 my_new_car.update_odometer(23)

my_new_car.read_odometer()


对Car 类所做的唯一修改是在1处添加了方法update_odometer() 。这个方法接受一个里程值,并将其存储到self.odometer_reading 中。在2处,我们调用

了update_odometer() ,并向它提供了实参23(该实参对应于方法定义中的形参mileage )。它将里程表读数设置为23;而方法read_odometer() 打印该读数:


2016 Audi A4

This car has 23 miles on it.


3)通过方法对属性的值进行递增

有时候需要将属性值递增特定的量,而不是将其设置为全新的值。假设我们购买了一辆二手车,且从购买到登记期间增加了100英里的里程,下面的方法让我们能够传递这个增

量,并相应地增加里程表读数:


class Car():

    --snip--

    def update_odometer(self, mileage):

        --snip--

    def increment_odometer(self, miles):

    '''彨棦掱昞.悢鷿壛巜掕揑検'''

        self.odometer_reading += miles

        my_used_car = Car('subaru', 'outback', 2013)

        print(my_used_car.get_descriptive_name())

my_used_car.update_odometer(23500)

my_used_car.read_odometer()

my_used_car.increment_odometer(100)

my_used_car.read_odometer()


5. 继承


1)在编写代码解决实际问题时,经常能找到一些已有的类,它们能够实现你所需的大部分功能,但不是全部。这时候利用类的继承。

从已有类中衍生出新的类,添加或修改部分功能。


2)一个类继承 另一个类时,它将自动获得另一个类的所有属性和方法;原有的

类称为父类 ,而新类称为子类 。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。


3)习惯上将原始的类称为 父类、超类或基类,将新的类称作孩子类、子类或衍生类。


4)定义子类的方法:

若已有的父类是Car,然后我们定义一个Car的子类Yugo,关键字class一样,不同的是需要在子类Yugo名字后面的括号里加上父类的名字。

>>> class Car():

        pass


>>> class Yugo(Car):

        pass

以上格式有一点需要关注:创建子类时,父类必须包含在当前文件中,且位于子类前面


class ElectricCar(Car):

'''电动汽车的独特之处'''

❸    def __init__(self, make, model, year):

     '''初始化父类的属性'''

❹           super().__init__(make, model, year)

super() 是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用ElectricCar 的父类的方法__init__() ,让ElectricCar 实例包含父类的所

有属性。父类也称为超类 (superclass),名称super因此而得名。


6. 给子类定义属性和方法

让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。

下面来添加一个电动汽车特有的属性(电瓶),以及一个描述该属性的方法。我们将存储电瓶容量,并编写一个打印电瓶描述的方法:

class Car():

    --snip--

class ElectricCar(Car):

'''Represent aspects of a car, specific to electric vehicles.'''

    def __init__(self, make, model, year):

'''电动汽车的独特之处初始化父类的属性,再初始化电动汽车特有的属性'''

        super().__init__(make, model, year)

❶       self.battery_size = 70

❷   def describe_battery(self):

    '''打印一条描述电瓶容量的消息'''

        print('This car has a ' + str(self.battery_size) + '-kWh battery.')

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())

my_tesla.describe_battery()


我们添加了新属性self.battery_size ,并设置其初始值(如70 )。根据ElectricCar 类创建的所有实例都将包含这个属性,但所有Car 实例都不包含它。

我们还添加了一个名为describe_battery() 的方法,它打印有关电瓶的信息。我们调用这个方法时,将看到一条电动汽车特有的描述:

2016 Tesla Model S

This car has a 70-kWh battery.


对于ElectricCar 类的特殊化程度没有任何限制。模拟电动汽车时,你可以根据所需的准确程度添加任意数量的属性和方法。如果一个属性或方法是任何汽车都有的,而不是

电动汽车特有的,就应将其加入到Car 类而不是ElectricCar 类中。这样,使用Car 类的人将获得相应的功能,而ElectricCar 类只包含处理电动汽车特有属性和行为的代

码。


7. 重写父类方法

对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这

个父类方法,而只关注你在子类中定义的相应方法。

假设Car 类有一个名为fill_gas_tank() 的方法,它对全电动汽车来说毫无意义,因此你可能想重写它。下面演示了一种重写方式:

class ElectricCar(Car):

    --snip--

    def fill_gas_tank():

    '''电动汽车没有油箱'''

        print('This car doesn't need a gas tank!')


现在,如果有人对电动汽车调用方法fill_gas_tank() ,Python将忽略Car 类中的方法fill_gas_tank() ,转而运行上述代码


8. 拆分小类

使用代码模拟实物时,你可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分作为一个独立的类提取出来。

你可以将大型类拆分成多个协同工作的小类。

例如,不断给ElectricCar 类添加细节时,我们可能会发现其中包含很多专门针对汽车电瓶的属性和方法。在这种情况下,我们可将这些属性和方法提取出来,放到另一个名

为Battery 的类中,并将一个Battery 实例用作ElectricCar 类的一个属性:


class Car():

--snip--

❶ class Battery():

'''一次模拟电动汽车电瓶的简单尝试'''

❷   def __init__(self, battery_size=70):

    '''初始化电瓶的属性'''

        self.battery_size = battery_size

❸   def describe_battery(self):

    '''打印一条描述电瓶容量的消息'''

        print('This car has a ' + str(self.battery_size) + '-kWh battery.')

class ElectricCar(Car):

'''电动汽车的独特之处'''

    def __init__(self, make, model, year):

    '''初始化父类的属性,再初始化电动汽车特有的属性'''

        super().__init__(make, model, year)

❹       self.battery = Battery()

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())

my_tesla.battery.describe_battery()


9. 导入类 

1)导入单个类 

car是包含Car类的一个模块


from car import Car

my_new_car = Car('audi', 'a4', 2016)

print(my_new_car.get_descriptive_name())

my_new_car.odometer_reading = 23

my_new_car.read_odometer()


2)在一个模块中存储多个类

虽然同一个模块中的类之间应存在某种相关性,但可根据需要在一个模块中存储任意数量的类。类Battery 和ElectricCar 都可帮助模拟汽车,因此下面将它们都加入模块

car.py中:

from car import ElectricCar

my_tesla = ElectricCar('tesla', 'model s', 2016)

print(my_tesla.get_descriptive_name())

my_tesla.battery.describe_battery()

my_tesla.battery.get_range()


3)从一个模块中导入多个类

from car import Car, ElectricCar

❷ my_beetle = Car('volkswagen', 'beetle', 2016)

print(my_beetle.get_descriptive_name())

❸ my_tesla = ElectricCar('tesla', 'roadster', 2016)

print(my_tesla.get_descriptive_name())


4)导入整个模块

import car

❷ my_beetle = car.Car('volkswagen', 'beetle', 2016)

print(my_beetle.get_descriptive_name())

❸ my_tesla = car.ElectricCar('tesla', 'roadster', 2016)

print(my_tesla.get_descriptive_name())


5)导入模块中所有类

from module_name import *


6)在一个模块中导入另一个模块

有时候,需要将类分散到多个模块中,以免模块太大,或在同一个模块中存储不相关的类。将类存储在多个模块中时,你可能会发现一个模块中的类依赖于另一个模块中的类。

在这种情况下,可在前一个模块中导入必要的类。


例如,下面将Car 类存储在一个模块中,并将ElectricCar 和Battery 类存储在另一个模块中。我们将第二个模块命名为electric_car.py


electric_car.py

'''一组可用于表示电动汽车的类'''

❶ from car import Car

class Battery():

    --snip--

class ElectricCar(Car):

    --snip--A?R?'t


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多