第二模块 类的笔记_汇总 第一篇

@

Python: 面向对象编程基础

  1. 面向对象编程( Object Oriented Programming, OOP) 是一种程序设计理想
  2. 在Python中, 所有数据类型都被视为对象, 自定义对象的数据类型就是面向对象中类class的概念

类编程风格, 标准

  • 关键词: , 实例, 方法(属性), 属性: 形参变量, 实例变量的值
  • 扩展知识: 包含类的py文件被称为模块,
  • 书写规范:
    • 类名应采用驼峰命名法, 即:将类名的每个单词的首字母大写,而不是使用下划线.
    • 实例名和模块名都采用小写格式, 多个单词拼接时,在单词之间使用下划线
    • 对于每个类, 都应该在类定义之后包含一个文档字符串 docstring进行简要的描述类的功能,甚至可以加上使用方法
    • 空行: 一个空行分隔方法, 两个空行分隔类
    • 导入模块时, 先导入标准库, 再使用空行区分自定义模块

类和实例

  • Class: 类是抽象的模板
  • 实例Instance: 实例是根据类创造出来的一个个具体的对象 (数据类型)
# 类, 抽象的模板
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def print_age(self):
        print(f"{self.name}'s age is {self.age}")
# 实例, 具体化类的对象
jim = Student("Jim", "20")
jim.print_age()  # 调用类方法
Jim's age is 20

方法

构造方法__init__(self, name, age)

  • 方法: 在类中的函数被称为方法,在类中的方法区分于函数 的地方就是调用的方式
  • 方法的圆括号内是形参:
    • 形参self位于其他形参前,区别于普通函数,表示创建的实例本身. Python在调用__init__方法时将自动传入实参self.
    • 形参name, age: 通过实例对象向模板传递形参变量, 该变量就被关联到当前创造的实例

访问属性

# 接上一个代码示例
jim.name
'Jim'
jim  # 查看类在内存的位置
<__main__.Student at 0x1d67c42b1d0>
  • 查看类在内存的位置
  • 访问实例的属性
  • 在编写类的过程中常见性会直接调用类,而没有进行实例化造成输出内容为内存的位置

调用方法

  • 可以按照需求根据类创建任意数量的实例, 对属性进行各类的数据封装
lili = Student("Lili", "20")
lili.print_age()

blue = Student("Blue", "20")
blue.print_age()
Lili's age is 20
Blue's age is 20

面向对象的特性:

1.class : 一个类是对拥有相同属性的对象的抽象. 类拥有类的属性和类的方法
2. object 对象: 一个对象即是一个类的实例化的实例. 这个过程就实例化
3. Encapsulation 封装: 在类中对数据的赋值, 隐藏实现细节,使得代码模块化
4. Inheritance 继承: 扩展已存在的代码模块(类),它们的目的都是为了代码重用
5. Polymorphism 多态: 接口重用。类在继承和派生的时候,保证使用"家谱"中任一类的实例的某一属性时的正确调用

案例:

# -*- coding:utf-8 -*-
# 演示一个汽车类
class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
2016 Audi A4

直接修改属性的默认值

# -*- coding:utf-8 -*-
# 演示一个汽车类
class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0  # 增加汽车里程数,并设置初始值为0
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
    def read_odo(self):
        """打印一条关于汽车里程数的消息"""
        print(f"{self.make} " + str(self.odometer_reading) + "miles on it ")
    
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 30  # 传递一个属性的值
my_new_car.read_odo()
2016 Audi A4
audi 30miles on it 

通过方法修改属性的值

# -*- coding:utf-8 -*-
# 演示一个汽车类
class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0  # 增加汽车里程数,并设置初始值为0
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
    def update_odo(self, mileage):
        """使用方法来修改属性的值"""
        self.odometer_reading = mileage    

    def read_odo(self):
        """打印一条关于汽车里程数的消息"""
        print(f"{self.make} " + str(self.odometer_reading) + "miles on it ")

    
my_new_car = Car('audi', 'a4', 2016)
print(my_new_car.get_descriptive_name())
my_new_car.update_odo(50)  # 类方法赋值给形参属性
my_new_car.read_odo()
2016 Audi A4
audi 50miles on it 

针对类方法进行逻辑判断,从而获得自定义传参效果

class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 500  # 增加汽车里程数,并设置初始值为0
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
    def update_odo(self, mileage):
        """
        设定里程表初始指定值
        禁止将里程表读数往回调
        """
        if mileage >= self.odometer_reading: # 构造函数中的形参默认值
            self.odometer_reading = mileage
        else:
            print("不可以偷偷修改里程数哟! ")
            
    def read_odo(self):
        """打印一条关于汽车里程数的消息"""
        print(f"{self.make} " + str(self.odometer_reading) + "miles on it ")

    def increment_odo(self, miles):
        """将里程表的值增加指定量"""
        self.odometer_reading += miles
        
used_car = Car('honde', 'outback', 2006)
print(used_car.get_descriptive_name())

used_car.update_odo(5250)  # 类方法赋值给形参属性
used_car.read_odo()

used_car.increment_odo(50)  # 控制用户随意修改里程数
used_car.read_odo()
2006 Honde Outback
honde 5250miles on it 
honde 5300miles on it 

继承, 重写父类的方法

  • 目标: 减少重复性工作
  • 子类继承父类的所有属性和方法, 同时还可以自定义自己的属性和方法
  • 初学时经常性出现的错误,各种难过(小彩蛋)

案例: 在汽车类的基础上,个性化创建一类电动汽车

