欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)

程序员文章站 2022-06-15 12:45:49
原创:叫我詹躲躲来源:简书链接:python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)致谢:感谢求知教育提供的视频教程1.单继承## 封装,继承和多态## 1.封装1、满足把内容封装到某个地方,另一个地方去调用封装的内容2、使用初始化构造方法,或者使用self获取封装的内容## 2.继承子类继承父类的属性和内容1.1单继承示例class Animal: def eat(self): print('吃饭了') pass...

原创:叫我詹躲躲
来源:简书
链接:python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)
致谢:感谢求知教育提供的视频教程

1.单继承

## 封装,继承和多态
## 1.封装
1、满足把内容封装到某个地方,另一个地方去调用封装的内容
2、使用初始化构造方法,或者使用self获取封装的内容

## 2.继承
子类继承父类的属性和内容

1.1单继承示例

class Animal:
    def eat(self):
        print('吃饭了')
        pass

    def drink(self):
        print('喝水了')
        pass


class Dog(Animal):
    def wwj(self):
        ## 子类独有的实现
        print('小狗汪汪叫')
        pass

class Cat(Animal):
    def mmj(self):
        ## 子类独有的实现
        print('小猫喵喵叫')
        pass

d1 = Dog()
d1.eat()

d2 = Cat()
d2.eat()

## 总结:所以对于面向对象的继承来说,可以极大的提升效率,减少重复代码

2.多继承

class Shenxian:
    def fly(self):
        print('神仙会飞')
    pass

class Monkey:
    def chitao(self):
        print('猴子喜欢吃桃')
    pass

class Sunwukong(Shenxian,Monkey):
    pass

swk = Sunwukong()
swk.fly()
swk.chitao()

2.1 注意方法重名:

## 多个父类存在相同的方法,该调用哪一个
class D(object):
    def eat(self):
        print('D.eat')
    pass

class C(object):
    def eat(self):
        print('C.eat')
    pass


class B(D):
    pass

class A(B,C):
    pass

a = A()
a.eat
print(A.__mro__) ##显示类的继承顺序
<class '__main__.A'>,
<class '__main__.B'>,
<class '__main__.D'>,
<class '__main__.C'>,
<class 'object'>
## 执行顺序应该是 去A里面查找,找第一个父类,A中没有的话,去B中查找,,B类中没有,C类中没有,去D类中查找;

2.2案例 简洁继承

class Grandfather():
    def eat(self):
        print('吃的方法')
        pass
    pass

class Father(Grandfather):
    pass

class Son(Father):
    pass

son = Son()
print(Son.__mro__)

## <class '__main__.Son'>,
## <class '__main__.Father'>,
## <class '__main__.Grandfather'>,
## <class 'object'>

2.3重写父类方法

class Grandfather():
    def eat(self):
        print('吃的方法')
        pass
    pass

class Father(Grandfather):
    ## 覆盖了父类的方法
    def eat(self):
        print('爸爸经常吃海鲜')
    pass

class Son(Father):
    pass

son = Son()
print(Son.__mro__)

## 定义跟父类相同的方法,可以实现覆盖和重写父类的方法

2.4重写初始化方法

class Grandfather():
    def __init__(self,name):
        self.name = name
        pass
    def eat(self):
        print('吃的方法')
        pass
    pass

class Father(Grandfather):
    def __init__(self):
        pass
    ## 覆盖了父类的方法
    def eat(self):
        print('爸爸经常吃海鲜')
    pass

class Son(Father):
    pass

son = Son()
print(Son.__mro__)

2.5调用父类初始化方法

class Father:
    def __init__(self,name):
        self.name = name
        pass

    ## 覆盖了父类的方法
    def eat(self):
        print('爸爸经常吃海鲜')
    pass

class Son(Father):
    def __init__(self,name):
        Father.__init__(self,name) ##调用父类的方法,可以具备name属性
        ## 或者
        ## super.__init__(name) ##也可以这样写
        self.age = 90 ## 添加新的实例方法
        self.sex = '男'
        pass
    pass

son = Son('hello')

2.6 调用父类的方法

class Father:
    def __init__(self,name):
        self.name = name
        pass

    ## 覆盖了父类的方法
    def eat(self):
        print('父类的吃方法')
    pass

class Son(Father):
    def __init__(self,name):
        Father.__init__(self,name) ##调用父类的方法,可以具备name属性
        ## 或者
        ## super.__init__(name) ##也可以这样写
        self.age = 90 ## 添加新的实例方法
        self.sex = '男'
        pass
    pass

    def __str__(self):
        print('{}'.format(self.name))
        pass

    def eat(self):
        super().eat() ##调用父类的方法
        print('子类的吃方法')
        pass

son = Son('詹躲躲')
son.eat()

