初学Python——面向对象(二)

一、抽象类、接口类和抽象接口

转自博客园魏恒https://www.cnblogs.com/weihengblog/p/8528967.html

(一)接口类

  什么是接口类?在继承中,我们可以声明某个子类继承自某基类,这个基类是个接口类,在接口类中定义了接口名(函数名)且并未实现接口的功能,子类继承接口类,并实现接口中的功能。这又叫做“接口继承”。

  接口继承实质上是规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。特点:1.做出良好的抽象类,2.规定兼容接口 3.调用者可以无需关心具体实现细节,可以一视同仁处理实现特定接口的所有对象。

#做出一个良好的抽象
class Payment(object):
    #规定了一个兼容接口
    def pay(self):
        pass

#微信支付
class WeChatPay(Payment):
    def pay(self,money):
        print(‘微信支付了%s‘%money)

#支付宝支付
class AliPay(Payment):
    def pay(self,money):
        print(‘支付宝支付了%s‘%money)

#苹果支付
class ApplePay(Payment):
    def pay(self,money):
        print(‘苹果支付了%s‘%money)

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

weixin = WeChatPay()
alipay = AliPay()
applepay = ApplePay()

#调用者无需关心具体实现细节,可以一视同仁的处理实现了特定接口的所有对象
pay(weixin,100)
pay(alipay,200)
pay(applepay,300)

(二)抽象类

什么是抽象类?

  与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

为什么要有抽象类?

  如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

  比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

  从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

  从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的

#一切皆文件
import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type=‘file‘
    @abc.abstractmethod #定义抽象方法,无需实现功能
        def read(self):
        ‘子类必须定义读功能‘
            pass

    @abc.abstractmethod #定义抽象方法,无需实现功能
        def write(self):
        ‘子类必须定义写功能‘
            pass

# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法

class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(‘文本数据的读取方法‘)

    def write(self):
        print(‘文本数据的读取方法‘)

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(‘硬盘数据的读取方法‘)

    def write(self):
        print(‘硬盘数据的读取方法‘)

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print(‘进程数据的读取方法‘)

    def write(self):
        print(‘进程数据的读取方法‘)

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)

(三)抽象类和接口类

  抽象类的本质还是类,指的是一组类的相似性,包括数据属性和函数属性,而接口强调函数属性的相似性。

  抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特征,可以用来实现归一化设计。

二、静态方法、属性方法、类方法

1.静态方法

  @staticmethod

  静态方法就是一个普通方法,不能访问实例变量与类变量,与类唯一的联系就是需要通过类名来调用这个方法,所以
  只是名义上归类管。私有方法不能作为静态方法,但受保护类可以作为静态方法。

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

    @staticmethod # 将eat变成了静态方法,作用是将此方法断绝与类的联系,变普通函数
    def eat(self):
        print(" is eating")

d = Dog("ChenRonghua")
d.eat()
# 这样运行会出错,要想不出错
1.调用时,d.eat(d)。已经断绝与类的联系,"self"需要手动传入
2.eat()方法去掉参数self

2.类方法

  @classmethod

  变成类方法后,方法内只能访问类变量,不能访问实例变量。

class Cat(object):
    name = "华仔"
    def __init__(self,name):
        self.name = name
        self.__person = None

    @classmethod # 类方法
    def eat(self,food):
        print(‘{0}吃{1}‘ .format(self.name,food))

c1 = Cat("小猫")

c1.eat("鱼")
# 输出结果显示,类方法没有使用实例变量,使用的是类变量

3.属性方法

  @property

  可以把一个方法变成静态属性。也就是将原本的方法变成了静态属性,不能传参数,不能修改属性值,也不能删除

先来看一下

class Cat(object):
    name = "华仔"
    def __init__(self,name):
        self.name = name
        self.person = None

    @property
    def talk(self):
        print("{0} is talking with {1}".format(self.name,self.person))

c1 = Cat("小猫")

c1.talk
#输出:小猫 is talking with None

  这时,想要对self.person进行修改是不可以的,会报错。

  若非要修改,也是可以通过特殊方法来修改的,

  #在上述代码的基础上加上如下代码(在原eat方法的下面,类的里面)
    @talk.setter   # 修改属性方法的值需要这样做
    def talk(self,person):
        print("{0} is talking with {1}".format(self.name,person))
        self.person = person

c1.talk = "Jack"
c1.talk   # 再次访问,发现真正修改了它
# 输出:
小猫 is talk with Jack

  同样,若非要删除,也可以

    @talk.deleter  # 删除属性方法的值需要这样做
    def talk(self):
        del self.person
        print("已删除talk")

