Python面向对象

类的空间问题

添加对象或类的属性

添加对象或类的属性哪里(类__init__方法中、类方法中、类外)都可以添加。

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

    def func(self,sex):
        self.sex = sex
# 类外面可以:
obj = A('barry')
obj.age = 18
print(obj.__dict__)  # {'name': 'barry', 'age': 18}

# 类内部也可以:
obj = A('barry') # __init__方法可以。
obj.func('男')  # func 方法也可以。

对象以及类查询"名字"的顺序

对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->…

类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> …

上面的顺序都是单向不可逆,类名不可能找到对象的属性。

类与类之间的关系

依赖关系

将一个类的对象或者类名传到另一个类的方法使用. 这种关系比较弱。

组合(关联、聚合)关系

关联关系, 其实就是 我需要你. 你也属于我

组合:将一个类的对象封装到另一个类的对象的属性中,就叫组合。

继承

继承分为单继承和多继承

  • python中类的分类

这里需要补充一下python中类的种类(继承需要): 在python2x版本中存在两种类.: ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写. ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。 python3x版本中只有一种类: python3中使⽤的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object类。

单继承

  1. 类名.对象执行父类方法
  2. 执行顺序
    • 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
    • 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
  3. 同时执行类以及父类方法
    • 子类方法中父类.func(对象,其他参数)
    • super().func(参数)

多继承

一个类继承多个类

  • 经典类 沿用深度优先算法
    1. 从左至右,依次查找。
    2. 每次都选取节点的最左边,一直找到头,如果没有,返回上一个节点在查询其他路线。
    3. 如果上一个节点没有其他路线或者都已经查询完毕,再返回上一个节点,直至遍历完所有的节点
  • 新式类 沿用c3算法 MRO

super()

  • 示例一
class A:
    def f1(self):
        print('in A f1')
    
    def f2(self):
        print('in A f2')


class Foo(A):
    def f1(self):
        super().f2()
        print('in A Foo')
        
        
obj = Foo()
obj.f1()
  • 示例二
class A:
    def f1(self):
        print('in A')

class Foo(A):
    def f1(self):
        super().f1()
        print('in Foo')

class Bar(A):
    def f1(self):
        print('in Bar')

class Info(Foo,Bar):
    def f1(self):
        super().f1()
        print('in Info f1')

obj = Info()
obj.f1()

'''
in Bar
in Foo
in Info f1
'''
print(Info.mro())  # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]
  • 示例三
class A:
    def f1(self):
        print('in A')

class Foo(A):
    def f1(self):
        super().f1()
        print('in Foo')

class Bar(A):
    def f1(self):
        print('in Bar')

class Info(Foo,Bar):
    def f1(self):
        super(Foo,self).f1()
        print('in Info f1')

obj = Info()
obj.f1()

封装

将属性写到__init__

多态

同样名称的方法在不同的子类中会有不同的行为

同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = “太白”, 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。

对类的约束

  1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
  2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
  • 方式一:
class Payment:
    """
    此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
    """
    def pay(self,money):
        raise Exception("你没有实现pay方法")

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay(Payment):
    def pay(self,money):
        print('使用阿里支付%s元' % money)

class Wechatpay(Payment):
    def fuqian(self,money):
        print('使用微信支付%s元' % money)


def pay(obj,money):
    obj.pay(money)

a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a,100)
pay(b,200)
pay(c,300)
  • 方式二:引入抽象类的概念
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):   
# 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethod
    def pay(self):pass  # 抽象方法

class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元'%money)

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付了%s元'%money)

class Wechatpay(Payment):
    # def pay(self,money):
    #     print('使用微信支付了%s元'%money)
    def recharge(self):pass

def pay(a,money):
    a.pay(money)

a = Alipay()
a.pay(100)
pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
q = QQpay()
q.pay(100)
pay(q,100)
w = Wechatpay()
pay(w,100)   # 到用的时候才会报错

抽象类和接口类做的事情 :建立规范,只要子类继承了我写的这个抽象类,实例化对象时就会报错。

类的私有成员

