Python学习11--面向对象

一、面向过程和面向对象

面向过程:程序里面有大量的函数,每一个环节都是进行函数的调用。编程思想是按照执行时从头到尾的顺序来进行编程的
面向对象:根据需求,划分不同的对象,将对象划分成若干个类,以对象的方式来进行方法或者行为
的调用,不是以函数为单位,而是以对象为单位。
举例说明:编写一个实现请假功能的代码块,大致流程为:员工请假—领导审批—人事记录

1、以面向过程的思想编程:

定义以下函数执行,伪代码如下:

def  请假(员工,领导)
	pass
def 撤销请假流程(员工,领导)
	pass
def 审批(员工,流程)
	pass
def 记录(人事,员工)
	pass

请假(员工,领导)
撤销请假流程(员工,领导)
审批(员工,流程)
记录(人事,员工)


2、以面向对象的思想编程:

分别定义员工 、领导、人事三个类。伪代码如下:

class worker:
  def 请假(领导):
     pass

  def 撤销(领导)
     pass

class leaderdef 审批(员工):
     pass
  def 驳回(员工):
     pass
class hr:
  def  记录(员工)
     pass

w=Worker()
l=Leader()
hr=hr()
w.请假(m)
w.撤销(m)


l.审批(w)
hr.记录(w)

面向过程的缺点:
(1)只看方法,不能弄清楚方法里面具体做的事情,不清楚角色之间的关系
(2)定义方法时,程序员自己传入参数,所以会造成很多不合理的情况
(3)如果进行升级或者扩展,修改的代码太多。

3、总结:

面向过程:不是先分析是谁,先分析要怎么做,如武松打虎,就是编写函数【打(武松,老虎)】
面向对象:先分析是谁,然后再分析怎么做,如武松打虎,编写类以及类下方法【武松.打(老虎)】
面向对象的三个特征:封装、继承、多态

二、封装

信息的封装,主要为了方便调用者调用。

1. 成员的私有化

成员包括: 实例属性、实例方法、类属性、类方法、静态方法
经常对实例属性和实例方法进行封装(对成员进行私有化)
目的:只能在当前类中使用和访问,不能在类的外部直接访问。

具体的做法:如果希望一个属性或者一个方法是私有的,那么将名字 __(开头)** 注意不以两个__结尾

class computer:
    def __init__(self):
        self.cpu = "inter cpu"
        self.__memory = "128G"
    #__memory属于私有属性,可以在类的内部被使用,不能在类的外部被直接引用
    def show(self):
        print(self.cpu,self.__memory)
    def get_memory(self):
        return self.__memory
    def set_memory(self,value):
        self.__memory =value

c1 = computer()
print(c1.cpu)
c1.cpu = "AMD"
print(c1.cpu)
# print(c1.__memory) 'computer' object has no attribute '__memory'
c1.show()
print("================")
#如何在类的外部访问私有属性,在类的里面使用get(获取)和set(赋值)方法
print(c1.get_memory())
c1.set_memory("512G")
print(c1.get_memory())

输出:

inter cpu
AMD
AMD 128G
================
128G
512G

私有属性只能在类的内部进行访问,如果需要在外部访问和修改私有属性,需在类里面提供get(获取)和set(赋值)方法。

封装的优势:提高了代码的扩展性和可维护性。
需要注意的是,python中的封装是假封装,将__**名字伪装成_类名+私有成员的名字
如访问例子中的私有成员时,可以使用如下代码

print(c1._computer__memory)

同样得到输出:

512G

2. 使用property完成成员的私有化

目的:为了方便调用者调用,方法有如下两种:
(1)使用property函数
(2)使用property装饰器
a)property函数,在定义好get方法和set方法之后,将方法进行封装。
封装的时候按照顺序propery(获取,赋值,删除,注释),如果没有定义删除方法而定义了注释方法,
应该propery(获取,赋值,None,注释)

class computer:
    def __init__(self):
        self.__memory = "128G"
    def get_memory(self):
        return self.__memory
    def set_memory(self,value):
        self.__memory = value

    def del_memory(self):
        print("del方法执行")
        del self.__memory
    memory = property(get_memory,set_memory,del_memory,"computer内存")

c1 = computer()
print(c1.memory)
c1.memory = "256g"
print(c1.memory)
#del c1.memory
print(c1.memory)
help(computer.memory)
print(computer.memory.__doc__)

输出:

128G
256g
256g
Help on property:

    computer内存

computer内存

b)使用property装饰器

class Computer:
    def __init__(self):
        self.__memory = "128G"
    @property
    def memory(self):
        "computer描述"
        return self.__memory
    @memory.setter
    def memory(self,value):
        self.__memory =value
    @memory.deleter
    def memory(self):
        print("del方法得到执行")
        del self.__memory
c = Computer()
print(c.memory)
#print(c.a)
c.memory = "256G"
print(c.memory)
# del c.memory
# print(c.memory)
help(Computer.memory)
print(Computer.memory.__doc__)

输出为:

128G
256G
Help on property:

    computer描述

computer描述

三、继承

1. 继承的关系

