Python 面向对象

Python 面向对象

1.成员共分三类

1.1 变量

1.1.1 实例变量与类变量
  • class Foo:
        # 类变量(静态字段)
        country="中国"# 每个对象中的值都相同。
        # 方法
        def __init__(self,name):
            self.name=name     # 实例变量,字段
    
        # 方法
        def func(self):
            print(self.country)
            
            print(Foo.country)# 推荐使用
    
    obj1=Foo('章北海')
    obj2=Foo('泰勒')
    print(obj1.name,obj1.country,Foo.country)# obj1.country 没有设置,默认取类的值
    obj2.country='美国'
    # 类变量,可以通过类直接访问
    print(obj2.name,obj2.country,Foo.country)
    
  • 准则:

    • 实例变量(字段)访问时,使用对象访问,即obj.name
    • 类变量(静态字段)访问时,使用类方法,即Foo.country,实在不方便时,才使用对象。
  • 类变量的是使用场景:当所有对象中有共同的字段时,且要改都改要删都删,可以将实例变量(字段)提取到类变量(静态字段)。

1.1.2 私有变量
  • 私有变量也分为两种,即私有类变量私有实例变量

  • class Foo:
        __country="中国"
        def __init__(self,name):
            self.__name=name #私有实例变量,字段
            self.age=123
    
        def func(self):
            print(self.__name)
            print(Foo.__country)
    
    obj=Foo('程心')
    # print(obj.__name) # 报错: AttributeError:'Foo' object has no attribute '__name'
    # print(Foo.__country)
    obj.func()
    
  • 私有的成员变量在 Python 中使用较少。特点是外部无法访问。特殊写法亦可获取到。一般不用。

1.2 方法

  • 分类
    • 实例方法
    • 静态方法
    • 类方法
  • 私有方法
    • 私有实例方法
    • 私有静态方法
    • 私有类方法
1.2.1 实例方法
  • 函数中必须包含self,
  • 一般通过对象调用
1.2.2静态方法
  • 编写时:

    • 方法上写上@staticmethod
    • 参数可有可无
  • 调用时:

    • 类.方法名()
    • 对象.方法名() # 不推荐使用此种方法
  • 使用场景:静态方法无需使用对象中封装的值,那么就可以使用静态方法。

  • class Foo:
        def __init__(self,name):
            self.name=name
    
        # 实例方法
        def func(self):
            print(self.name)
    
        @staticmethod
        def display():
            print(666)
    
    obj=Foo("逻辑")
    Foo.display()# 一般使用类调用
    
1.2.3 类方法
  • # -*- coding: utf-8 -*-
    '''
    @Time    : 2022/1/23 13:18
    @Author  : ziqingbaojian
    @File    : 03.方法.py
    '''
    class Foo:
        def __init__(self,name):
            self.name=name
    
        # 实例方法
        def func(self):
            print(self.name)
        
        # 静态方法
        @staticmethod
        def display():
            print(666)
    
        # 类方法
        @classmethod
        def show(cls,x1,x2):
            print(cls,x1,x2)
    
    # obj=Foo("逻辑")
    # Foo.display()# 一般使用类调用
    
    Foo.show(1,8)
    
    • 补充:self代值对象,cls代指类。
  • 定义时:

    • 方法上写上:@classmethod
    • 至少包含一个cls参数
  • 执行时:

    • 类名.方法名;默认会讲话当前类传值参数中
  • 使用场景:

    • 如果在方法中会使用到当前类,那么就可以使用类方法。单利模式可能会使用到对应的类方法。
  • 类方法与静态方法特别相似。调用时无需实例化。

1.2.4 私有方法的使用
# -*- coding: utf-8 -*-
'''
@Time    : 2022/1/23 13:18
@Author  : ziqingbaojian
@File    : 03.方法.py
'''
class Foo:
    def __init__(self,name):
        self.name=name

    # 实例方法
    def func(self):
        print(self.name)

    def __f1(self,args):
        print("私有方法")
    # 静态方法
    @staticmethod
    def __display():
        print("私有静态方法")
    @staticmethod
    def get_display():
        Foo.__display()
    # 类方法
    @classmethod
    def show(cls,x1,x2):
        print(cls,x1,x2)

# obj=Foo("逻辑")
# Foo.display()# 一般使用类调用

Foo.get_display()

1.3 属性

class Foo:

    @property
    def start(self):
        return 1
    @property
    def end(self):
        return 2

obj=Foo()
print(obj.start)
print(obj.end)

将方法改造为属性,即调用方法时通常不使用()进行调用。

  • 编写时:
    • 方法上方写上@property
    • 方法参数只有一个self
  • 调用时:
    • 无序加括号,使用 对象.方法
  • 应用场景:
    • 对于简单的方法,当无需传参,且有返回值时,可以使用@property
  • 属性也具有共有和私之分。与变量和方法类似

注意:类中私有的成员,在继承的子类中依旧不能被使用。

2.组合(建模)

2.1 对象的嵌套

# -*- coding: utf-8 -*-
'''
@Time    : 2022/1/23 14:02
@Author  : ziqingbaojian
@File    : 04.组合建模.py
'''

class School:
    def __init__(self,name,addres):
        self.name=name
        self.addres=addres

obj1=School("亚洲舰队",'自然选择号')
obj2=School("亚洲舰队",'蓝色空间号')


class Teacher:
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.__salary=salary
        self.school=None
t1=Teacher("章北海",30,10000)
t2=Teacher("褚岩",20,30000)
t1.school=obj1
t2.school=obj2
# 查看舰长所在的飞船,嵌套查看
print(t1.school.name)
print(t1.school.addres)

