Python面向对象oop编程(二)

简介: Python面向对象oop编程(二)

Hello,大家好,我是你们的老朋友景天,上一章我们聊到了python的面相对象编程的语法,以及一些面相对象的基本操作,今天我们继续深入探讨下面向对象的其他一些常用方法和规范

1.如何在类外访问私有成员

class Plane():
    # 公有成员
    captian = "赵沈阳"
    
    # 私有成员
    __air_sister = "3名空姐"
    
    # 公有绑定方法
    def fly(self):
        print("飞机要非要平流层,才能减少震动",self.__air_sister)
        
    # 私有绑定方法
    def __age(self):
        print("空姐年龄保密")
        
    # 公有无参方法
    def fly2():
        print("航天飞机飞到天空层,翱翔太空")
    
    # 私有无参方法
    def __earn():
        print("机长的收入保密")
        
    def pub_get1(self):
        print(self.__air_sister)
        self.__age()
        
    def pub_get2():
        print(Plane.__air_sister)
        Plane.__earn()

#实例化对象
obj = Plane()

方法一.访问私有成员 (不推荐) 使用改名方法,_类名+私有属性名

#python私有化,其实是: 采取了改名策略 =>  _类名 + __air_sister
#print(obj.__air_sister)
print(obj._Plane__air_sister)
print(Plane.__dict__)

{'__module__': '__main__', 'captian': '赵沈阳', 
'_Plane__air_sister': '3名空姐', 
'fly': <function Plane.fly at 0x7f2774616158>, '_Plane__age': <function Plane.__age at 0x7f27746161e0>, 'fly2': <function Plane.fly2 at 0x7f2774616268>, '_Plane__earn': <function Plane.__earn at 0x7f27746162f0>, '__dict__': <attribute '__dict__' of 'Plane' objects>, '__weakref__': <attribute '__weakref__' of 'Plane' objects>, '__doc__': None}


方法二.访问私有成员 (使用类中的公有方法,间接访问私有成员,包括调用私有属性和私有方法) (推荐)

obj = Plane()
obj.pub_get1()
Plane.pub_get2()

2.使用类对象删除相应的成员

1.对象可以访问类中的公有成员,但是无权修改或者删除该类中的成员

2.对象在访问成员时,优先访问该对象自己的成员,如果没有在访问类的,类如果也没有直接报错;

使用对象删除类的属性,方法,报错

#删除对象成员属性,但可以删除对象自己添加,修改的属性,方法

obj.captian = "赵世超"
del obj.captian
print(obj.captian)


#删除对象成员方法

obj.basketball = lambda : print("我的私人飞机可以在天上打篮球")
print(obj.__dict__)
obj.basketball()
del obj.basketball
print(obj.__dict__)
#obj.basketball() error

#删除类中成员属性 要通过类来删除

del Plane.captian
print(Plane.__dict__)
#Plane.captian
#print(obj.captian) error

#删除类中成员方法,删除类成员方法 不能加括号

del Plane.fly2
#Plane.fly2() error

#注意: 对象无法调无参方法!! 返回来,类可以调用对象的绑定方法么? 可以!!

Plane.fly(obj)

#类调用有参方法,要把类对象传进去

要删除私有的属性,方法。要在类内里面删除

3.构造方法

(1)init 构造方法 也就是初始化方法

所有编程语言都有构造方法

触发时机:实例化对象,初始化的时候触发
功能:为对象添加成员
参数:参数不固定,至少一个self参数
返回值:无

一般添加成员方法都是在类外,构造方法可以在创建对象的同时给对象创建成员

(2) 基本语法,至少加一个参数,本对象

class MyClass():
    def __init__(self):
        print("构造方法被触发 ... ")
        self.color = "屎黄色"
        
#实例化对象
obj = MyClass()
print(obj.__dict__)
print(obj.color)

如果定义了构造方法,则实例化对象的时候,该方法就会被调用。执行该方法的代码,可以为对象添加成员属性。只是给对象添加成员,并没有给类添加成员

只要创建对象,构造方法就被自动调用。 不是手动调用的

可以看到test对象被自动添加了color成员,并且__init__方法里面的代码也被自动执行

现在构造函数是把所有创建的对象都添加了color:蓝色 这个属性,并不是我们想要的结果。

此时就需要让构造函数带多个参数。创建对象时,可以带上参数,这样每个对象 都可以按传参不同而成员不同