## 父类的吃方法
## 子类的吃方法

3 多态

同一种行为,对于不同子类【对象】有不同的实现方式

3.1 要想实现多态,必须有两个前提

1.继承:发生在父类和子类之间

2.重写:子类重写父类的方法

3.1 案例演示

class Animal:
    ## 基本类
    def say(self):
        print('动物类')
        pass
    pass

class Duck(Animal):
    ## 子类 派生类
    def say(self):
        print('鸭子类')
        pass
    pass

class Dog(Animal):
    ## 子类 派生类
    def say(self):
        print('小狗类')
        pass
    pass

## duck1 = Duck()
## duck1.say()

## dog = Dog()
## dog.say()


def commonIvoke(obj):
    ## 统一调用
    obj.say()

## 循环统一调用
listObj = [Duck(),Dog()]
for item in listObj:
    commonIvoke(item)

## 在定义时的类型跟调用时不一样的时候,称为多态。

3.2 多态的好处

1.增加程序的灵活性

2.增加程序的扩展性

4.类属性和实例属性

## 类属性:就是类对象拥有的属性,它被所有类对象的实例对象所共有,类对象和实例对象可以访问。
## 实例属性:实例对象所拥有的属性,只能通过实例对象访问。

class Student:
    ## 类属性
    name = '叫我詹躲躲'
    def __init__(self,age):
        self.age = age
        pass
    pass

lm = Student(18)

## 通过实例对象去访问类属性
print(lm.name)
print(lm.age)

## 通过类对象去访问
print(Student.name)
print(Student.age)

## 总结
## 类属性:类对象和实例对象都可以访问
## 实例属性:只能由实例属性访问

## 所有的实例对象指向同一类对象
## 实例对象去修改类属性 不能修改
## 类对象可以修改类属性 可以修改

5.类属性和静态方法

## 装饰器@classmethod
class Person:
    country = 'china'

    ## 类方法 用classmethod修饰
    @classmethod
    def get_country(cls):
        return cls.country ## 访问类属性
        pass
    @classmethod
    def change_country(cls):
        cls.country = 'America'
    pass

## 通过类对象去引用
print(Person.get_country())
print(Person.change_country())
print(Person.get_country())

5.1 静态方法

class Person:
    country = 'china'

    ## 类方法 用classmethod修饰
    @classmethod
    def get_country(cls):
        return cls.country ## 访问类属性
        pass
    @classmethod
    def change_country(cls):
        cls.country = 'America'
        pass
    @staticmethod
    def get_data():
         return Person.country
    pass

## 通过类对象去引用
print(Person.get_country())
print(Person.change_country())
print(Person.get_country())
print(Person.get_data())

一般不会通过是实例对象去访问静态方法

由于静态方法主要存放逻辑方法,本身与类以及实例没有交互,也就是不会涉及类中方法和属性的操作

根据资源能够有效的利用

5.2求系统当前的时间

import time
class sys_time:
    def __init__(self,hour,min,second):
        self.hour = hour
        self.min  =min
        self.second = second

    @staticmethod
    ## 独立的功能
    def show_time():
        return time.strftime('%H:%M:%S',time.localtime())
print(sys_time.show_time())
## 15:15:44

5.3 总结

1.类方法的第一个参数是类对象,cls进而去引用类对象的属性和方法

2.实例方法的第一个参数是实例属性,若存在相同的实例属性或者方法,实例属性优先级最高

3.静态方法不需要额外的参数,若需要引用属性。,则可以通过类对象或者实例对象去引用即可,必须使用装饰器@staticmethod装饰

6.私有化

6.1 私有化属性

## 私有属性 以__开头,声明为属性私有,不能在类的外部被使用或者直接访问。

class Person(object):
    def __init__(self):
        self.__name = '叫我詹躲躲' ## 私有化
        self.age = '21'
    pass
    def __str__(self):
        return '{}的年龄是{}'.format(self.__name,self.age)

person = Person()
## print(person.__name) ##报错
print(person) ##可以访问
## 叫我詹躲躲的年龄是21

## 私有属性,不能被子类继承

6.2私有化方法

class A(object):
    def __eat(self):
        print('吃饭')
        pass
    pass

    def run(self):
        print('跑步')
        pass
    pass

b = A()
b.__eat() ## 报错
b.run() ## 跑步

7.property方法

属性函数

class A(object):
    def __init__(self):
        self.__name = 18

    def __eat(self):
        return self.__name
        pass
    pass

    def run(self):
        print('跑步')
        pass
    pass

    age = property(__eat, run)


b = A()
print(b.age)  ## 报错
b.run()  ## 跑步

7.1 @age.setter ##修改属性

