面向对象&三大基本特征&五大基本原则&魔法方法&反射

面向对象

面向对象编程概念:(Object Oriented Programming-OOP)
是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

特点:

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

三大基本特征:封装、继承、多态

面向对象的三个基本特征是:封装、继承、多态

1、封装

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。
  
  面向对象的不就是使用程序处理事情时以对象为中心去分析吗,与面向过程不同,面向过程关心处理的逻辑、流程等问题,而不关心事件主体。而面向对象即面向主体,所以我们在解决问题时应该先进行对象的封装(对象是封装类的实例,比如张三是人,人是一个封装类,张三只是对象中的一个实例、一个对象)。比如我们日常生活中的小兔子、小绵羊都可以封装为一个类。

封装的优点:

  • 将变化隔离
  • 便于使用
  • 提高复用性
  • 提高安全性

2、继承

继承是面向对象的基本特征之一,当一个类继承自另一个类,它就被称为一个子类/派生类,继承自父类/基类/超类。它会继承/获取所有类成员(属性和方法)。继承机制允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
  
继承的作用:
继承能让我们重新使用代码,也能更容易的创建和维护应用。

继承的分类:

  • 单继承:一个类继承自单个基类
  • 多继承:一个类继承自多个基类
  • 多级继承:一个类继承自单个基类,后者则继承自另一个基类
  • 分层继承:多个类继承自单个基类
  • 混合继承:两种或多种类型继承的混合

继承概念的实现方式有三类:

实现继承、接口继承和可视继承。

Ø 实现继承是指使用基类的属性和方法而无需额外编码的能力;

Ø 接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;

Ø 可视继承是指子窗体(类)使用基窗体(类)的外观和实现代码的能力。

3、多态

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。“一个接口,多种实现”

实现多态的两种方式:

覆盖,是指子类重新定义父类的虚函数的做法。

重载,是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

多态的优点:

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

五大基本原则

1、单一职责原则(SRP)
  一个类应该有且只有一个去改变它的理由,这意味着一个类应该只有一项工作。
  比如在职员类里,将工程师、销售人员、销售经理这些情况都放在职员类里考虑,其结果将会非常混乱,在这个假设下,职员类里的每个方法都要if else判断是哪种情况,从类结构上来说将会十分臃肿。
  
  2、开放封闭原则(OCP)
  对象或实体应该对扩展开放,对修改封闭。
  更改封闭即是在我们对模块进行扩展时,勿需对源有程序代码和DLL进行修改或重新编译文件!这个原则对我们在设计类的时候很有帮助,坚持这个原则就必须尽量考虑接口封装,抽象机制和多态技术!
  
  3、里氏替换原则(LSP)
  在对象 x 为类型 T 时 q(x) 成立,那么当 S 是 T 的子类时,对象 y 为类型 S 时 q(y) 也应成立。(即对父类的调用同样适用于子类)
  
  4、依赖倒置原则(DIP)
  高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。具体实现应该依赖于抽象,而不是抽象依赖于实现。
 
  5、接口隔离原则(ISP)
  不应强迫客户端实现一个它用不上的接口,或是说客户端不应该被迫依赖它们不使用的方法,使用多个专门的接口比使用单个接口要好的多!

属性

1.类的公有属性
public_attrs:能在类的外部被使用或直接访问。在类内部的方法中使用时 public_attrs_attrs,在类的外部class_name.public_attrs。

2.类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。

3.类的(公有)方法
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。

4.类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。

类实例化时魔法方法

1、何为魔法方法:
  Python中,一定要区分开函数和方法的含义;
  1.函数:类外部定义的,跟类没有直接关系的;形式: def func(*argv):
  2.方法:class内部定义的函数(对象的方法也可以认为是属性);分为两种:
    ① python自动产生的(魔法方法):一般形式为 func(),python会在对应的时机自动调用该函数;
    ② 人为自定义的方法:一般和普通函数没有区别,只是定义在了class中而已
  3.方法与函数的区别:
    方法可认为是函数的特殊情况;
    ① 方法定义在class内部
    ② 方法的第一个参数应为 cls(类方法) 或者 self(实例方法)

2、魔法方法调用的顺序

class Student(object):
    def __new__(cls, *args, **kwargs):
        print('__new__')
        return object.__new__(cls)   # 必须返回父类的__new__方法,否则不不执行__init__方法,无法创建实例
 
    def __init__(self,name):
        print('__init__')
        self.name = name
 
    def __str__(self):                # 作用:打印实例时显示指定字符串,而不是内存地址
        print('__str__')
        return self.name
 
    def __call__(self, *args, **kwargs):        # 当执行C()(*args) 或者 s1(*args) 就会执行__call__
        print('__call__',*args)
 
    def __del__(self):                # 作用:清除无用的实例对内存的暂用
        print('__del__')
 

#1、实例化时机会执行__new__、init

#2、执行 实例() 就会执行__call__ 方法,并将参数传递给__call__函数

#3、当打印实例时就会执行 str 方法下返回的字符串(默认返回的实例地址)

#4、析构方法:当删除实例时就会调用 del 方法

##魔法方法汇总:
1.基本方法


 __int__(self) 定义当被 int() 调用时的行为  
 __float__(self)  定义当被 float() 调用时的行为  
 __round__(self[, n]) 当被round()调用时的行为 round(digit[, n]) 将digit数字保留n位精度  __hash__(self) 定义能被 hash() 调用的行为     __bytes__(self)  定义被 bytes() 调用的行为    __bool__(self) 定义被 bool() 调用的行为 返回True(1)False(0)  
 __format__(self, form) 定义被 format()调用的行为

