Python入门到精通(八):面向对象

一、面向对象简介

面向对象(OOP)是一种对现实世界理解和抽象的方法,对象的含义是指在现实生活中能够看得见摸得着的具体事物,一句比较经典的描述是一切皆对象,Python 是一门面向对象的语言,面向对象编程简单来说就是一种封装代码的方式。

1、面向对象相关概念

  • 类:描述具有相同属性和方法的集合,简单来说就是一个模板,通它来创建对象。

  • 对象:类的实例。

  • 方法:类中定义的函数。

  • 类变量:定义在类中且在函数之外的变量,在所有实例化对象中公用。

  • 局部变量:方法中定义的变量,只作用于当前实例。

2、面向对象三大特性

  • 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,提高复用性和安全性。

  • 继承:一个类继承一个基类便可拥有基类的属性和方法,可提高代码的复用性。

  • 多态:父类定义的引用变量可以指向子类的实例对象,提高了程序的拓展性。

二 、类属性和类方法

2.1类属性

  • 定义在类里面,方法外面,定义的时候不需要self关键字,语法类似于定义普通变量

  • 不需要把类实例化为对象,直接通过类名.属性名 使用 

2.2类方法

  • 类方法不需要把类实例化为对象,通过类名.类方法名调用

  • 用@classmethod来修饰的方法,就是类方法

  • 类方法的参数为 cls,在类方法内部通过 cls.类属性 或者 cls.类方法 来访问同一个类中的其他类属性和类方法;

  • 类方法不需要实例化就可以调用,类方法只能访问同一个类中的类属性和类方法。

  • 类方法的一个参数是cls(不是self)

  • 在类方法内部如果使用类属性, cls.类属性名

  • 类方法内部不能使用普通属性,也不能调用普通方法

    • 因为类方法不需要对象的,但普通方法和普通属性一定需要通过对象调用

三、面向对象简单实现

定义类的格式

2.1 类

# 定义一个类
class StuInfo():
    # 定义属性
    age = "10"
    addr = "hebei"
    name = "tom"

    # 定义方法
    def showInfo(self):  # 类中的方法的第一个形参必须是self
        #print("%s的年龄是%s, 地址在%s"%(name, age, addr))     # 此时这三个变量是去全局段找
        print("%s的年龄是%s, 地址在%s"%(self.name, self.age, self.addr))   # 加上self是去类内部找变量

# 进行实例化,将实例化结果赋值给stu1变量
# stu1是一个对象
stu1 = StuInfo()

# 显示类属性
print(stu1.age)
print(stu1.addr)
print(stu1.name)

# 调用类方法
stu1.showInfo()

构造方法 __init__() 会在类实例化时自动调用。无论构造方法还是其他方法都需要将 self 作为第一个参数,它代表类的实例。

类创建好后,我们可以直接通过类名访问属性,格式为:类名.属性名,比如我们访问 Cat 类的 color 属性,如下所示:

# 显示类属性
print(stu1.age)
print(stu1.addr)
print(stu1.name)

 上面 StuInfo 类中定义的属性和方法都是公开的,除此之外我们还可以定义私有属性和方法,声明方式为:在属性名或方法名前加两条下划线,示例如下所示:

类的私有属性和私有方法

  • 私有属性就是对象不希望公开的属性 ;

  • 私有⽅法就是对象不希望公开的⽅法 。

class woman:
    def __init__(self):
        self.name = "玛丽"
        self.__weight = 200  # __weigth是一个私有属性

    def __eat(self):         # __eat方法为私有方法
        print("吃的很多")

w = woman()
print(w.name)
# print(w.__weight)  不能在类的外部访问类的私有属性
# w.__eat()   不能在类的外部调用私有方法
  • 在定义属性或⽅法时,在属性名或者⽅法名前 增加两个下划线,定义的就是私有属性或方法。

  • 对于私有属性和私有方法,只能在类的内部访问,类的外部无法访问。

  • 就是把类的属性和方法封装到类的内部,只能在内部使用,不能在类的外部使用

  • 把属性和方法名前面加两个下划线__,这个属性和方法就成为了类的私有属性和方法

需要强调一点是:外部不能访问私有属性和调用私有方法,自然 Cat.__cid 是会报错的。 

2.2 对象

创建对象也称类的实例化,比如我们通过 MyClass类创建对象,如下所示:

# 定义一个类
class MyClass():
    """
        这是我的测试类
        你听懂了吗
    """
    name = "python开发"
    def __init__(self):
        self.height = "175"
    def show(self):
        age = "20"
        print("%s 的年龄是 %s, 身高是%s"%(self.name, age, self.height))
# 创建对象 也叫类的实例化
str = MyClass()
# 使用方法
str.show()

 创建好对象后,我们就可以使用它访问属性和调用方法了。

四、继承

继承的概念

  • ⼦类拥有⽗类的所有⽅法和属性。