class A(object):
    def __init__(self):
        self.__name = 18

    def __eat(self):
        return self.__name
        pass
    pass

    def run(self):
        print('跑步')
        pass

    @property ##添加属性标识
    def age(self):
        return self.__name
    pass

    @age.setter ##修改属性
    def age(self,params):
        self.age  = params
        pass
    pass

p1 = A()
print(p1.age) ## 18
p1.age = 16
print(p1.age)

8. __new__方法

作用:创建并返回一个实例对象,如果__new__只调用了一次,就会得到一个对象。继承自object的新式类,才有new这一魔术方法。

8.1 注意事项

 1.__new__是一个实例化调用的第一个方法
 2.__new__至少必须有一个参数 cls,代表要实例化的类,此参数在实例化时由python解释器提供,其他的参数是直接传递给__init__方法
 3.__new__决定是否使用该__init__方法,因为__new__可以调用其他的类的构造方法或者返回实例对象作为类的实例,如果__new__没有返回实例,则__init__不会被调用
 4.在__init__方法中,不能调用自己的__new__方法,return cls__new__(cls),否则会报错。
class A(object):
    def __init__(self):
        print('__init__执行了')
        pass
    pass

    def __new__(cls,*args,**kwargs):
        return super().__new__(cls,*args,**kwargs)
        pass
    pass

a = A()
print(a)

__init__执行了
<__main__.A object at 0x00000291F97D5160>

## 当__new__返回的时候 __init__才会显示

9.单例模式

9.1 确保一个类只有一个实例存在,使用__new__

class DataBaseClass(object):
    def __new__(cls,*args,**kwargs):
        ## cls._instance = cls.__new__(cls) ##不能使用自己的new方法
        if not hasattr(cls,'_instance'):
            cls._instance = super().__new__(cls,*args,**kwargs)
        return cls._instance
        pass
    pass

db1 = DataBaseClass()
db2 = DataBaseClass()
db3 = DataBaseClass()
print(id(db1))
print(id(db2))
print(id(db3))

## 三个指向的内存地址都一样的
## 1852298514784
## 1852298514784
## 1852298514784

10 错误和异常处理

try:
    ## 可能出现错误的代码块
except:
     ## 出错之后执行的代码块
else:
     ## 没有出错的代码块
finally:
    ## 不管有没有出错,都会执行

10.1 错误和异常处理示例

try:
    ## 可能出现错误的代码块
    li = [1,2,3]
    ## print(li[10])
    print(1/0)

except IndexError as msg:
    ## 出错之后执行的代码块
    print(msg)

except ZeroDivisionError as msg:
    ## 出错之后执行的代码块
    print(msg)

else:
    ## 没有出错的代码块
    print('没有出错了')
finally:
    ## 不管有没有出错,都会执行
    print('出错了')


## 用一个try可以捕获多个不同类型的异常

10.2 使用 Exception处理所有错误

try:
    print(b)
except Exception as result:
    print(result)
else:
    print('出错了')
finally:
    print('出错了')

10.3在合适的层次去捕获

def A(s):
    return s/int(s)
    pass


def B(s):
    return A(s)/2
    pass


def main():
    try:
        B(0)
    except Exception as result:
        print(result)

main()

在合适的位置进行错误捕获

division by zero

10.4 异常运行机制

1、解释器会查找相应的异常捕获类型
2、不断传递给上层,没有找到异常处理,会退出

11.自定义异常类型

class ToolongException(Exception):
    def __init__(self, len):
        self.len = len

    def __str__(self):
        return '输入的长度是'+str(self.len)+'长度,超出长度了'

def name_test():
    name = input('输入名字')
    try:
        if len(name)>5:
            raise ToolongException(len(name))
        else:
            print(name) 
    except ToolongException as result:
        print(result)
    else:
        print('没有出错了')


name_test()

##输入的长度是13长度,超出长度了 

12 动态添加属性和方法


import types

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        pass
    pass

    def __str__(self):
        return '{}今天{}岁了'.format(self.name, self.age)
        pass
    pass


zhz = Student('詹躲躲', 25)
zhz.wight = 60


def dymicMethod(self):
    print('{}体重是{}'.format(self.name,self.wight))
    pass

## 动态添加属性
print(zhz.wight)

## 类添加属性
Student.pro = '计算机科学'
## 实例可以访问
print(zhz.pro)

## 动态添加实例方法
## import types
zhz.printInfo = types.MethodType(dymicMethod,zhz)
zhz.printInfo()

## 詹躲躲体重是60

13 动态绑定类方法

import types

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        pass
    pass

    def __str__(self):
        return '{}今天{}岁了'.format(self.name, self.age)
        pass
    pass


zhz = Student('詹躲躲', 25)
zhz.wight = 60


def dymicMethod(self):
    print('{}体重是{}'.format(self.name,self.wight))
    pass