(3) 带有多个参数的构造方法

class MyClass():
    def __init__(self,color):
        self.color = color

# 实例化对象
obj1 = MyClass("狗屎绿")
print(obj1.color)
obj2 = MyClass("粉嫩红")
print(obj2.color)

设置成员属性时,self.设置的成员属性名 = 传参传进来的值

这样就给对象添加了成员

这样,针对不同对象,就可以通过传参赋予不同的属性值

(3)类可以是一个,对象可以是多个,创造的对象彼此是独立的,可以给构造函数带多个参数,分别赋予不同的值;

class Children():
    def __init__(self,name,skin):
        self.name = name
        self.skin = skin
    
    def cry(self):
        print("小孩一下生久哇哇哇的哭")
    
    def la(self):
        print("小孩一下生久拉粑粑")
        
    def __eat(self):
        print("小孩一下生就要吃奶奶..")
    
        #这种成员方法,通过self.参数名 调用对象属性,创建对象的时候可通过类传参,对象调用的时候,通过对象传参,不用手动传参
    def info(self):
        print("小孩的名字:{},小孩的肤色{}".format(self.name,self.skin))
    
  #这种成员方法,直接调用参数名 对象调用该成员方法的时候,需要手动传参    。可以覆盖构造函数在创建对象时的值
    def info2(self,name,skin):
        print("小孩的名字:{},小孩的肤色{}".format(name,skin))

#实例化对象

afanda = Children("阿凡达","深蓝色")
afanda.cry()
afanda.info()

haoke = Children("绿巨人","绿色的")
haoke.la()
haoke.info()

wangbaoqiang = Children("王宝强","亮绿色")
wangbaoqiang.info()
# wangbaoqiang.__eat() error
wangbaoqiang.info2("张保张","黄色")

构造函数除了self外有几个参数,创建对象的时候,就必须带几个参数,不能少也不能多。否则创建对象失败

不能少参数

也不能多

成员方法带参数时,调用成员方法应该带参数

当成员方法里面是通过self.属性名 时,是通过对象来传参,调用函数时,传的参不会传进去

成员方法

调用:

当成员方法直接通过变量名来调用,调用时传参,会把创建对象时的参数覆盖


#这种成员方法,通过变量名调用参数。此时的参数是成员方法的形参,不是类或对象的成员属性

对象调用的时候,需要手动传参,会把创建对象时的参数覆盖。 但是这样调用比较麻烦,应该让对象来操作一切

4.继承

一个类除了自身所拥有的属性方法之外,还获取了另外一个类的成员属性和方法 是一种继承关系

被继承的类叫做父类(基类,超类),继承的类叫做子类(衍生类)

在python中所有类都继承object这个父类

继承: (1) 单继承 (2) 多继承

子类继承父类所有的属性和方法

节省了代码量

不由任意内置类型派生的类,称之为经典类

class 类名:

代码

新式类:

class 类名(object):

代码

Python面向对象的继承指的是多个类之间的从属关系,即子类默认继承父类所有的属性和方法

如果一个类不去写继承哪个类,默认继承的是object, object类是顶级类或基类。其他子类叫派生类

1.单继承

(1) 子父继承之后,子类可以调用父类的公有成员

class Human(object):
    eye = "黑色的"
    
    def jump(self):
        print("古代人类都能上树")
    
    def beat_animal(self):
        print("古代人类都会打猎")

    def __makefire(self):
        print("古代人类会生火")
        

class Man(Human):
    pass
    
obj = Man()
obj.jump()

(2) 子父继承之后,子类不能调用父类的私有成员

class Woman(Human):
    def pub_func(self):
        self.__makefire()
    
obj2 = Woman()
# obj2.__makefire()  不行
# obj2.pub_func()    不行

(3) 子父继承之后,子类可以重写父类的同名公有方法和属性

class Children(Human):
    def beat_animal(self):
        print("小孩天生只会打豆豆,不会打猎")
        
obj3 = Children()
obj3.beat_animal()

2.多继承

多继承就是一个类同时继承了多个父类

当一个类继承多个父类的时候,默认使用第一个父类的同名属性和方法

(1) 基本语法

class Father():
    property = "风流倜傥,才华横溢,玉树临风,才高八斗,学富五车,英姿洒窗"
    def f_hobby(self):
        print("吃喝嫖赌抽,坑蒙拐骗偷,抽烟喝酒烫头")
    