del c1.talk
c1.talk # 删除后再访问运行出错!

  这时相信你会有个疑问,为什么还需要属性方法的存在呢?直接定义一个静态变量不就行了吗?属性方法和属性有什么不同呢?

  属性方法的本质还是方法(函数),只是变得特殊了,我们知道属性方法具有以下两点特征:

    1.属性方法内可以对内部属性进行访问

    2.属性方法不能被随意修改删除,防止误改误删,保证了安全性。

  在实际应用中,有这样的需求:已经写好了具有特定功能的方法,作用是返回一个数值。而要经过一系列的动作才能得到这个值,这显然不是变量可以完成的。用户调用它时只需要像对待静态变量一样就可以得到一个值,中间的过程用户不需要关心。

三、反射

  在实际应用中,我们需要根据用户输入来做出相应的工作,比如输入1调用a方法,输入2调用b方法,输入2调用c方法.....,这些我们可以用if else分支语句来判断并执行,但显而易见,如果用户输入的种类非常多,if else语句的代码量就非常可观了,不美观,也不便于维护。怎么办呢?

  1.需要用到反射函数hasattr()来判断对象是否有这个方法

  2.如果有这个方法,则可以用getatter()函数来找到对象方法的内存地址

  3.加上括号即可调用  

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

    def eat(self,name):
        print("{0} is eating {1}".format(self.name,name))

def bulk(self):
    print("{0} is yelling".format(self.name))

d = Dog("Alex")

chioce = input("请输入操作:").strip()
If hasattr(d,chioce) == True:
    fun = getattr(d,chioce)
    a = input("what does the dog want eating ?")
    fun(a)
else:
    setattr(d,chioce,bulk) # 将类外部的函数加入了类的内部
    v = getattr(d,chioce)
    v(d)

  so,什么叫反射?通过字符串来运行或修改程序运行时的状态、属性、方法

  一共有四个方法:

    1.hasattr(obj,str)  obj是对象,str是字符串,判断对象是否有此方法(属性),返回True或False

    2.getattr(obj,str)  obj是对象,str是字符串,返回对象中方法(属性)的内存地址

    3.setattr(x,y,z)     (x,y=z)x是对象,y是字符串,z是方法的内容,设置一个新的方法(属性),或修改方法(属性)

    4.delattr(obj,str)  obj是对象,str是字符串,删除属性(不能删除原有的方法?)

chioce = input("请输入操作:").strip()
setattr(d,chioce,18) # 创建属性并赋值
print(d.talk)
setattr(d,"name","Chen") # 修改已存在的name属性
print(d.name)

delattr(d,"name") # 删除name属性
#print(d.name)  # 报错

# 输入:talk
输出:
18
Chen
Chen is yelling

四、动态导入模块

  如何使用字符串导入模块呢?

  之前讲过一个方法,使用__import__()内置函数;第二个方法是动态导入模块

  • __import__()内置函数:
‘‘‘导入lib包,调用包下aa模块的text()函数‘‘‘
b = __import__("lib.aa")
b.aa.text()
"这是解释器内部用的,一般不建议用这个,建议用下面的"
#output:
from lib.aa.text()
  • 动态导入
vimport importlib
c = importlib.import_module("lib.aa")
"导入lib.aa。b 代表 lib.aa "
c.text()
#output:
from lib.aa.text()

五、异常处理

name = ["alex","jack"]
data = {}
try:
    a=5
    f = open("123","r")   #会触发异常Exception,这个包括了所有个异常
    name[3]         # 会触发异常indexError
    data["name"]  # 会触发异常KeyError
except KeyError as e:
    print("没有此信息",e)
except IndexError as e:
    print("列表索引超出范围",e)
except Exception as e:
    print("未知错误",e)
else: # 一切正常的情况下会执行后面的语句
    print("OK")
finally:
    print("不管有没有错误,都会执行的语句") #输出:

未知错误 [Errno 2] No such file or directory: ‘123‘
不管有没有错误,都会执行的语句

  上面的输出结果是因为,按照执行的顺序,首先执行打开文件出现异常,后面的语句没有被执行的机会。

  想要一条语句抓住两种错误,可以这样写:

try:
    name[3]
    data["name"]
except (KeyError,IndexError) as e:
    print("没有此信息",e)

  能抓住所有错误的写法:

try:
    name[3]
    data["name"]
except Exception as e: # 一劳永逸,无论出现什么错误都会异常处理
    print("出错了",e)

  有一种错误没办法抓住:缩进错误,例如