对于每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

类内部

派生类

公有类的静态属性

可以访问

可以访问

可以访问

公有方法

可以访问

可以访问

可以访问

私有类的静态属性

不可以访问

可以访问

不可以访问

私有方法

不可以访问

可以访问

不可以访问

对象属性

对象

类内部

派生类

公有对象属性

可以访问

可以访问

可以访问

私有对象属性

不可以访问

可以访问

不可以访问

对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.

类的其他成员

类方法

使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);

调用:实例对象和类对象都可以调用。

class Student:
    
    __num = 0
    def __init__(self,name,age):
        self.name = name
        self.age= age
        Student.addNum()  # 写在__new__方法中比较合适,但是现在还没有学,暂且放到这里
        
    @classmethod
    def addNum(cls):
        cls.__num += 1

    @classmethod
    def getNum(cls):
        return cls.__num



a = Student('太白金星', 18)
b = Student('barry', 18)
print(Student.getNum())

静态方法

定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;

调用:实例对象和类对象都可以调用。

静态方法是类中的函数,不需要实例化。可以理解为,静态方法是个独立的、单纯的函数,仅仅托管于某个类的名称空间中,便于使用和维护。

import time

class TimeTest(object):
    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())


print(TimeTest.showTime())
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)

属性

property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的时候运行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的时候运行我啊')

#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

#或者:
class Foo:
    def get_AAA(self):
        print('get的时候运行我啊')

    def set_AAA(self,value):
        print('set的时候运行我啊')

    def delete_AAA(self):
        print('delete的时候运行我啊')
    AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应

f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

isinstance

  • isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象 class A: pass class B(A): pass obj = B() print(isinstance(obj,B)) print(isinstance(obj,A)) isinstance
  • issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类 class A: pass class B(A): pass class C(B): pass print(issubclass(B,A)) print(issubclass(C,A)) issubclass

反射

python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

Python实现自省的函数hasattrgetattrsetattrdelattr

应用于对象的反射

class Foo:
    f = '类的静态变量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#检测是否含有某属性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

print(getattr(obj,'aaaaaaaa','不存在啊')) #报错

#设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,则报错

print(obj.__dict__)

应用于类的反射

与对象基本相同

反射的作用

更优雅的写代码?

