最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

python面向对象三大特性详解1-封装

XAMPP案例 admin 658浏览 0评论
面向对象编程有三大特性:封装、继承、多态,本文带大家来认识和了解这三个特性~
补充 – 新式类 & 经典类
1
在python2.x中,新式类是继承了object类的子类,以及该子类的子类 子子类…;经典类就是没有继承没有继承object类的子类,以及该子类的子类 子子类…。在python3.x中,如果没有继承任何类,默认就会继承object类,没有经典类和新式类之分。object类提供了一些常用内置方法的实现,比如用来在打印对象时返回字符串的内置方法__str__,后续文章会做介绍的哦~
封装
1
封装是面向对象编程最重要的特性,封装就是将数据和功能整合到一起,就是我们之前说的将数据与功能装在一起。
针对封装到对象或者类中属性,我们可以严格控制在类外部对它们的访问,即隐藏属性和开放接口。 
隐藏属性
如何隐藏属性
在类体代码中,如果在一个属性名前加__前缀,就会实现一个对外部隐藏该属性的效果,虽然在类外部无法直接通过对象.属性的方式直接访问双下划线开头的属性,但是知道类名和属性名就可以得到外部访问类属性的方式即对象._类名__属性名,所以说这种操作并没有严格意义上的限制外部访问类内部定义的属性。这种隐藏对外不对内,这种变形操作只在检查类体语法的时候发生一次,在类外部定义的__开头的属性都不会发生变形。
class Test():
    __name = 'test'  # 函数外部访问时变为_Test__name
    
    def __init__(self):
        self.__x = 'x'
        
    def test(self):
        self.__x = 'test'  # 在类体代码内部可以正常使用属性
        print('test')
        
print(Test.__name)  # AttributeError: type object 'Test' has no attribute '__name'
print(Test._Test__name)  # test
print(Test.__dict__) 

mappingproxy(..., '_Test__name': 'test', '_Test__test': <function Test.__test at 0x0000026E75F6E3A0>, ...})

test_obj = Test()
test_obj.test()  # 正常执行
print(test_obj.__x)  # AttributeError: 'Test' object has no attribute '__x'
test_obj.__a = 'a'  # 类外部定义的__的属性不会发生变形
print(test_obj.__a)  # a

 隐藏属性的目的

定义属性就是为了使用,所以隐藏并不是最终的目的,将数据属性隐藏起来就限制了类外部对数据的直接操作,但是类内部应该提供相应的接口来允许类外部间接的操作数据,可以在接口上增加额外的逻辑来对外部操作类内定义的数据进行严格的控制。比如:
class People:
    
    def __init__(self,name):
        self.__name = name
        
    def tell_info(self):
        pwd = input('请输入暗号>>').strip()
        if pwd == '0':
            print(self.__name)
        else:
            print('暗号错误')
            
    def set_name(self,new_name):
        if type(new_name) is str:
            self.__name = new_name
            print(self.__name)
        else:
            print('请输入字符串')

p = People('python')
p.tell_info()p.set_name(123)

隐藏函数属性的目的是只将用户用到的接口暴露出去,在该接口内可能会用到类内定义的其他方法,但是这些方法用户无需直接调用,就可以将这些方法进行隐藏,隔离程序的复杂度。

隐藏属性和暴露接口就是为了明确的区分类的内外部分,类的内部可以修改类内定义的数据但是不影响外部调用,类外部只需要有一个接口,只要接口的名字、参数不变,那么无论类内部的代码如何改变,外部调用方式都不会发生改变。

 

继承与派生
2
继承是创建新类的一种方式,通过继承得到的新类可以称为子类或者派生类,被继承的类被称为父类或者基类。通过继承得到的子类会继承父类的所有属性,python支持多继承,子类可以继承一个或者多个父类。通过使用类的继承,可以解决类与类之间的代码冗余问题。类的继承语法如下:

class Parent1():
    x = 111
class Parent2():
    pass

class Foo(Parent1): # 单继承,父类是Parent1
    pass

class Foo1(Parent1,Parent2): # 多进程,父类是Parent1 Parent2
    pass