一般与特殊的关系
【特殊类】是【一般类】的子类
【一般类】是【特殊类】的父类

例子:水果 苹果 香蕉

子类可以继承父类,当继承父类后,就继承了父类下的所有成员(属性、方法)
作用跟定义在自己的类中一样。

2. 继承的实现

a)显式继承
格式如下:

class  类名(父类):
       类体

具体实现如下所示:

class Fruit:
    def show(self):
        print("水果")
    def __str__(self):
        return "这是一个水果类"
class Apple(Fruit):
     pass
f = Fruit()
f.show()
print("f=====>",f)
a = Apple()
a.show()
print("a=====>",a)

输出:

水果
f=====> 这是一个水果类
水果
a=====> 这是一个水果类

b)隐式继承
在python中,如果没有写明()继承,就叫隐式继承,只有一种情况,继承object父类
所有的类都会直接或者间接的继承object父类

3. 继承的意义

a)为什么要有子类继承父类
当父类有一些属性和方法,允许相关的子类使用的时候,子类可以通过继承的方式直接使用
如果子类有特殊的属性和方法,可以自行定义,甚至扩展,重写。

b)通过继承,实现代码的重用性,可以将公共的部分提取(抽取)出来, 放到父类中。

c)解决实际编程问题时:通过抽取对象得到类,通过抽取类得到父类

4. 两个重要的内建函数

a)isInstance(对象,类型):判断第一个参数指定的对象是否是第二个参数的类型(父类也可以)
例如:

class Fruit:
    def show(self):
        print("水果")
    def __str__(self):
        return "这是一个水果类"
class Apple(Fruit):
     pass
f = Fruit()
a = Apple()
print(isinstance(a,Apple))
print(isinstance(a,Fruit))

输出:

True
True

b) issubclass(类型,类型):第一个参数是否是第二个参数的子类

class Fruit:
    def show(self):
        print("水果")
    def __str__(self):
        return "这是一个水果类"
class Apple(Fruit):
     pass
f = Fruit()
a = Apple()
print(issubclass(Apple,Fruit))
print(issubclass(Apple,object))

输出:

True
True

5. 成员的继承

a)类属性、类方法、静态方法、实例方法的继承
关于方法的重写
子类继承了父类,如果父类的成员未必完全适合子类,可以是用重写的方式来自行扩展方法。
规则:如果子类中重写了父类的方法,运行时会按子类的方法进行执行,如果没有重写父类的方法,运行时按照父类的执行。
重写后调用父类成员:super().父类的成员 进行访问

class Bike:
    #类属性
    brand = "凤凰"

    # 类属性
    @classmethod
    def copy_bike(cls):
        print("仿照一台自行车")

    #静态方法
    @staticmethod
    def static_method():
        print("静态方法")
	#实例方法
    def bybike(self):
        print("step1_双手扶把")
        print("step2_骑上自行车")
        print("step3_开始骑车")

class Cvbike(Bike):
    def bybike(self):
        print("step0_调整变速轮")
        super().bybike()

b1 = Bike()
c1 =Cvbike()
print(Bike.brand)
b1.bybike()
b1.copy_bike()
b1.static_method()
print("============")
print(Cvbike.brand)
c1.bybike()
c1.copy_bike()
c1.static_method()

输出:

凤凰
step1_双手扶把
step2_骑上自行车
step3_开始骑车
仿照一台自行车
静态方法
============
凤凰
step0_调整变速轮
step1_双手扶把
step2_骑上自行车
step3_开始骑车
仿照一台自行车
静态方法

由上例可知,子类继承父类时可以继承类属性、类方法、静态方法、实例方法,可以在子类中重写方法并调用父类的方法。

b)实例属性的继承
1、如果子类中没有定义__init__方法,就会执行父类中的init方法,进行属性的初始化
2、如果子类中定义了自己的__init__方法,则会按子类中的属性进行初始化
3、如果子类的init中没有继承父类的__init__,pycharm会提示继承关系是否有问题。
4、子类的init方法继承了父类的__init__,尽量将父类的init放在第一行。

class Bike:
    def __init__(self):
        self.color = "蓝色"


class Cvbike(Bike):
    def __init__(self):
        super().__init__()
        self.change = "变速器"
        self.color = "白色"

b1 = Bike()
c1 =Cvbike()
print(b1.color)
print("==========")
print(c1.color)
print(c1.change)

输出:

蓝色
==========
白色
变速器

c) 私有成员的继承
子类不建议访问父类中的私有成员,如果一定要访问可以通过 _父类名+私有成员名

class C1:
    def __p(self):
        print("父类私有方法")

class D1(C1):
    def t(self):
        pass
c = C1()
d = D1()
c._C1__p()

输出:

父类私有方法

d)多重继承
一个子类可以继承多个父类,例如正方形是特殊的矩形,正方形也是特殊的菱形,那么正方形可以同时继承矩形和菱形
对于同名方法,哪一个父类写在前面,就先继承哪一个父类的方法。
如下:

class Rectangle:
    def area(self):
        print("求矩形面积")

class Diamond:
    def area(self):
        print("求菱形面积")

