python面向对象(三)

前言

  1. 在python中一切皆为对象,变量是对象,函数是对象,类也是对象。例如:数字6、字符串"hello"、列表[1,2,3]等等都是对象。对象是分配好的一块内存空间,具有三要素:标识(identity, id)、类型(type)、值(value)。
  • 标识: 唯一标识一个对象,通常对应对象在计算机内存中的地址。可使用内置函数id(obj)返回对象的内存地址。
  • 类型:表示对象存储的数据类型,使用内置函数type(obj)返回对象所属类型。
  • 值:表示对象存储的数据信息,也就是对象的值。使用内置函数print(obj)可以直接打印值。
  1. 变量:python中变量总是存放对象的引用,变量和对象之间的关系为引用(或者说变量是对象的引用)。不需要提前声明变量的数据类型,只需要在用的时候,给变量赋值即可。例如:a = [1,2,3], a = 6 ,[1,2,3]是列表对象,6是数字对象,刚开始变量a是该列表对象的一个引用,后来变量a变成了该数字对象的一个引用。赋值操作=就是把一个变量和一个对象绑定在一起,就像给对象添加标签。变量本身没有数据类型,但变量指向的对象具有数据类型。当没有变量指向对象时,这个对象便进入了垃圾收集过程。(Python 中的变量与 C/C++ 中的变量有着很大的不同)。顺便说一下,python的基本数据类型可分为两大类:可变数据类型和不可变数据类型。其中,列表、元组和字典属于"可变对象",数字、字符串和元组属于"不可变对象"。
  2. ==用来比较对象的值(value)是否相同。is用来比较对象的地址(id)是否相同,即是否为同一个引用。
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)  # 结果: True
print(id(a))  # 结果: 2247727763080
print(id(b))  # 结果: 2247727861320
print(a is b)  # 结果: False

a = 12
b = 12
print(a == b)  # 结果: True
print(a is b)  # 结果: True,表示此时a和b是同一个引用(地址),即指向同一个对象

具体可参考以下文章:
python 引用和对象理解
Python彻底搞懂:变量、对象、赋值、引用、拷贝
彻底理解Python中对象、对象与变量引用的关系

  1. 之前学习的字符串(str)、整数(int)、列表(list)等都是类的对象,我们可根据类来创建这些对象。
my_int = int(1)
my_str = str("hello")
my_list = list([1, 2, 3])
print(type(my_int))  # 结果: <class 'int'>
print(type(my_str))  # 结果: <class 'str'>
print(type(my_list))  # 结果: <class 'list'>

str1 = "hello" # python在内部省略了初始化方法 

1.1 类的成员

  1. 类的定义
"""
类的定义语法:
class 类名称:
	类的属性
	类的行为

创建类对象的语法:
对象 = 类名称()
"""
  • class是关键字,表示要定义类了。
  • 类的属性:即定义在类中的变量(成员变量)
  • 类的行为:即定义在类中的函数(成员方法)
  1. 成员方法的定义
"""
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
def 方法名(self, 形参1, 形参2, ..., 形参N):
	方法体
"""
  • 参数列表中的self表示类对象自身的意思,必须填写。但是self这个形参可以修改为a,b,c,…等等,只是约定俗称的定义为self。当我们通过对象.方法名()的方式去调用方法时,python会将该对象传递给self这个参数,换而言之,self就是当前调用这个方法的对象。
  • 在方法内部,想要访问类的成员变量,必须使用self。
class Student:
	name = None
	def say_hi(self):
		print("Hi,大家好")
	def say_hello(self, msg):
		print(f"Hello {msg}")

stu = Student()
stu.say_hi()  # 会将对象stu传递给self
stu.say_hello("张三")
  1. 构造方法的定义
    构造方法(初始化方法)是__init__()方法,在创建类对象(构造类)的时候,会自动执行,并将参数自动传递给__init__()方法使用。
class Student:
"""
在创建对象的时候,即Student("张三", 21, "男"),会产生一块内存空间。然后自动调用(执行)__init__()方法,
并将创建的那块内存空间传递给参数self(即self是该对象的引用),将"张三"、21和"男"分别传递给形参name、age和gender。
最后通过self.name、self.age和self.gender在对象中创建成员变量name、age和gender,并将"张三"、21和"男"分别赋值给它。
只要你实例化对象(创建对象)就一定会自动调用__init__()方法。
"""
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def print_msg(self):
        print(f"name:{self.name}, age:{self.age}, gender:{self.gender}")