继承的语法

class 类名(⽗类名): 
	pass
  • ⼦类继承⾃⽗类,可以直接享受⽗类中已经封装好的⽅法,不需要再次开发

  • ⼦类中应该根据职责,封装⼦类特有的属性和⽅法。

专业术语

  • 子类---派生类

    • dog是animal的子类

    • dog是animal的派生类

  • 父类---基类

    • animal是dog的父类

    • animal是dog基类

  • 继承---派生

    • dog类继承自animal

    • dog类派生自animal

  • 一个父类可以有多个子类继承,每个子类可以有自己特有的方法和属性 

object 类

在 Python 3 中定义类时,如果没有指定⽗类,会默认使⽤ object 作为该类的基类 —— Python 3 中定义的类都是新式类 。

在 Python 2 中定义类时,如果没有指定⽗类,则不会以 object 作为基类 。新式类和经典类在多继承时 —— 会影响到⽅法的搜索顺序 。

为了保证编写的代码能够同时在 Python 2 和 Python 3 运⾏! 今后在定义类时,如果没有父类,建议统一继承自 object。

五、方法的重写

当⽗类的⽅法实现不能满⾜⼦类需求时,可以对⽅法进⾏ 重写(override)。

方法重写有两种方式

  • 覆盖父类方法

  • 扩展父类方法

覆盖父类方法

如果在开发中,⽗类的⽅法实现和⼦类的⽅法实现,完全不同 ,就可以使 ⽤覆盖的⽅式,在⼦类中重新编写⽗类的⽅法实现 。

具体的实现⽅式,就相当于在⼦类中定义了⼀个 和⽗类同名的⽅法并且实现 。

重写之后,在运⾏时,只会调⽤⼦类中重写的⽅法,⽽不再会调⽤父类封装 的方法

  • 子类中出现和父类相同的方法,那么在子类中相同方法会把父类的方法覆盖

class animal:
    def sleep(self):
        print("睡")

    def eat(self):
        print("吃")

class dog(animal):
    def eat(self):  # 出现和父类同名方法,在子类dog中,就没有父类的eat方法了
        print("吃肉")

d = dog()
d.sleep()
d.eat()  # 由于覆盖了父类的eat方法,,所以这里调用的是dog类的eat方法

扩展父类方法

  • 如果父类的方法不能完全满足子类需求, 子类可以在父类方法基础上增加功能

语法

 1.在子类中实现和父类同名方法
2.在子类的同名方法中用super().父类同名方法 来调用父类的方法

class animal:
    def sleep(self):
        print("睡")

    def eat(self):
        print("吃")

class dog(animal):
    def sleep(self):
        super().sleep() # 在子类方法中调用父类的sleep方法
        print("睡得更多")

d = dog()
d.sleep() # 扩展了父类的sleep,所以既执行了父类的sleep,又增加了功能

⽗类的私有属性和私有⽅法

  • 1.⼦类对象不能在⾃⼰的⽅法内部,直接访问⽗类的私有属性或私有⽅法;

  • 2.⼦类对象 可以通过⽗类的公有⽅法间接访问到私有属性或私有⽅法; 私有属性、⽅法是对象的隐私,不对外公开,外界以及⼦类都不能直接访问私有属性、⽅法通常⽤于做⼀些内部的事情 。

父类的私有成员不会继承给子类

  • 父类中所有的私有方法和私有属性归父类特有,子类不能继承

class animal:
    def sleep(self):
        print("睡")

    def __eat(self):  # 私有成员不会被子类继承
        print("吃")

class dog(animal): # 在dog类里面,没有__eat方法
    pass

d = dog()
d.sleep()
# d.__eat()  # 这里的代码会出错

  六、多态

  • 不同的子类,调用相同的父类方法,产生不同的结果

  • 多态的前提,不同的子类来自相同的一个父类,子类会覆盖父类的方法

七、静态方法

如果需要在类中封装⼀个⽅法,这个⽅法既不需要访问实例属性 或者调⽤实例⽅法也不需要访问类属性或者调⽤类⽅法, 这个时候,可以把这个⽅法封装成⼀个静态⽅法。

  • 在类中通过@staticmethod修饰的方法

  • 静态方法不需要实例化为对象,通过类名.静态方法名 调用

  • 静态方法不能访问类中的其他成员,静态方法就是一个独立与类存在的函数

格式:

class dog:
    @staticmethod
    def help():
        print("这是一个静态方法")

dog.help()

静态方式使用场景

  • 当代码量特别大的时候,函数也会特别多,为了避免函数的重名,可以把同名函数放到不同的类里面,做为静态方法

  • 避免由于函数重名带来错误

以上就是面向对象的所有内容,觉得有用的朋友可以点点收藏,还会更新更多有用的知识。

猜你喜欢

转载自blog.csdn.net/weixin_67281781/article/details/123711607
今日推荐