可以通过__bases__查看子类继承的所有父类。
print(Foo.__bases__)
# (<class '__main__.Parent1'>,)
print(Foo1.__bases__)
# (<class '__main__.Parent1'>, <class '__main__.Parent2'>)

如果想要找出类和类之间的关系,需要先总结一下多个类的相似之处,就可以得到父类,类与类之间的继承指的就是什么是什么的关系,比如金毛是狗,狗是动物比如:

子类可以继承父类的所有属性,比如我们还是以上篇文章中的外卖系统作为案例,在这个程序中至少存在三个类:商家类、外卖小哥类、顾客类,我们可以先定义出这三个类:

# 商家类
class Merchants():
    
    platform = 'python外卖平台'
    
    def __init__(self, name, addr, tel):
        self.name = name  # 商家名字
        self.addr = addr  # 商家地址
        self.tel = tel  # 商家联系电话
        
    def reveive_order(self):
        print(f'{self.name}已经接单')
        
# 外卖小哥类
class Rider():
    
    platform = 'python外卖平台'
    
    def __init__(self, name, addr, tel):
        self.name = name  # 外卖小哥姓名
        self.addr = addr  # 外卖小哥配送地址
        self.tel = tel  # 外卖小哥电话
        
    def distribution(self):
        print(f'{self.name}正在配送')
        
# 顾客类
class Customer():
    
    platform = 'python外卖平台'
    
    def __init__(self, name, addr, tel):
        self.name = name  # 顾客姓名
        self.addr = addr  # 收货地址
        self.tel = tel  # 顾客电话
        
    def accept_delivery(self):
        print(f'{self.name}已经收到外卖')

以上三个类之间存在重复的代码,都属于python外卖平台,都需要独有的name、addr、tel,因此可以得出以下继承关系,实现代码重用:

class Personnel_information():
    platform = 'python外卖平台'
    
    def __init__(self, name, addr, tel):
        self.name = name  
        self.addr = addr 
        self.tel = tel 
        
# 商家类class Merchants(Personnel_information):
        
    def reveive_order(self):
        print(f'{self.name}已经接单')
        
# 外卖小哥类
class Rider(Personnel_information):
    
    def distribution(self):
        print(f'{self.name}正在配送')
    
# 顾客类
class Customer(Personnel_information):
    
    def accept_delivery(self):
        print(f'{self.name}已经收到外卖')

商家类、外卖小哥类和顾客类中并没有定义__init__方法,但是会从它们的父类中找到__init__方法,因为子类会继承父类所有的属性和方法,因此仍然可以正常实例化:

mer = Merchants('川菜', '山清水秀区', '11111')
rider = Rider('小庄', '依山傍水区', '2222')
customer = Customer('xu', '养生区', '33333')
01
属性查找
单继承属性查找
对象的属性可以通过对象.__dict__查看,有了继承关系后,对象在查找属性时先从自己的__dict__中查找,如果没有则去实例化自己的类中找,找不到再去父类中找,都找不到会抛出异常。注意,属性的查找一定是以定义阶段为准。
class Test():
    
    def t1(self):
        print('from Test t1')
        
class Foo(Test):
    
    def f1(self):
        print('Foo f1')
        
f = Foo()
f.t1
# 运行结果
from Test t1

父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的。

class Test():
    
    def __t1(self):
        print('from Test t1')
    
    def t2(self):
        self.__t1() 
        print('from Test t2')
        
class Foo(Test):
    
    def __t1(self):
        print('Foo t1')
        
f = Foo()
f.t2()
# 运行结果from Test t1from Test t2

 多继承属性查找

python面向对象支持多继承,好处是子类可以同时继承多个父类的属性,最大限度的重用代码,但是多继承也有很多缺点,多继承违背了继承表达的什么是什么的关系,而且如果一个类同时继承多个父类,代码的可读性就会变得很差,可能会出现菱形继承的问题。菱形继承是不同子类拥有同一个非object的父类,而不同的子类又是另一个子类的父类,如果A类中有一个方法,B类或者C类对这个方法进行了重写,D类继承的是哪个版本的方法?

dy000024

转载请注明:XAMPP中文组官网 » python面向对象三大特性详解1-封装

您必须 登录 才能发表评论!