class User:
    def login(self):
        print('欢迎来到登录页面')
    
    def register(self):
        print('欢迎来到注册页面')
    
    def save(self):
        print('欢迎来到存储页面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user,choose): #如果user存在choose这个属性
        func = getattr(user,choose)#取这个属性并赋值给func变量
        func()#执行
    else:
        print('输入错误。。。。')

异常处理

AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的

基本语法:

try:
     被检测的代码块
except 异常类型:
     try中一旦检测到异常,就执行这个位置的逻辑

多分支+万能异常

dic = {
    1: login,
    2: register,
    3: dariy,
    4: article,
    5: comment,
}
print('''
    欢迎访问博客园系统:
    1,登录
    2,注册
    3,访问日记页面
    4,访问文章页面
    5,访问评论页面
''')
try:
    choice = int(input('请输入:'))
    dic[choice]()
# if choice.isdigit():
#     if
#
# else:
#     print('请输入数字...')
except ValueError:
    print('请输入数字....')
except KeyError:
    print('您输入的选项超出范围...')
except Exception as e:
    print(e)
    • try…except…else组合 与循环中的else比较类似,try代码中,只要出现了异常,则不会执行else语句,如果不出现异常,则执行else语句。 比如我们完成一个转账功能的代码,需要一个转账给另一个人,然后另一个人确认收到才算是转账成功,我们用伪代码写一下,他就可以用在这个地方:
# 伪代码
try:
    print('扣第一个人钱')
    ...
    print('给第二个人加钱')
except ValueError:
    print('必须输入数字。。。')

else:
    print('转账成功')
  • Try…excet…finally组合 finally这个用法比较有意思,他是在捕获异常发生之前,先执行finally的代码,有点未卜先知的意思。
    • 如果出现异常并且成功捕获了,finally会在try中最后执行。
try:
    dic = {'name': '太白金星'}
    print(dic[1])

except KeyError:
    print('出现了keyError错误....')

finally:
    print('正常执行')
  • 如果出现异常但是没有成功捕获,finally会在异常发生之前执行。
try:
    dic = {'name': '太白金星'}
    print(dic[1])

except NameError:
    print('出现了NameError错误....')

finally:
    print('异常发生之前,先执行我')
  • finally用在哪里呢?
    1. 关闭文件的链接链接,数据等链接时,需要用到finally。
f = open('file',encoding='utf-8')
try:
    '''各种操作'''
    print(f.read())
    '''但是发生错误了, 此时没关闭文件句柄,所以'''

finally:
    f.close()
  1. 函数中,finally也会在return之前先执行。
def func():
    try:
        return 1
    finally:
        print('finally')
func()
  1. 循环中,finally也会在return之前执行。
 while 1:
    try:
        break
    finally:
        print('finally')

一般就是收尾工作,在一些重要环节出错之前必须一定要做的比如关闭链接的问题时,最好是用上finally作为最后一道防线,收尾。

  • 主动出发异常 在类的约束中,我们已经用过此方法,主动发出异常
raise TypeError('类型错误')
  • 断言 表示一种强硬的态度,只要assert后面的代码不成立,直接报错,下面的代码就不让你执行。
# assert 条件
 
assert 1 == 1
 
assert 1 == 2
# 应用:
assert 条件
代码
代码
.......
  • 自定义异常 python中给你提供的一些错误类型并不是所有的,只是常见的异常,如果以后你在工作中,出现了某种异常无法用已知的错误类型捕获(万能异常只能捕获python中存在的异常),那么你就可以尝试自定义异常,只要继承BaseException类即可。
# assert 条件
 
assert 1 == 1
 
assert 1 == 2
# 应用:
assert 条件
代码
代码
.......
  • 异常处理正确的使用方式 有的同学会这么想,学完了异常处理后,好强大,我要为我的每一段程序都加上try…except,干毛线去思考它会不会有逻辑错误啊,这样就很好啊,多省脑细胞===》2B青年欢乐多 try…except应该尽量少用,因为它本身就是你附加给你的程序的一种异常处理的逻辑,与你的主要的工作是没有关系的 这种东西加的多了,会导致你的代码可读性变差,只有在有些异常无法预知的情况下,才应该加上try…except,其他的逻辑错误应该尽量修正

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 为你的好朋友添点评论

    想要为朋友来点评论就需要知道他的博客域名、appId、appKey和他所使用的机器是哪个地区的。

    Dreamy.TZK
  • 21错误与异常

    错误,指程序中的非正常运行状态,在其它编程语言中称为“异常”或“错误”。解释器会为每个错误情形创建并抛出一个Error对象,其中包含错误的描述信息。

    Dreamy.TZK
  • 05JavaScript函数

    利用JavaScript第二个特性(少传入不报错),我们可以在一个函数中实现多个不同的功能。

    Dreamy.TZK
  • python面向对象的多态-类相关内置函数-类内置魔法函数-迭代器协议-上下文管理-04

    首先强调,多态不是一种特殊的语法,而是一种状态,特性(多个不同对象可以相应同一个方法,长身不同的结果)

    suwanbin
  • Python第八周 学习笔记(1)

    bisect.bisect_left(a, x, lo=0, hi=len(a)) 查找在有序列表a中插入x的index,lo和hi用于指定列表的区间,默认是...

    py3study
  • python面向对象OOP入门

          面向对象编程不是python独有,几乎所有高级语言都支持;面向对象不管在那个语言中都有三大特性:即:封装、继承、多态;具体的本文主要讲python面...

    py3study
  • python 成员

    py3study
  • python3–面向对象–类

    老七Linux
  • python高级-面向对象特性(12)

    在现实生活中,继承一般指的是子女继承父辈的财产,在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫...

    Se7eN_HOU
  • 面向对象:反射,双下方法

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应...

    changxin7

扫码关注云+社区

领取腾讯云代金券