Python学习——类


一、概述

面向对象编程(oop, Object Oriented Programming)是最有效的软件编写方法之一。在面向对象的编程中,我们编写表示现实世界中的实物和情景的类,并基于这些类来创造对象。通过类来创造对象的过程被称为实例化,这让我们能够使用类的实例。


二、创建和使用类

使用类几乎可以模拟任何东西。

1、创建dog类

下面我们创建了一个dog类,根据dog类创建的每个实例都将存储名字和年龄,并且我们赋予了每条小狗蹲下(sit() )和打滚(roll_over() )的能力:

① class Dog():
②    """一次模拟小狗的简单尝试"""

③     def __init__(self, name, age):
         """初始化属性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!")

​

根据约定,在Python中,首字母大写的名称指的是类。

(1)方法__init__()

类中的函数称为方法

上面代码中的方法__init__()是一个特殊的方法,每当我们根据Dog类创建新实例时,Python都会自动运行它。

我们将方法__init__() 定义成了包含三个形参: self 、 name 和age 。其中,形参self必不可少,且位于最前面。在这个方法中,形参self必不可少的原因是:Python调用这个__init__() 方法来创建Dog 实例时, 将自动传入实参self 。 每个与类相关联的方法调用都自动传递实参self , 它是一个指向实例本身的引用, 让实例能够访问类中的属性和方法。(这个实参self其实就是实例化时使用的变量,如后面的my_dog)。

我们通过实参向Dog()传递名字和年龄;self会自动传递,我们只需传递后两个形参(name和age)提供值。

④处定义的变量都有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 ) 指的是类, 而小写的名称(如my_dog ) 指的是根据类创建的实例。

(1)访问属性

要访问实例的属性,可使用句点表示法:

my_dog.name

(2)调用方法

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

class Dog():
--snip--

my_dog = Dog('willie', 6)
my_dog.sit()
my_dog.roll_over()

(3)创建多个实例

可按需要根据类创建任意数量的实例。下面再创建一个名为your_dog的实例:

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()

输出:

My dog's name is Willie.
My dog is 6 years old.
Willie is now sitting.

Your dog's name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.

三、使用类和实例

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

1、给属性指定默认值

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

如下面的名为odometer_reading 的属性:

 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):
         """返回整洁的描述性信息"""
         long_name = str(self.year) + ' ' + self.make + ' ' + self.model
         return long_name.title()

❷    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()

输出:

2016 Audi A4
This car has 0 miles on it.

2、修改属性的值

出售时里程表读数为0的汽车并不多,因此需要一个修改该属性的值的途径。

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

(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--
❶     def update_odometer(self, mileage):
          """将里程表读数设置为指定的值"""
          self.odometer_reading = mileage

  my_new_car = Car('audi', 'a4', 2016)
  print(my_new_car.get_descriptive_name())

❷ my_new_car.update_odometer(23)
  my_new_car.read_odometer()

(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()

在❶处, 新增的方法increment_odometer() 接受一个单位为英里的数字, 并将其加入到self.odometer_reading 中。

输出

2013 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.

三、继承

编写类时,不一定非要从空白开始。如果我们编写的类是另一个类的特殊版本,可使用继承。一个类继承另一个类时,他将自动获得另一个类的所有属性和方法。原有的类称为父类,而新类称为子类。子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法。

1、子类的方法__init__()

在创建子类的实例时,Python首先给父类中的所有属性赋值。这就需要将子类中的方法__init__()与父类中的方法__init__()关联起来。使用super()函数。

下面我们模拟电动汽车。电动汽车是一种特殊的汽车,所以我们在之前car类的基础之上创建新类ElectricCar,这样我们就只需为电动汽车特有的属性和行为编写代码。

❶ 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):
          long_name = str(self.year) + ' ' + self.make + ' ' + self.model
          return long_name.title()

      def read_odometer(self):
          print("This car has " + str(self.odometer_reading) + " miles on it.")

      def update_odometer(self, mileage):
          if mileage >= self.odometer_reading:
              self.odometer_reading = mileage
          else:
              print("You can't roll back an odometer!")

      def increment_odometer(self, miles):
          self.odometer_reading += miles

❷     class ElectricCar(Car):
          """电动汽车的独特之处"""

❸         def __init__(self, make, model, year):
              """初始化父类的属性"""
❹             super().__init__(make, model, year)

❺ my_tesla = ElectricCar('tesla', 'model s', 2016)
  print(my_tesla.get_descriptive_name())

首先是Car类的代码(间①),创建子类时,父类必须包含在当前文件夹下,且在子类的前面。在②处,我们定义了新的子类ElectricCar。定义子类时,括号中必须指定父类的名称。方法__init__()接收创建Car类所需的信息。

如上所述,④处的super()是一个特殊的函数,帮助Python将子类和父类关联起来。这行代码让Python调用父类(Car类)中的方法__init__(),让ElectricCar实例包含父类(Car类)中的所有属性。父类也称为超类,函数名super()由此得名。

为测试继承是否好用,在⑤处创建了一个ElectricCar的实例。

输出:

2016 Tesla Model S

2、给子类定义属性和方法

在上面的介绍中,我们只介绍了怎样继承父类的属性和方法。接下来介绍如何创建子类特有的属性和方法。

在下面的代码中,我们给子类ElectricCar添加一个特有的方法describe_battery():

  class Car():
      --snip-- 
  
  class ElectricCar(Car):
      """继承Car类的属性,并添加电动车特有的属性"""
                     
      def __init__(self, make, model, year):
          """
          电动汽车的独特之处
          初始化父类的属性,再添加电动汽车特有的属性
          """
          super.__init__(make, model, year)
①         seif.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()         

    

在①处,我们加了一个新属性;在②处,我们添加了一个新方法。

3、重写父类的方法

对于父类的方法,只要它不符合子类模拟的实物的行为,就可以进行重写。只需在子类中重写的方法与父类中的方法同名就可以了。

现在假设Car类中,有一个叫做fill_gas_tank()的方法,它对ElectricCar完全没用,所以可以对它进行重写:

def ElectricCar(Car):
    --snip--

    def fill_gas_tank():
        """电动汽车没有油箱"""
        print("This car doesn't need a gas tank!")

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

4、将实例用作属性

在编写一个类时,随着添加的属性和方法越来越多,代码会越来越长,这时可以将这个类的一部分作为一个独立的类提取出来。

我们可以讲一个大型类拆分成几个协同工作的小类。

例如,我们在不断给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()

在①处,我们定义了一个名为Battery的新类,它没有继承任何类。②处的方法__init__()除self外,还有一个形参battery_size。这个形参是可选的:如果没有给它提供值,默认70。


在ElectricCar 类中, 我们添加了一个名为self.battery 的属性(见❹) 。 这行代码让Python创建一个新的Battery 实例(由于没有指定尺寸, 因此为默认值70 ) , 并将该实例存储在属性self.battery 中。 每当方法__init__() 被调用时, 都将执行该操作; 因此现在每个ElectricCar 实例都包含一个自动创建的Battery 实例。


四、导入类

Python可以将类存储在模块中,然后在主程序中导入所需的模块。

1、导入单个类

注意:使用一个模块的程序的名称不能与该模块同名。例如:一个包含了Car类的模块命名为car.py,则使用这个模块的程序应使用更具体的名称,如:my_cay.py。

car.py

❶ """一个可用于表示汽车的类"""
  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):
          """返回整洁的描述性名称"""
          long_name = str(self.year) + ' ' + self.make + ' ' + self.model
          return long_name.title()

      def read_odometer(self):
          """打印一条消息, 指出汽车的里程"""
          print("This car has " + str(self.odometer_reading) + " miles on it.")

      def update_odometer(self, mileage):
      """
     将里程表读数设置为指定的值
     拒绝将里程表往回拨
     """
         if mileage >= self.odometer_reading:
             self.odometer_reading = mileage
         else:
             print("You can't roll back an odometer!")

     def increment_odometer(self, miles):
     """将里程表读数增加指定的量"""
         self.odometer_reading += miles

my_car.py
 

❶ 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()

①处,from car import Car,从car模块中调用Car类。

2016 Audi A4
This car has 23 miles on it.

另外,我们还可以在一个模块中存储多个类,以及从一个模块中导入多个类,还可以导入整个模块。

从一个模块中导入多个类:from car import Car, ElectricCar
导入整个模块:import car

还可以从一个模块中导入所有类,使用语法:from module_name import *,但不推荐使用。需要从一个模块中导入很多类时, 最好导入整个模块, 并使用 module_name.class_name 语法来访问类。
 


五、Python标准库

Python标准库是一组模块。跟上面所述的使用方法相同。


六、类编码风格

我们必须熟悉有些与类相关的编码风格问题, 在编写的程序较复杂时尤其如此。


类名应采用驼峰命名法 , 即将类名中的每个单词的首字母都大写, 而不使用下划线。 实例名和模块名都采用小写格式, 并在单词之间加上下划线。


对于每个类, 都应紧跟在类定义后面包含一个文档字符串。 这种文档字符串简要地描述类的功能, 并遵循编写函数的文档字符串时采用的格式约定。 每个模块也都应包含一个文档字符串, 对其中的类可用于做什么进行描述。


可使用空行来组织代码, 但不要滥用。 在类中, 可使用一个空行来分隔方法; 而在模块中, 可使用两个空行来分隔类。


需要同时导入标准库中的模块和你编写的模块时, 先编写导入标准库模块的import 语句, 再添加一个空行, 然后编写导入你自己编写的模块的import 语句。 在包含多条import 语句的程序中, 这种做法让人更容易明白程序使用的各个模块都来自何方。

以上内容基本来自于《Python编程:从入门到实践》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值