try:
    name1 = 10
     b = 20
except Exception as e:
    print("错误!")

# output:
 File "F:/Python Files/Learning Log/day7/异常处理.py", line 44
    b = 20
    ^
IndentationError: unexpected indent

断言:

class A(object):
    def __init__(self,name):
        self.name = name
a = A("Alex")
try:
    assert type(a.name) is str # 意为:断定A.name的类型是字符串
except AssertionError:
    print("is not str")

  断言的作用是:可以做一些检查,增强安全性

原文地址:https://www.cnblogs.com/V587Chinese/p/9304199.html

时间: 2024-10-16 03:58:43

初学Python——面向对象(二)的相关文章

初学Python(二)——数组

初学Python(二)——数组 初学Python,主要整理一些学习到的知识点,这次是数组. # -*- coding:utf-8 -*- list = [2.0,3.0,4.0] #计算list长度 print len(list) #第一个元素 print list[0] #最后一个元素 print str(list[-1]) list.append(2.4) list.insert(1,2.7) list.pop(1) list.insert(1,['sdf','sdfdf']) print

python面向对象二

1.1类的静态属性,类方法,类的静态方法 1.1.1静态属性(@property) 在类中: python内置的@property装饰器就是负责把一个方法(函数)变成属性来调用. class Student: def __init__(self,name,age,score): self.name = name self.age = age self.score = score @property def get_score(self): return self.score def learn(

python面向对象(二)

类的成员 类的成员可以分为三大类:字段.方法和属性 一.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 class foo: # 字段(静态字段,保存在类里) cc = '111' def __init__(self): # 字段(普通的字段,保存在对象里) self.name = 'mxz' def f1(self): print(self.name) class Province: # 静态字段 cou

Python 面向对象 二

通过此方法communicate  管道 日志模块logging python单独提供 re.split(规则,字符串,1)以第一个符合规则的进行分割. random 模块 将数字转换为字母char(65) = A __init__:构造方法,实例化的时候执行 经典类: 如: class N: pass 新式类: 如: class M(object): pass 一个类不管直接或间接的继承object类就是新式类.推荐使用新式类 两者区别: 继承:java.C# 不支持多继承,python 支持

初学Python(二)

五.变量与赋值 Python中的变量在声明时不需要指定其类型,它会根据你的赋值自动判断 对于数字和字符这种值类型的赋值,变量只是对它的引用,并不能直接删除其值(其实由于Python中的垃圾回收机制,你并不能真正删除任何东西,由Python自动判断它“没有人”了才会删除它) >>> a = 1 >>> b = a >>> print(a, b) 1 1 >>> a = 9 >>> print(a, b) 9 1 六.数

Python 面向对象(二) 特殊方法

一些Python特殊方法的汇总 __bases__              类的基类,返回元祖__base__                类的基类,也叫父类__call__                  '类名()',类名加括号调用时执行的语句__class__               表示当前操作的对象的类是什么__del__                   析构方法,对象在内存中被释放时,自动触发执行__dict__                  存储类或实例的所有属性

四十一、python面向对象二

A.成员: 1.字段:静态字段(每个对象都有同一字段),普通字典(每个对象都有不同的数据) 2.方法:静态方法(无需使用对象的内容),类方法,普通方法(使用对象中的数据) 3.特性:普通特性(将方法伪造成字段) 通过类去访问的有:静态字段,静态方法,类方法 通过对象去访问的有:普通字段,类的方法 自己的成员自己去访问 静态方法:没有self,前添加@staticmethod,即为静态方法(通过类去访问) 类方法:比静态方法多一个参数,该参数是为了显示哪个类,前添加@classmethod 特性:

Python自动化开发 - 面向对象(二)

本节内容 1.isinstance(obj,cls)和issubclass(sub,super) 2.反射 3.__setattr__,__delattr__,__getattr__ 一. isinstance(obj,cls)和issubclass(sub,super) 1.isinstance(obj,cls) 检查obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) # True 2.

初学 Python(十二)——高阶函数

初学 Python(十二)--高阶函数 初学 Python,主要整理一些学习到的知识点,这次是高阶函数. #-*- coding:utf-8 -*- ''''' 话说高阶函数: 能用函数作为参数的函数 称为高阶函数 ''' #函数作参 def f(x): return x*x #map函数为内置函数,意思为将第二个参数的list作用到f函数中 #最后的结果为一个list print map(f,[1,2,3,4,5]) #reduce函数为内置函数,意思将第二参数的序列作用到add函数值 #将结