python面向对象

基础概念:

class Dog:
    d_type = "金毛"   # 类属性,所有实例共享

  # 解释器执行实例化代码,会先在内存中创建该类实例对象,然后调用类 的__init__方法。
  # 调用 __init__方法时,就将实例对象 传递给 self参数,self 参数变量 指向的 就是 实例对象 本身
  def __init__(self, name, age):  # 初始化方法/实例方法,实例化时会自动执行,创建一些实例属性
    self.name = name    # 实例属性,每个实例独享
    self.age = age    # 实例属性通常在类的初始化方法里面定义
  
  @classmethod  # 类方法只能访问类属性,不能访问实例属性
  def class_method(cls):  # 不操作任何实例的话就应该定义为类方法
    print('class method called',cls)

  @staticmethod  
  def haha():  # 静态方法不能访问实例属性也不能访问类属性,没有传入self
    print('hello world!')  
  
def say_hi(self): # 类的实例方法,都是要访问类的实例属性的 或 操作实例属性 print("hello, I am a dog,my type is ",self.d_type,self)

dog = Dog('小金',2)
# 通过类名访问类属性
print(Dog.d_type)
# 通过实例名访问类属性
print(d.d_type)
# 不能通过类名访问实例属性
print(Dog.name)
# 实例给类属性赋值,相当于给实例创建了一个新的实例属性
dog.d_type = '二哈'
print(dog.d_type)
print(Dog.d_type)

-------------------------------------------------------------------------

类与类(接口)之间的关系:实现关系、依赖关系、关联关系、聚合关系、组合关系、继承关系。

举例说明几种关系:

  1. 依赖关系:狗和主人的关系
  2. 关联关系:你和你女朋友的关系
  3. 聚合关系:电脑的各部件组成完整的电脑,电脑里面有CPU,硬盘,内存等。每个组件都有自己的生命周期,电脑挂了,CPU还是好的,还是完整的个体
  4. 组合关系:比聚合还要紧密,比如人的大脑,心脏,各个器官。这些器官组成一个人,如果人挂了,其他东西也跟着挂了

 

实现关系(Realization):是一种类与接口的关系,指一个类实现一个或多个接口功能的过程,这里的接口更多的是一种契约或规范。实现是两个类之间或类与接口之间耦合度最大的关系之一,在这种关系中,类实现了接口或接口类中所声明的操作

代码实现的二种形式:

  • 类具体实现接口中所声明的操作:如Java中支持原生interface,可以直接implement
  • 类具体实现接口类中所声明的操作:如python中无原生interface,这里的接口类更多的是逻辑上的契约或规范

 UML中使用带三角箭头的虚线,箭头指向接口

代码实现:

class Car(object):  # 待实现的接口
    def engine(self):
        raise NotImplementedError

class Benz(Car):  # 具体实现所定义的引擎
    def engine(self):
        print ("奔驰嘟嘟~~~")

        
class BMW(Car):  
    def engine(self):
        print ("宝马嘟嘟~~~")

       
benz = Benz() bmw = BMW() benz.engine()
bmw.engine()

 

依赖关系(Dependency):是一种使用的关系,即一个类的实现需要另一个类的协助,所以要尽量不使用双向的互相依赖.

代码表现:局部变量、方法的参数或者对静态方法的调用

三种形式:

  • 类B作为类A方法的形参
  • 类B作为类A方法的局部变量
  • 类A调用类B的静态方法

UML中使用带箭头的虚线表示,箭头指向表示调用关系,从类A指向类B

代码实现:

类B作为类A方法的形参

class Person(object):  # 类A
    def flying(self, plane):
        plane.fly()  # 在类A中调用类B的方法
        
class Plane(object):  # 类B作为一个参数传递给类A
    def fly(self):
        print ("飞机起飞了。。。")

person = Person()
plane = Plane()
person.flying(plane) # 传入类B

类B作为类A方法的局部变量