stu = Student("张三", 21, "男")
stu.print_msg()
"""
输出:
name:张三, age:21, gender:男
"""
  1. 魔术方法的定义
    python的内置方法具有特殊的功能,这些内置方法我们也称之为魔术方法__init__()方法是python内置方法之一。下面介绍几个常见的内置方法:

内置方法

class Student:

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __str__(self):
        return f"Student类对象, name={self.name}, age={self.age}, gender={self.gender}"


stu = Student("张三", 21, "男")
print(stu)
"""
如果不加 __str__()方法
print(stu)会输出:<__main__.Student object at 0x000001525F5B1C08>
加上 __str__()方法
print(stu)会输出:Student类对象, name=张三, age=21, gender=男

(__str__"类似于Java中的toString()方法。)
"""

1.2 面向对象的三大特性

面向对象的三大特性:封装、继承、多态。

  1. 封装:将现实世界事物在类中描述为属性和方法,即为封装。私有成员无法被外部的类对象调用,但是可以被类内部的其它成员使用。

私有成员

  1. 继承:就是一个类继承另外一个类的成员变量和成员方法。
  • 单继承:class 类名(父类名): 类内容体

单继承

  • 多继承:class 类名(父类1, 父类2, ..., 父类N)

多继承
注意:多继承的优先级为从左到右,即父类1的优先级最高。
关键字pass是占位语句,用来保证函数(方法)或者类定义的完整性,表示无内容,空的意思。

  • 继承的复写(重写)

重写

  • 调用父类同名成员

调用父类成员

  1. 多态:指的是多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。

多态
多态作用

  • 抽象类(接口):包含抽象方法的类被称为抽象类。抽象方法指的是没有具体实现的方法(方法体内部使用关键字pass)

抽象类

  1. super().__init__()的使用
  • 一个子类继承一个父类(超类)时,子类将自动获得父类的所有属性(成员变量)和行为(成员方法),同时子类还可以定义自己特有的属性和行为。子类可以继承父类中的所有成员,但是没有权限使用父类的私有属性和私有方法。super()是一个特殊函数,用于调用父类的成员,可以将python中父类和子类关联起来。
  • 方法解析顺序(Method Resolution Order, mro),mro就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。我们可以通过__mro__属性来查看类的mro列表,即:类名.__mro__
  • __init__()构造方法的继承顺序:

(1)当子类中没有__init__()方法,且不使用super().__init__()来初始化父类的属性,将会自动调用父类的__init__()方法。

class Car:
    """"这个一个名为汽车的父类"""
    def __init__(self):
        print("这个一个名为汽车的父类")
        self.title = "遥遥领先"
class ElectricCar(Car):
    """这是一个电动车的子类"""
    print("这是一个电动车的子类")
my_tesla = ElectricCar()
print(my_tesla.title)
"""
输出:
这是一个电动车的子类
这个一个名为汽车的父类
遥遥领先
"""

(2)子类有__init__()方法,但不使用super().__init__()方法来初始化父类的属性。

class Car:
    """"这个一个名为汽车的父类"""
    def __init__(self):
        print("这个一个名为汽车的父类")
class ElectricCar(Car):
    """这是一个电动车的子类"""
    def __init__(self):
        print("这是一个电动车的子类")
my_tesla = ElectricCar()
"""
输出:
这是一个电动车的子类
# 此时不会调用父类的__init__()方法
"""

(3)在子类的__init__()方法中使用super().__init__()方法来初始化父类的属性。

class Car:
    """"这个一个名为汽车的父类"""

    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        self.title = "遥遥领先"
        print("这个一个名为汽车的父类")

    def get_car_description(self):
        print(f"品牌:{self.make},型号:{self.model},生产年份:{self.year}")


class ElectricCar(Car):
    """这是一个电动车的子类"""

    def __init__(self, make, model, year, battery_size):
        # 初始化父类的属性(成员变量),调用父类的__init__()方法,让子类ElectricCar对象拥有父类的所有属性
        # 在python2.7中,继承的语法变为super(子类名, self).__init__(make, model, year)。
        # 在Python2中需要写完整,而Python3中可以简写为super()
        super().__init__(make, model, year)
        # super(ElectricCar, self).__init__(make, model, year)  # python2中的语法
        self.battery_size = battery_size
        print("这是一个电动车的子类")

    def get_car_description(self):
        print(f"品牌:{self.make},型号:{self.model},生产年份:{self.year},电池容量:{self.battery_size}")