class Mother():
    property = "倾国倾城,貌美如花,沉鱼落雁,闭月羞花,婀娜多姿,前凸后翘"
    def m_hobby(self):
        print("蹦野迪,社会摇,打麻将,网红勾引小鲜肉")
        
class Daughter(Father,Mother):
    pass
    
obj = Daughter()
print(obj.property)
obj.m_hobby()

#当一个类继承多个父类的时候,默认使用第一个父类的同名属性和方法。按继承括号里面的先后顺序,谁在前先调用谁的

(2) 多继承的成员调用

class Father():
    property = "风流倜傥,才华横溢,玉树临风,才高八斗,学富五车,英姿洒窗"
    def f_hobby():
        print("吃喝嫖赌抽,坑蒙拐骗偷,抽烟喝酒烫头")
    
class Mother():
    property = "倾国倾城,貌美如花,沉鱼落雁,闭月羞花,婀娜多姿,前凸后翘"
    def m_hobby(self):
        print(self.property)
        print("蹦野迪,社会摇,打麻将,网红勾引小鲜肉")




super()调用父类方法:

语法一:super(当前类名, self).函数()

语法二:super().函数()

(1)super本身是一个类 super()是一个对象 传子类对象  用于调用父类的绑定方法
(2)super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self)
(3)super用途: 解决复杂的多继承调用顺序    
使用super()可以自动查找父类。调用的顺序遵循类.mro()方法返回的的列表顺序。比较适合单继承


class Son(Father,Mother):
    property = "打游戏,吃小零食"
    
    def m_hobby(self):
        print("son中m_hobby方法")
    
    
    # 用类调用成员
    def skill1(self):
        Father.f_hobby()
        print(Mother.property)
        
    # 用对象调用成员
    """self按照顺序找: 对象本身 => 类 => 父类 对应的成员 """
    def skill2(self):
        print(self.property)
        self.m_hobby()
        
    # 用super调用成员
    """super()只调用父类的相关成员,顺带传递对象参数"""
    def skill3(self):
        print(super())
        print(super().property)
        super().m_hobby()
        

obj2 = Son()
# obj2.skill1()

通过类调用指定类下的成员属性,类名.属性名

obj2.property = "喜欢看lol,dnf,wow,跑跑卡丁车,ddo,霸王大陆,澄海3c"
# obj2.skill2()

obj2.skill3()

即便在子类中存在同名方法或属性,也不调用。只调用父类方法和属性

super() 只应用在绑定方法中,默认自动传递self对象 (前提:super所在作用域存在self)

如果调用非绑定方法,会报错

f_hobby()方法非绑定方法

通过super()调用报错

通过super调用父类方法,是把子类对象传过去,执行,如果方法中调用对象成员属性,则调用的是子类成员属性

(3).菱形继承 (钻石继承) super深度理解

“”"

Human

Man Woman

Children

“”"

四个类中都有同名方法,该怎么调

class MyClass():
    pass

class Human():
    pty = 1
    def feelT(self):
        print("古代人类,天热了,光腚1")
        print(self.pty)
        print("古代人类,天冷了,穿寿衣2")
    
class Man(Human):
    # pty = 2
    def feelT(self):
        print("男人,天热了,光膀子3")
        print(super(),"<==2==>")
        super().feelT()
        print("男人,天冷了,光腚4")
    
class Woman(Human):
    # pty = 3
    def feelT(self):
        print("女人,天热了,脱毛5")
        print(super(),"<==3==>")
        super().feelT()
        print("女人,天冷了,穿貂6")

class Children(Man,Woman):
    # pty = 4
    def feelT(self):
        print("小孩,天热了,光腚7")
        print(super(),"<==1==>")
        super().feelT()
        print("小孩,天冷了,多喝热水8")


# ### super的深层理解
obj = Children()
obj.feelT()
# 73512648

super调用顺序

#mro: 方法解析顺序 (c3算法计算的)

#语法: 类.mro() => 列表

m :method

r :resolution

o :order

super 会自动根据mro列表返回出来的顺序关系,依次调用

super作用:专门用于解决复杂的多继承调用顺序关系;依照mro返回的列表顺序,依次调用;

super调用的顺序:会按照c3算法的广度优先原则进行调用

super传参:会默认在调用方法时,传递该对象参数;

lst = Children.mro()
print(lst)

[
<class '__main__.Children'>, 
<class '__main__.Man'>, 
<class '__main__.Woman'>,
<class '__main__.Human'>, 
<class 'object'>
]