class Person(object):  # 类A 
    def flying(self):
        self.plane = Plane()  # 类B作为类A实例属性
        plane.fly()  # 调用类B的方法

        
class Plane(object):  # 类B
    def fly(self):
        print ("飞机起飞了。。。")

        
person = Person()
person.flying()

 类A调用类B的静态方法

class Person(object):  # 类A
    def flying(self):
        Plane.fly()  # 直接调用类B的静态方法

        
class Plane(object):  # 类B
    @staticmethod  # 类B的静态方法
    def fly():
        print ("飞机起飞了。。。")

        
person = Person()
person.flying()

 

关联关系(Association):是一种长期性的、拥有的关系,它使一个类知道另一个类的属性和方法,双方的关系一般是平等的,如学校与学生之间、老师与学生之间。被关联类B以类的属性形式出现在关联类A中,双向的关联可以有两个箭头或者没有箭头,单向的关联有一个箭头。

依赖关系与关联关系的区别有动静之分,依赖关系的偶然性和临时性说明了动态性,关联关系的长期性、拥有性静态地展示了对被关联类的引用。

四种形式:

  • 单向关联:单向拥有关系,只有一个类知道另一个类的属性和方法
  • 双向关联:双向拥有关系,双方都知道对方的属性和方法
  • 自身关联:自己关联自己,这种情况比较少但也有用到,如链表
  • 多重性关联:表示两个类的对象在数量上的对应关系,多重性可在关联线上用数字范围表示

UML中使用直线箭头表示,箭头指向为被关联的类,从类A指向类B

 单向关联

 双向关联

 自我关联

  多重性关联

 代码实现:

单向关联

class Student(object):  # 类B
    def __init__(self):
        self.title = "张三"

    def study(self):
        print ("学习中...")

        
class School(object):  # 类A 知道类B的属性和方法
    def __init__(self):
        self.address = "北厂街"
        self.student = Student()  # 实例化类B

    def act(self):
        print(self.student.title)  # 打印类B的实例属性title  
        self.student.study()  # 调用类B的实例方法 study

        
school = School()
school.act()

 双向关联

class Student(object):  # 类B
    def __init__(self):
        self.school = School()  # 实例化类A

        
class School(object):  # 类A
    def __init__(self):
        self.student = Student()  # 实例化类B

自我关联

class Node(object):  
    def __init__(self):
        self.next = Node()  #调用自己


class ListNode:
    """链表节点类"""
    def __init__(self, val: int):
        self.val: int = val                  # 节点值
        self.next = None # 指向下一节点的指针(引用)

 

聚合关系(Aggregation):聚合关系是关联关系的特例,是整体和部分的关系,聚合关系中的整体和部分是可以分离的,生命周期也是相互独立的,如计算机与CPU、公司与员工的关系、车和轮胎是整体和部分的关系,轮胎离开车仍然可以存在。

uml中使用 带空心菱形的实心线,空心菱形指向整体(类A),实线箭头边指向部分(类B)

代码实现:

类A由类B聚合而成,类A包含有类B的全局对象,但类B的对象可以不在类A创建的时刻创建

class School(object):  # 类A
    def __init__(self):
        self.__students = []  # 类B的对象不在类A初始化时创建

    def add_student(self, student):
        self.__students.append(student)


class Student(object):  # 类B
    pass

student = Student()
school = School()
school.add_student(student)

 

组合关系(Composition):组合关系也是关联关系的特例,属于强聚合,本身也表示整体与部分的关系,但部分不能离开整体而单独存在,整体生命周期的结束时也是部分的生命周期到头时。如人和大脑,如公司和部门是整体和部分的关系,没有公司就不存在部门。

 

聚合和组合其实都是关联的特例,都是整体与部分的关系。它们的区别在于整体和部分是否可分离,

聚合的两个对象之间是可分离的,且具有各自的生命周期