class Square(Rectangle,Diamond):
    def s(self):
        self.area()
s = Square()
s.s()

输出:

求矩形面积

对于多继承而言采用MRO原则: 方法调用顺序
如果是多继承,子类到每一个父类都是一条分支,按照继承的顺序,沿着每一条分支,从子类
到父类进行搜索,一直找到object类为止(深度优先)

如果非想继承指定父类方法
有两种方式:1、将指定的父类放在第一个位置
2、第二种,指定父类.方法
如下:

class Rectangle:
    def area(self):
        print("求矩形面积")

class Diamond:
    def area(self):
        print("求菱形面积")

class Square(Rectangle,Diamond):
    def s(self):
       Diamond.area(self)
s = Square()
s.s()

输出:

求菱形面积

三、多态

多态是指程序运行或者编译时期的多种形态
Python动态强类型语言,鸭子类型语言,多态上体现的不明显

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 魔术方法是Python中的特殊方法,它们以双下划线开头和结尾,例如__init__、__str__、__add__等。这些方法可以在类的实例化、运算符重载、属性访问等方面提供特殊的行为。 __init__方法是一个特殊的构造函数,用于初始化类的实例。__str__方法用于返回对象的字符串表示形式,可以通过print函数输出。__add__方法用于重载加法运算符,可以实现自定义的加法操作。其他常用的魔术方法还包括__eq__、__lt__、__gt__等,用于比较运算符的重载。 学习魔术方法可以让我们更好地理解Python面向对象编程的特性,提高代码的可读性和可维护性。 ### 回答2: 魔术方法是Python中最有趣且也是最强大的概念之一。魔术方法(也称为特殊方法或双下划线方法)是一些特殊的方法,它们以双下划线(__)开头和结尾,并具有特定的名称。 这些特殊方法可以为我们提供许多有用的功能,例如重载操作符,处理类的属性,实现自定义迭代器,使用描述符等。 下面是一些常见的魔术方法: __init__:这是最常见的魔术方法。当创建一个实例时,它会被自动调用。它用于初始化对象的属性。 __str__:当你想要将一个对象转换成字符串时,这个方法会被调用。如果你不指定__str__方法,Python默认会使用对象的类名和内存地址来表示对象。 __repr__:这个方法和__str__方法类似,也是用于将对象转换成字符串。但是__repr__方法在调试时有很大的作用,因为它返回的字符串可以用来唯一地标识对象。 __len__:这个方法可以返回对象的长度。例如,如果你想获取一个字符串的长度,你可以使用len("hello"),在底层,它实际上是调用了字符串对象的__len__方法。 __getattr__和__setattr__:这些方法允许你动态地获取和设置对象的属性。当你访问一个不存在的属性时,__getattr__方法会被调用。当你设置一个属性时,__setattr__方法会被调用。 __call__:这个方法允许你将对象作为函数调用。当你调用一个对象时,Python实际上是在调用对象的__call__方法。 除了上面列举的方法,还有许多其他的魔术方法,例如__cmp__,__hash__,__iter__等等。学习这些魔术方法将使你能够更好地理解Python面向对象编程模型。 总之,学习和理解魔术方法是Python面向对象编程中的一个关键概念,因为它们可以帮助你实现更加灵活和强大的代码。如果你想成为一名Python高手,那么深入学习魔术方法是不可避免的。 ### 回答3: Python中的“魔术方法”指的是每个类中定义的特殊方法,它们以双下划线(__)开头和结尾,并且有着特定的用途。通过使用这些魔法方法,我们可以自定义类的行为,并为程序提供更高级别的功能。 以下是Python中常用的一些魔术方法: 1. __init__:这是最常用的魔术方法之一,它用于初始化一个类的对象,以及定义类的属性和方法。 2. __str__:此方法用于返回对象的字符串表示形式,类似于Java中的toString()方法。 3. __repr__:与__str__类似,但是返回的是对象的“官方”字符串表示形式,通常用于调试和开发。 4. __getattr__:当试图访问一个不存在的属性时,此方法被调用。 5. __setattr__:当尝试设置类的属性时,此方法被调用。 6. __delattr__:当尝试删除类的属性时,此方法被调用。 7. __call__:将对象作为函数调用时,此方法被调用。 8. __len__:返回对象的长度。 9. __getitem__:允许通过索引访问对象的元素。 10. __setitem__:允许通过索引设置对象的元素。 11. __delitem__:允许通过索引删除对象的元素。 通过了解和使用这些魔术方法,我们可以编写出更高效、更灵活、更具可读性的Python代码,并且实现类似于内置类型一样的功能。例如,我们可以实现一个自定义列表,类似于Python的list类型,然后使用上述魔术方法来访问、设置和删除元素。同时,我们还可以自定义变量和函数的行为,使我们的Python代码变得更具有表现力和弹性。 总之,了解和掌握Python的魔术方法是Python编程中必不可少的一部分,对于理解和编写实际应用程序非常有价值。在实践中,我们可以根据实际情况选择恰当的魔术方法,从而创建更灵活、更高效的Python类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值