# -*- coding:utf-8 -*-
class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0  # 增加汽车里程数,并设置初始值为0
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
    def update_odo(self, mileage):
        """
        设定里程表初始指定值
        禁止将里程表读数往回调
        """
        if mileage >= self.odometer_reading: # 构造函数中的形参默认值
            self.odometer_reading = mileage
        else:
            print("不可以偷偷修改里程数哟! ")
            
    def fill_gas_tank(self):
        """子类会重写"""
        print("我是烧油的! ")
            
    def read_odo(self):
        """打印一条关于汽车里程数的消息"""
        print(f"{self.make} " + str(self.odometer_reading) + "miles on it ")
        
    def increment_odo(self, miles):
        """将里程表的值增加指定量"""
        self.odometer_reading += miles
        

class ElectCar(Car):
    """获取Car类的属性,并定义一个新的子类电动汽车"""
    def __init__(self, make, model, year):
        super().__init__(make, model, year)  # 3.0的写法
        """super(ElectCar, self)__init__(make, model, year), 2.7的写法"""
        self.battery_size = 70  # 子类的特有属性
        
    def describ_battery(self):
        """输出一条关于电池的消息"""
        print("This ElectricCar has a " + str(self.battery_size) + "-kWh battery")
    
    def fill_gas_tank(self):
        """重写父类方法"""
        print("我不需要油箱! ")
        

my_elect_car = ElectCar("tesla", "model's", 2018)
print(my_elect_car.get_descriptive_name())
print("这里是分隔符区分实例方法故障,送新手".center(50, "*"))
print(my_elect_car.get_descriptive_name)  # 注意上下两行print的区别,别漏了花括号
my_elect_car.describ_battery()
my_elect_car.fill_gas_tank()


2018 Tesla Model'S
****************这里是分隔符区分实例方法故障,送新手****************
<bound method Car.get_descriptive_name of <__main__.ElectCar object at 0x000001D67C515358>>
This ElectricCar has a 70-kWh battery
我不需要油箱! 

分离类, 父类重写

  • 当类方法的某一个属性不断被定义时,可以将这些属性和方法提取出来,单独建立一个类
# -*- coding:utf-8 -*-
class Car:
    """模拟汽车"""
    def __init__(self, make, model, year):
        """初始化描述汽车的属性"""
        self.make = make
        self.model = model
        self.year = year
        self.odometer_reading = 0  # 增加汽车里程数,并设置初始值为0
        
    def get_descriptive_name(self):
        """返回一个汽车的描述性信息"""
        full_name = str(self.year) + " " + self.make + " " + self.model
        return full_name.title()
    
    def update_odo(self, mileage):
        """
        设定里程表初始指定值
        禁止将里程表读数往回调
        """
        if mileage >= self.odometer_reading: # 构造函数中的形参默认值
            self.odometer_reading = mileage
        else:
            print("不可以偷偷修改里程数哟! ")
            
    def fill_gas_tank(self):
        """子类会重写"""
        print("我是烧油的! ")
            
    def read_odo(self):
        """打印一条关于汽车里程数的消息"""
        print(f"{self.make} " + str(self.odometer_reading) + "miles on it ")
        
    def increment_odo(self, miles):
        """将里程表的值增加指定量"""
        self.odometer_reading += miles

        
class Battery:
    """将电池从ElectCar类中独立出来重写一个类"""
    def __init__(self, battery_size=70):
        """初始化电池属性"""
        self.battery_size = battery_size
    
    def describ_battery(self):
        """对电池容量进行描述"""
        print("This ElectricCar has a " + str(self.battery_size) + "-kWh battery")
    
        
class ElectCar(Car):
    """获取Car类的属性,并定义一个新的子类电动汽车"""
    def __init__(self, make, model, year):
        super().__init__(make, model, year)  # 3.0的写法
        """super(ElectCar, self)__init__(make, model, year), 2.7的写法"""
        self.battery = Battery()  #  初始化类在形参中调用Battery类方法
   
    def fill_gas_tank(self):
        """重写父类方法"""
        print("我不需要油箱! ")
        

my_elect_car = ElectCar("tesla", "model's", 2018)
print(my_elect_car.get_descriptive_name())

my_elect_car.battery.describ_battery()  # 实例中直接调用了Battery的方法


2018 Tesla Model'S
This ElectricCar has a 70-kWh battery

多态:

  • Python天生多态, "鸭子类型"
  • Pyhon 很多语法都是支持多态的.比如 len(), sorted()。 你给len传字符串就返回字符串的长度。 传列表就返回列表长度
  • 还没有太大的印象,等后期再回顾时再做一些额外的补充
class Animal(object):
    def __init__(self, name):  # Constructor of the class
        self.name = name
 
    def talk(self):  # Abstract method, defined by convention only
        raise NotImplementedError("Subclass must implement abstract method")
 
class Cat(Animal):
    def talk(self):
        return "Neow!"
 
class Dog(Animal):
    def talk(self):
        return "Woof!...Woof!"
 
D = Dog("D1")
C = Cat("C1")
 
def Animal_talk(obj):# 一个接口.多种形态.
    print(obj.talk())
 
Animal_talk(D)
Animal_talk(C)
Woof!...Woof!
Neow!

未完待续,待补充内容如下:

  1. 元编程
  2. 属性: 私有属性, 共有属性, 成员属性
  3. 特殊方法:
__init__ : 初始化函数, 将各种属性绑定到self
__slots__: 限制实例的动态属性, 减少内存消耗, tuple类型
__eq__: 比较对象是否相等
@classmethod :会将类本身作为第一个参数传入
@staticmethod: 定义一个静态方法, 类可以不用实例化就可以调用方法
posted @ 2019-03-03 15:41  lataku~~  阅读(139)  评论(0编辑  收藏  举报