而组合的两个对象往往表现为一种同命相连的关系。

 

uml中使用带实心菱形的实线,菱形指向整体

 代码实现

class Company(object):
    def __init__(self):
        print("公司有多个部门:")
        self.__partmentA = PartmentA()
     self.__partmentB = PartmentB()
def run(self): print("打卡上班...") class PartmentA(object): def __init__(self): print("公司的部门A")
class PartmentB(object):
    def __init__(self):
        print("公司的部门B")
company = Company() 
company.run()

 

继承关系(泛化关系 Generalization):是一种继承关系,它指定了子类如何特化父类的所有特征和行为,即子类继承父类、或子接口继承父接口的功能并增加自己新功能的过程。例如:老虎是动物的一种,即有老虎的特性也有动物的共性 

父类称为基类或超类,子类也称为派生类。子类可以继承自抽象类或普通类。

 

二种形式: 

 

  • 子类继承自抽象类或普通类
  • 子接口继承自父接口:适用于Java

 

 UML中使用带三角箭头的实线,箭头由子类指向父类、或子接口指向父接口

 代码实现:

子类继承自抽象类,必须实现父类中@abstractmethod修饰的抽象方法

from abc import ABCMeta, abstractmethod

#
抽象基类是一种不能直接被实例化的类,它的主要作用是定义接口和规范子类的行为
class Animal(metaclass=ABCMeta):  # 父类
def __init__(self):
        self.name = "动物"
    
  # ABC 是一个抽象基类,它的子类必须实现指定的抽象方法 @abstractmethod  # abstractmethod是一个装饰器,用于指定一个抽象方法
def run(self): print ("奔跑的动物。。。") def play(self): print ("动物在玩耍。。。") class Dog(Animal): def __init__(self): self.name = "狗子 def run(self): print ("奔跑的狗子。。。") def __bark(self): print ("狗子汪汪汪。。。") class Cat(Animal): def __init__(self): self.name = "喵咪" def run(self): print ("奔跑的动物。。。") def play(self): print ("喵咪在玩耍。。。") def __jump(self): print ("喵咪蹦蹦跳。。。") dog = Dog() cat = Cat() dog.run() dog.play() cat.run() cat.play()
子类继承自普通类,子类方法重写父类同名非私有方法
class Animal(object):
    def __init__(self):
        self.name = "动物"

    def run(self):
        print ("奔跑的动物。。。")

    def play(self):
        print ("动物在玩耍。。。")

class Dog(Animal):
    def __init__(self):
        self.name = "狗子"

    def run(self):
        print ("奔跑的狗子。。。")

    def __bark(self):
        print ("狗子汪汪汪。。。")

        
class Cat(Animal):
    def __init__(self):
        self.name = "喵咪"
        
    def play(self):
        print ("奔跑的喵咪。。。")

    def __jump(self):
        print ("喵咪蹦蹦跳。。。")

    
dog = Dog()
cat = Cat()
dog.run()
dog.play()
cat.run()
cat.play()

关系的强弱:继承 = 实现 > 组合 > 聚合 > 关联 > 依赖

关联和依赖的区别:

  • 关联关系强、长期
  • 关联关系是通过属性来实现;依赖关联是通过方法形参或者局部变量实现

关联、组合/聚合的异同

  • 相同:都是关联,都是做类的属性
  • 不同点:组合 /聚合表示的是整体和部分的关系,关联可以表示所有关系

组合和聚合的异同

  • 相同:都是关联的特例,都是表示的整体和部分的关系
  • 不同点:整体部分的生命周期是否相同?组合更强

 

 参考学习:https://www.cnblogs.com/coolstream/p/9499299.html

--------------------------------------------------------------------------

面向对象三大特性:

  • 封装
  • 继承
  • 多态

 

三大特性之-封装

封装相当于一个保护屏障,防止这个类的代码和数据被外部代码随机访问。

原则:

1,将不需要对外提供的内容隐藏