根据 类.mro方法返回的列表顺序,来调用。遇到super().feelT()暂停,查找下一个调用

当不确定调用顺序时,可以打印下这个列表,来确认

# ### issubclass与isinstance
# issubclass 判断类的子父关系(应用在类与类之间) 第一个参数是子,第二个参数是父  是父子关系返回True,非父子关系返回False
"""只要在一条继承链上满足关系即可"""
res = issubclass(Children,Man)
res = issubclass(Children,Human)
res = issubclass(Children,MyClass)
# 如果元组当中有一个父类满足,即返回真
res = issubclass(Children,  (Man,Human,MyClass)  )
print(res)

# isinstance 判断对象的类型  (应用在类与对象之间)  第一个参数是对象,第二个参数是类
"""只要在一条继承链上满足关系即可"""
res = isinstance(obj,Children)
res = isinstance(obj,Human)
res = isinstance(obj,MyClass)
# 如果元组当中有一个类满足,即返回真
res = isinstance(obj,  (Man,Human,MyClass)  )
print(res)

#该对象只要是该类,或者该类的子类创建的,返回的都是True

(4).多继的承弊端

多继承的弊端会造成菱形继承这种情况,找不清调用顺序

super对象按照mro列表的顺序依次调用,解决菱形继承存在的问题

经典类:深度优先 (python2.x)

新式类:广度优先 (python3.x)

写多继承时,尽量避免造成不同类相同方法名的情况,提高代码质量 高内聚,低耦合

高内聚:一个模块只完成一个任务,专一性高

低耦合:模块与模块之间可以彼此独立不冲突,方便移植复用.


相关文章
|
17天前
|
存储 人工智能 数据处理
Python:编程的艺术与科学的完美交融
Python:编程的艺术与科学的完美交融
19 1
|
4天前
|
JSON 数据格式 开发者
pip和requests在Python编程中各自扮演着不同的角色
`pip`是Python的包管理器,用于安装、升级和管理PyPI上的包;`requests`是一个HTTP库,简化了HTTP通信,支持各种HTTP请求类型及数据交互。两者在Python环境中分别负责包管理和网络请求。
18 5
|
6天前
|
存储 Python 容器
Python高级编程
Python集合包括可变的set和不可变的frozenset,用于存储无序、不重复的哈希元素。创建集合可使用{}或set(),如`my_set = {1, 2, 3, 4, 5}`。通过add()添加元素,remove()或discard()删除元素,如`my_set.remove(3)`。
|
7天前
|
测试技术 Python
Python模块化方式编程实践
Python模块化编程提升代码质量,包括:定义专注单一任务的模块;使用`import`导入模块;封装函数和类,明确命名便于重用;避免全局变量降低耦合;使用文档字符串增强可读性;为每个模块写单元测试确保正确性;重用模块作为库;定期维护更新以适应Python新版本。遵循这些实践,可提高代码可读性、重用性和可维护性。
31 2
|
9天前
|
Python
Python中的面向对象
【5月更文挑战第4天】面向对象编程(OOP)是Python的核心,涉及类与对象、封装、继承和多态。类是对象的模板,对象则是类的实例。例如,`Person`类有`__init__`构造方法和`greet`方法。
15 3
|
13天前
|
测试技术 调度 索引
python编程中常见的问题
【4月更文挑战第23天】
32 2
|
13天前
|
网络协议 算法 网络架构
Python网络编程之udp编程、黏包以及解决方案、tcpserver
Python网络编程之udp编程、黏包以及解决方案、tcpserver
|
13天前
|
机器学习/深度学习 数据挖掘 算法框架/工具
Python:编程的艺术与魅力
Python:编程的艺术与魅力
25 3
|
14天前
|
机器学习/深度学习 数据可视化 数据挖掘
实用技巧:提高 Python 编程效率的五个方法
本文介绍了五个提高 Python 编程效率的实用技巧,包括使用虚拟环境管理依赖、掌握列表推导式、使用生成器提升性能、利用装饰器简化代码结构以及使用 Jupyter Notebook 进行交互式开发。通过掌握这些技巧,可以让你的 Python 编程更加高效。
|
16天前
|
机器学习/深度学习 数据挖掘 API
pymc,一个灵活的的 Python 概率编程库!
pymc,一个灵活的的 Python 概率编程库!
21 1