2.2 主动调用其他类的成员

class Base:
    def f1(self):
        print("5个功能")


class Foo(object):
    def f1(self):
        Base.f1(self)
        print("3个功能功能")
        
  • 通过类名.实例方法()需要进行手动传参,传入self.

  • obj=Base()
    Base.f1(obj)# 手动传参
    

2.3 继承调用

class Base:
    def f1(self):
        print("5个功能")


class Foo:
    def f1(self):
        super().f1()
        print("3个功能")

class Info(Foo,Base):
    pass

obj=Info()
obj.f1()
# 正确执行

# obj=Foo()
# obj.f1()报错,因为类中的 super() 表示的是当前继承顺序的下一个。并不是单单的只当前类的父类
  • super() 表示的是当前继承顺序的下一个。并不是单单的只当前类的父类

3.特殊成员

3.1 常见的双下滑线方法

# -*- coding: utf-8 -*-
'''
@Time    : 2022/1/23 20:41
@Author  : ziqingbaojian
@File    : 06.特殊成员.py
'''
class Foo:
    # 初始化方法  类名()自动执行
    def __init__(self,name,age):
        print("对象初始化开始")
        self.name=name
        self.age=age
    # 对象() 自动执行
    def __call__(self, *args, **kwargs):
        print(args,kwargs)

    # 对象[xxx]自动执行
    def __getitem__(self, item):
        print(item)
        return 1

    # 对象[xxx]=11自动执行
    def __setitem__(self, key, value):
        print(key,value)
        # 本方法没返回值

    def __delitem__(self, key):
        print(1)

    # 实现对象加对象的运算
    def __add__(self, other):
        return self.age+other.age


    def __enter__(self):
        print("可以使用 with 上下文管理,返回值被 as 后面的值接收")
        return 123

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(456)

obj1=Foo("啊哈",20)
obj1(1,23,3,k1="12")
res=obj1['123']
print(res)
obj1['k1']="v1"
obj1.__delitem__('123')
list
with obj1 as f:
    print(f)
    print("执行中")

image-20220123210008557

image-20220123202514799

3.2 构造方法

class Foo:
    def __init__(self,name):
        self.name=name
        print(2)
    def __new__(cls, *args, **kwargs):
        '''
        返回一个空的对象的供 init 进行初始化赋值
        :param args:
        :param kwargs:
        '''
        print(1)
        return object.__new__(cls)

obj=Foo('0')

image-20220123203842467

说明:

__init__一般称做初始化方法,__new__是真正创建对象的方法。是两个方法组成了类似与其他语言中的构造方法。

3.3 常见特殊方法的使用

  1. __dict__方法
  • class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    obj=Foo('章北海','230')
    print(obj.__dict__)#将实例变量以字典的形式返回
    
  • image-20220123211055754

  • 补充:

    • image-20220123211850447
    • 类.__dict__,会返回包括函数在内的成员信息,使用较少。
  1. __str__方法
  • class Foo:
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def __str__(self):
            return "打印对象我就执行"
    obj=Foo('章北海','230')
    print(obj)
    
  • image-20220123211259108

  • 类似与 Java中的toString()方法。

  • 补充__repr__方法

    • image-20220123211520197
    • __str__内部调用了__repr__。当类中没有__str__,但是有__repr__,打印对象时 就会执行。一般使用__str__方法较多

4.类的约束

4.1 主动抛出异常

class Foo:
    def send(self):
        # 如果抛出异常,则子类如果要调用则必须重写该方法
        raise NotImplemented(".send() must be overrideen")
    def func(self):
        print("正常执行")
class Bar(Foo):
    pass
obj=Bar()
obj.func()
obj.send()

image-20220126204449752

image-20220126204644594

4.2 抽象类和抽象方法

  • 补充:

    • Python 语言中不包含接口的数据类型,但是包含抽象类,和抽象方法。
    • Java 中包含抽象类和抽象方法,且接口中的方法必须是抽象方法。
  • from abc import ABCMeta,abstractmethod
    
    
    class Foo(metaclass=ABCMeta):
    
        def func(self):
            print(123)
    
        @abstractmethod
        def send(self):
            pass
    
    
    class Bar(Foo):
        def send(self):
            print("Hello world")
    obj= Bar()
    obj.send()
    
  • image-20220126210226974

  • 说明:在 Python 语言中一般会使用第一种方式NotImplemented异常进行处理,而不定义相关的抽象类,抽象类与抽象方法不常用。

5.多继承的补充

  • 默认:先找左边的再找右面的父类。
class A(object):
    pass

class B(object):
    def f1(self):
        print("B.f1")

class C(A,B):
    pass

obj=C()
obj.f1()

5.1 经典类和新式类

  • python2.2

    • 经典类:
    • 新式类:如果自己或自己的前辈只要有人继承 object,那么此类就是新式类。
  • python3 中全部都是新式类。

  • 区别:查找流程不同。

    • 经典类:一条到走到黑;深度优先
    • 新式类:采用 C3 算法。
  • 补充:

    查看继承关系。

    # 语法:类.__mro__
    print(E.__mro__)
    

    image-20220126212700559

    • 注意事项:super是遵循__mro__执行顺序。
    • Python2 中不包含__mro__方法。

5.2 C3 算法

image-20220126214450397

  • 简单新式类(记忆),复杂的时候使用C3算法。
    • image-20220126214315246
posted @ 2022-01-26 21:50  紫青宝剑  阅读(92)  评论(0编辑  收藏  举报