2.运算符方法

 __add__(self, other) 加法:+   
__sub__(self, other)  减法:-  
__mul__(self,other)  乘法:*   
__truediv(self, other) 除法:/ 注意是 truediv 
__floordiv(self, other) 整数除法://  floor()即为向下取整的意思
__mod__(self, other)  求余:%  
__pow__(self, other[, mod]) 乘方:**   pow(x,y[,z]),若无Z,则为 return x**y若有Z,则为 return x**y%z
__divmod__(self, other) divmode()  返回值为元祖  (商值,余数) 
__lshift__(self, other)  左移:<<  
__rshift__(self, other) 右移:>>   
__and__(self, other) 按位与:& 注意以下均为按位操作,非逻辑操作 
__or__(self, other) 按位或:|   
__xor__(self, other) 按位异或:^  

3.反运算符方法

 __radd__(self, other) 加法,如a+b,当a不支持__add__()操作时,调用此函数;  即在运算符的基础上加上 'r' 即可,以下雷同 
 __rsub__(self, other) other - self  

4.增量赋值运算方法

 __iadd__(self, other) 赋值加法:+=    即在赋值运算符之前加 'i' ,以下雷同 
__isub__(self, other)  赋值减法:-=  self = self - other 

5.一元运算符方法

__pos__(self) 定义正号:+x  
__neg__(self) 定义负号:-x  
__abs__(self) 取绝对值  
__invert__(self) 按位求反:~x  

6.比较运算符方法

__gt__(self, other) 大于:>  
__ge__(self, other) 大于等于:>=  
__lt__(self, other) 小于:<  
__le__(self, other) 小于等于:<=  
__eq__(self, other) 相等:==  
__ne__(self, other) 不等:!= 

7.属性操作

__getattr__(self, name) 当用户访问一个不存在的属性时调用 注意 object/super() (所有类的基类) 是无该方法的
__getattribute(self, name) 访问存在的属性时调用 先调用此函数,如找不到该属性,再去调用上面的属性
__setattr__(self, name, value) 设置属性时调用  
__delattr__(self, name) 删除一个属性时调用 
__get__(self, instance, owner) 描述符被访问时调用 想详细了解,请点击这里
 __set__(self, instance, value) 描述符被改变时调用  
  __delelte__(self, instance, value) 删除描述符时调用 

8.容器类型操作

__len__(self)    求容器的大小(注意与capacity的区别) 可变和非尅便容器均具备 __len__ 和 __getitem__
__getitem__(self, key) 获取容器中指定元素的行为  
__setitem__(self, key, value) 设置容器中指定元素的行为  只有可变容器拥有 __setitem__ 和 __delitem__
__delitem__(self, key) 删除容器中指定元素的行为  
__iter__(self) 定义迭代器中元素的行为  
__reversed__(self) 当调用reversed()函数时  
__contains__(self, item) 成员运算符in/ not in的行为  

PS: ①.以上所有的魔法方法,采用__xx__形式(__为双 “_”,双下划线) 
  ②.以上魔法方法为Python解释器自动调用,当然也可以手动调用 
  ③.魔法方法Python解释器自动给出默认的,因此除非需要改变其内部功能,其它时刻刻使用默认魔法方法 
  ④.魔法方法是针对class而言的,脱离了”类“谈magic_method是没有意义的
  ⑤.*argv为可变的参数列表,类似C语言的va(variable argument),注意与指针的区别,python中暂时忘掉指针,因为python的内存机制都是解释器自动完成的

反射(hasattr和getattr和setattr和delattr)

反射的概念:
反射指的是通过 “字符串” 对 对象的属性进行操作。

- hasattr: 通过 “字符串” 判断对象的属性或方法是否存在。hasattr(ogj,name_str) 判断一个对象里是否有对应的字符串方法
class Dog(object):
    def eat(self,food):
        print("eat method!!!")
d = Dog()
 
#hasattr判断对象d是否有eat方法,有返回True,没有返回False
print(hasattr(d,'eat'))     #True
print(hasattr(d,'cat'))     #False
- getattr: 通过 “字符串” 获取对象的属性或方法。getattr(obj,name_str) 根据字符串去获取obj对象里的对应的方法的内存地址
class Dog(object):
    def eat(self):
        print("eat method!!!")
d = Dog()
 
if hasattr(d,'eat'):          # hasattr判断实例是否有eat方法
    func = getattr(d, 'eat')  # getattr获取实例d的eat方法内存地址
    func()                    # 执行实例d的eat方法
#运行结果:  eat method!!!
- setattr: 通过 “字符串” 设置对象的属性或方法。使用stattr给类实例对象动态添加一个新的方法
def abc(self):
    print("%s正在交谈"%self.name)

class Person(object):
    def __init__(self,name):
        self.name = name

p = Person("星珲)
setattr(p,"talk",abc)   # 将abc函数添加到对象中p中,并命名为talk
p.talk(p)               # 调用talk方法,因为这是额外添加的方法,需手动传入对象

# 打印结果 星珲正在交谈

setattr(p,"age",30)     # 添加一个变量age,复制为30
print(p.age)  
- delattr: 通过 “字符串” 删除对象的属性或方法。
class Person(object):
    def __init__(self,name):
        self.name = name
    def talk(self):
        print("%s正在交谈"%self.name)

p = Person("星珲)

delattr(p,"name")       # 删除name变量
print(p.name) 
发布了25 篇原创文章 · 获赞 11 · 访问量 915

猜你喜欢

转载自blog.csdn.net/weixin_45139342/article/details/104215168