2,隐藏属性,提供公共方法对其访问

私有变量和私有方法:在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

class Person(object):

    def __init__(self, name, age):
        self.name = name    # 实例变量,成员变量
        self.age = age
        self.__life_val = 100     # 私有变量,私有属性

    def get_life_val(self):
        print("生命值 还有",self.__life_val)
        return self.__life_val

    def __breath(self):     # 私有函数
        print("%s is breathing..." % self.name)

    def got_attack(self):   # 封装
        self.__life_val -= 20
        print("被攻击了,生命值减20")
        self.__breath()
        return self.__life_val

a = Person('张三',20)  # 实例化一个类
a.get_life_val()  # 通过公共方法访问 私有变量
a.got_attack()  # 通过公共方法访问 私有函数
# 访问私有函数:实例名._类名+方法名()
a._Person__breath()
# 修改私有属性
a._Person__life_val = 11
# 查看修改后的生命值
a.get_life_val()
# 实例生成后,再创建的私有属性,并不具有私有性,可以直接访问
a.__val = 333
print(a.__val) # 直接访问属性

 

三大特性之-继承见类的关系之继承关系。

在python中,有两种类的写法,不用写法采用的继承顺序不同

class A:  # 经典类

       pass

 

class B(object):  # 新式类

       pass

 

在python2中,经典类采用的是深度优先查找法,新式类采用的是广度优先

在python3中,无论是经典类,还是新式类,都是按广度优先查找

Python2.x中默认都是经典类,只有显示继承了object的才是新式类

Python3.x中默认都是新式类,不必显式的继承object.

之所以在python3中全部改成了广度优先,是因为深度优先在某些特殊情况下,会出现BUG。

 

多继承之C3算法

#
class A:
    def test(self):
        print("from A")


class B(A):
    # def test(self):
    #     print('from B')
    pass


class B2:
    def test(self):
        print('from B2')


class C(A):
    def test(self):
        print('from C')


class C2:
    def test(self):
        print('from C2')


class D(B,B2):
    # def test(self):
    #     print('from D')
    pass


class E(C,C2):
    def test(self):
        print('from E')


class F(D,E):
    # def test(self):
    #     print('from F')
    pass


f1 = F()
f1.test()
print(F.__mro__)    # 打印类的继承顺序

 三大特性之-多态

有时候一个对象会有多种表现形式,比如网站页面有个button按钮,这个button的设计可以不一样(单选框、多选框、圆角的点击按钮、直角的点击按钮等),尽管长的不一样,但它们都有一个共同的调用方式,就是onClick()方法。我们只要在页面上一点击就会触发这个方法。点完后有的按钮会变成选中状态、有的会提交表单、有的甚至会弹窗。

这种多个对象共用一个接口,又表现的形态不一样的现象,就叫做多态。

1,通过统一函数接口实现多态

2,通过抽象类实现多态(常用)

# 通过统一函数接口实现多态

class Dog(object):

    def sound(self):
        print('汪汪汪。。。')


class Cat(object):

    def sound(self):
        print('喵喵喵。。。')


def make_sound(animal_type):
    """统一调用接口"""
    animal_type.sound()     # 不管传进来什么动物,我都调用sound()方法


dogObj = Dog()
catObj = Cat()

make_sound(dogObj)
make_sound(catObj)
# 通过抽象类实现多态(常用)

class Document:  # 文件

    def __init__(self, name):
        self.name = name

    def show(self):
        raise NotImplementedError("Subclass must implement abstract method.")


class Pdf(Document):  # 继承Document,文件类型为PDF

    def show(self):
        return 'Show pdf contents!'


class Word(Document):  # 文件类型为word

    def show(self):
        return 'Show word contents'


pdf_obj = Pdf("练习题目.pdf")
print(pdf_obj.show())

 

posted @ 2023-06-10 21:39  天才九少  阅读(24)  评论(0)    收藏  举报