## 动态绑定类方法
@classmethod
def classTest(cls):
    print('类方法')
    pass

## 动态绑定静态方法
@staticmethod
def staticTest():
    print('静态方法')
    pass

13.1.动态添加属性

print(zhz.wight)

13.2.类添加属性

Student.pro = '计算机科学'
## 实例可以访问
print(zhz.pro)

13.3.动态添加实例方法

## import types
zhz.printInfo = types.MethodType(dymicMethod,zhz)
zhz.printInfo()

13.4.动态绑定类方法

Student.testMethod = classTest
Student.testMethod()

13.5.动态绑定类方法 实例调用

zhz.testMethod()

13.6.动态绑定静态方法

Student.statictest = staticTest
Student.statictest()

13.7.动态绑定静态方法 实例调用

zhz.statictest()

14._slots_属性

class Student(object):
    __slots__ = ('name', 'age', 'score')

    def __str__(self):
        return "{},{}".format(self.name, self.age)

xw = Student()
xw.name = '叫我詹躲躲'
xw.age = 25
## print(xw.__dict__)
## {'name': '叫我詹躲躲', 'age': 25}

xw.s11  = '1212'

#### 报错
print(xw)

子类未声明 slots,不会继承父类的__slots__,此时子类可以随意的属性赋值

子类声明了,范围为 子类+父类的范围

15.题目练习 一

15.1 python new的方法和作用是什么?

用来创建实例对象,只有继承了object的话,才有这个方法。

15.2 什么是单例模式,适用于什么场景?

要求一个类有且只有一个实例,并且提供了全局的访问点。日志插入logger,网站计数器,权限验证模块,window资源管理器,系统回收站,数据库连接池

15.3 私有化方法和私有化属性在子类中能否继承?

不能的

15.4 在python中什么是异常?

程序在执行中出现的异常。

15.5 python中如何处理异常?

分别根据异常的类型去处理

15.6 python中异常处理的一般格式,可以使用伪代码描述?

##  try:
##     正常操作
## except:
##     ##....
## else:
##     ##....
## finally:

##     ##...

15.7 __slots__的作用

限制属性的随意输入,节省内存空间

15.8 私有化的属性的作用?

保护数据,封装性的体现

15.9 在类外是否修改私有属性?

不可以直接修改,通过方法去实现,可以借助property

15.10 如果一个类,只有指定的属性或者方法能被外部修改,该如何限制?

对属性进行私有化

16 题目练习二

16.1 定义一个person类,类中要有初始化方法,方法中要有人名,年龄两个私有属性

提供获取用户信息的函数,提供设置私有属性的方法,设置年龄在0-120岁中间,如果不在这个范围,不能设置成功

class Person:
    def __init__(self,name,age):
        self.__name = name
        self.__age = age
        pass
    pass

    def GetUserInfo(self):
        return "{}的年龄为{}".format(self.__name,self.__age)
        pass
    pass

    def __str__(self):
        return "{}的年龄为{}".format(self.__name,self.__age)

    def setAge(self,age):
        if age>0 and age<120:
            self.__age = age
        else:
            pass
        
person = Person('詹躲躲',19) 
print(person.GetUserInfo())
## 詹躲躲的年龄为19

print(person.setAge(30))
print(person.GetUserInfo())
## 詹躲躲的年龄为30

16.2 请写一个单例模式

class DataBaseClass(object):
    def __new__(cls,*args,**kwargs):
        ## cls._instance = cls.__new__(cls) ##不能使用自己的new方法
        if not hasattr(cls,'_instance'):
            cls._instance = super().__new__(cls,*args,**kwargs)
        return cls._instance
        pass
    pass

db1 = DataBaseClass()
db2 = DataBaseClass()
db3 = DataBaseClass()
print(id(db1))
print(id(db2))
print(id(db3))

16.3 创建一个类,并定义两个私有化属性,提供一个获取属性的方法。利用property属性给调用者提供调用

class Student:
    def __init__(self, name, score):
        self.__name = name
        self.___score = score

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    def __str__(self):
        return self

    def __call__(self, *args, **kwargs):
        print(self.name)
        pass
    pass

xm = Student('詹躲躲',98)
xm.__call__()

xm.name()

16.4 创建一个Animal类。实例一个cat对象,给cat 绑定一个run方法,给类绑定一个类属性color

import types
class Animal:
    pass

def run(self):
    print('小猫')

cat = Animal()
cat.run = types.MethodType(run,cat)
cat.run()

Animal.color = 'red'
print(cat.color)

def info():
    print('ok')

Animal.info = info
Animal.info()

原创:叫我詹躲躲
来源:简书
链接:python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)
致谢:感谢求知教育提供的视频教程

本文地址:https://blog.csdn.net/weixin_43779957/article/details/107270956