my_tesla = ElectricCar("tesla", "model s", 2016, 70)
my_tesla.get_car_description()
print(f"头衔:{my_tesla.title}")
print(ElectricCar.__mro__)  # 查看继承顺序
"""
输出:
这个一个名为汽车的父类
这是一个电动车的子类
品牌:tesla,型号:model s,生产年份:2016,电池容量:70
头衔:遥遥领先
(<class '__main__.ElectricCar'>, <class '__main__.Car'>, <class 'object'>)

#解析"super(ElectricCar, self).__init__(make, model, year)"
 首先找到子类(ElectricCar)的父类(Car);
 然后将子类的对象self转换为父类的对象,也就是将子类对象self作为实参传递给父类中__init__方法的形参self;
 最后父类的对象self就可以调用自己的属性和方法。子类进而继承父类的所有属性
"""

参考文章如下:
浅谈Python的super().__ init__()
Python中super().init()用法
解惑(一) ----- super(XXX, self).init()到底是代表什么含义

1.3 注解

  1. python在3.5版本的时候引入了类型注解,类型注解是指在代码中涉及到数据交互的地方,提供数据类型的注解(显式的说明)。类型注解的主要功能:帮助第三方IDE工具(PyCharm)对代码进行类型推断,协助做代码提示;帮助开发者自身对变量进行类型注释。类型注解支持:变量的类型注解;函数(方法)形参列表和返回值的类型注解。总而言之,加上注解之后,我们可以直观的看出变量、函数(方法)参数列表和返回值到底是个什么东西(什么类型)。
  2. 变量类型注解
  • 为变量设置类型注解,语法:变量: 类型
# 1.基础数据类型注解
num1: int = 10
num2: float = 3.1415926
num3: bool = True
num4: str = "hello"

# 2.基础容器类型注解
my_list: list = [1, 2, 3, 4, 5, 6]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {1: "a", 2: "b", 3: "c"}
my_str: str = "hello"

# 3. 容器类型详细注解
from typing import List, Tuple, Set, Dict

my_list1: List[int] = [1, 2, 3, 4, 5, 6]
my_tuple1: Tuple[int, str, bool] = (1, "hi", True)
my_set1: Set[int] = {1, 2, 3}
my_dict1: Dict[int, str] = {1: "a", 2: "b", 3: "c"}
# (1)元组类型设置类型详细注解,需要将每一个元素都标记出来
# (2)字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value

# 4.类对象类型注解
class Student:
    pass
stu: Student = Student()
  • 除了使用变量: 类型这种注解语法外,还可以在注释中进行类型注解,语法:# type: 类型
num1 = 10  # type: int
num2 = 3.1415926  # type: float
num3 = True  # type: bool
num4 = "hello"  # type: str
  • num1 = 2 num2 = 3.14 list1 = [1,2,3]num1、num2和list1就算不写注解,也明确知晓变量num1是整型,变量num2时浮点型,变量list1是列表类型,那么此时无需注解。一般,无法直接看出变量类型时会添加变量的类型注解,如下所示。
import random
import json

num1: int = random.randint(1, 10)
data: dict = {"0": "a", "1": "b"}
data_str: str = json.dumps(data)
data_dict: dict = json.loads(data_str)

注意:类型注解仅仅是提示性的,不是决定性的,就算你类型注解错误也不会报错。像下面的代码就不会报错。

num1: int = "hello"
num2: str = 22
  1. 函数(方法)注解
  • 给函数(方法)形参类型进行注解,定义语法如下:
""""
def 函数方法名字(形参名1: 类型, 形参名2: 类型, ...):
    pass
"""
def add(x: int, y: int):
    return x+y

def func(data: list):
    pass
  • 给函数(方法)返回值进行注解,定义语法如下:
""""
def 函数方法名字(形参名1: 类型, 形参名2: 类型, ...) -> 返回值类型:
    pass
"""
def add(x: int, y: int) -> int:
    return x+y

def func(data: list) -> list:
    pass
  1. Union联合类型注解定义语法如下:
""""
Union[数据类型, ..., 数据类型]
"""
# 变量Union联合类型注解
from typing import Union, List, Dict
my_list: List[Union[int, str]] = [1, 2, "hello"]
my_dict: Dict[str, Union[str, int]] = {"name": "Jack", "age": 16}
# 函数(方法)形参和返回值Union联合类型注解
def func(data: Union[int, str]) -> Union[int, str]:
    pass
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值