面向对象

'''
class Person:   #类名
    country = "China"  # 创建这类的属性 #类属性:静态属性
    def __init__(self,name,blood,aggr,sex,money): #初始化方法,self是对象,必须传的参数
        self.name = name  #对象的属性
        self.blood = blood
        self.aggr = aggr
        self.sex = sex
        self.money = money
    def da(self,dog):    #方法,一般情况下必须传self参数,且必须写在第一个,后面还可以传其他参数,是自由的
        dog.blood -= self.aggr
        print("%s被%s打了,掉了%s的血"%(dog.name,self.name,self.aggr))
    def get_wuqi(self,wuqi):
        if self.money >= wuqi.price:
            self.money -= wuqi.price
            self.aggr += wuqi.aggr
            self.wuqi = wuqi
        else:
            print("余额不足,请充值")
class Dog:
    def __init__(self,name,blood,aggr,kind):
        self.name = name
        self.blood = blood
        self.aggr = aggr
        self.kind = kind
    def yao(self,person):
        person.blood -= self.aggr
        print("%s被%s打了,掉了%s的血" % (person.name, self.name, self.aggr))
class Wuqi:
    def __init__(self,name,price,aggr,njd):
        self.name = name
        self.price = price
        self.aggr = aggr
        self.njd = njd
    def dazhao(self,dog):
        if self.njd >0:
            dog.blood -= self.aggr*2
            self.njd -= 1
        if dog.blood>0:
            print("%s被打死了"%(dog.name))
print(Person.country)    #类名 可以查看类中的属性,不需要实例化就可以查看
xiaoli = Person("狗蛋",1000,100,"男",0)   #实例化 xiali是对象
zhu = Dog("猪猪侠",2000,10,"泰迪")        #对象 = 类名()
wuqi = Wuqi("打狗棒",1000,200,10)

print(xiaoli.__dict__) #查看所有属性
print(zhu.__dict__["name"]) #查看zhu的name属性值 可以看作是一个字典,属性对应的相当于字典的
                # "key",而属性值相当于字典的"value",对象的属性操作,可以适用字典的操作
print(wuqi.__dict__)
xiaoli.da(zhu)    #调用方法     类名.
zhu.yao(xiaoli)
xiaoli.get_wuqi(wuqi)
xiaoli.money += 1000
xiaoli.get_wuqi(wuqi)
xiaoli.da(zhu)
xiaoli.wuqi.dazhao(zhu)
print(zhu.blood)   #查看属性值
print(wuqi.njd)
View Code

组合 :一个对象的属性值是另外一个类的对象

xiaoli.wuqi 是 Wuqi类的对象

from math import pi
class Circle:
    def __init__(self,r):
        self.r = r
    def area(self):
        return self.r**2 * pi
    def perimeter(self):
        return 2*pi*self.r

class Ring:
    def __init__(self,outside_r,inside_r):
        self.outside_c = Circle(outside_r)
        self.inside_c = Circle(inside_r)
    def area(self):
        return self.outside_c.area() - self.inside_c.area()
    def perimeter(self):
        return self.outside_c.perimeter()+self.inside_c.perimeter()

# ring = Ring(20,10)
# print(ring.area())
# print(ring.perimeter())
组合练习
# 创建一个老师类
# 老师有生日
# 生日也可以是一个类
# 组合
class Birthday:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

class Course:
    def __init__(self,course_name,period,price):
        self.name = course_name
        self.period = period
        self.price = price

class Teacher:
    def __init__(self,name,age,sex,birthday):
        self.name = name
        self.age = age
        self.sex = sex
        self.birthday =birthday
        self.course = Course('python','6 month',2000)

b = Birthday(2018,1,16)
egg = Teacher('egon',0,'',b)
print(egg.name)
print(egg.birthday.year)
print(egg.birthday.month)
print(egg.course.price)
View Code

## 对象 = 类名()         》实例化
# 过程:
  # 类名() 首先 会创造出一个对象,创建了一个self变量
  # 调用init方法,类名括号里的参数会被这里接收
  # 执行init方法
  # 返回self
# 对象能做的事:
  # 查看属性
  # 调用方法
  # __dict__ 对于对象的增删改查操作都可以通过字典的语法进行
# 类名能做的事:
  # 实例化
  # 调用方法 : 只不过要自己传递self参数
  # 调用类中的属性,也就是调用静态属性
  # __dict__ 对于类中的名字只能看 不能操作
# 定义类
  # class
  # 函数 : 方法 动态属性 # 类中可以定义方法,方法都有一个必须传的参数self
  # 变量 : 类属性 静态属性 # 类中可以定义静态属性
# __init__方法 初始化方法
  # python帮我们创建了一个对象self
  # 每当我们调用类的时候就会自动触发这个方法。默认传self
  # 在init方法里面可以对self进行赋值
# self是什么 self拥有属性都属于对象
  #在类的内部,self就是一个对象
  # xiaoli = Person() #实例化
  # xiaoli.da(zhu) == Person.da(xiaoli,zhu) #对象调用方法:对象名.方法名 == 类名.方法名(对象名)
# 实例化
  # 对象 = 类(参数是init方法的)
  # 实例、对象 完全没有区别
# 对象查看属性
  # 对象.属性名
  # 对象调用方法
  # 对象.方法名(参数) #类名.方法名(对象名,参数)

一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
类属性的补充
# class Course:
#     language = "Chinese"
#     def __init__(self,teacher,course_name,period,price):
#         self.teacher = teacher
#         self.course_name = course_name
#         self.period = period
#         self.price = price
# print(Course.language)    #  查看类属性  Chinese
# Course.language = "English"  #修改类的属性  #类名.属性 = 新的属性名
# print(Course.language)   #  English
# python = Course("xiaoli","python","6 months",20000)
# linux = Course("zhu","linux","3 montths",13000)
# print(python.language)     # English
# python.language = "Chinese"   #相当于给对象python 添加了一个language属性
# print(python.language)    # Chinese
# print(linux.language)      #对象调用类的静态属性    # English

# class Course:
#     language = ["Chinese"]
#     def __init__(self,teacher,course_name,period,price,):
#         self.teacher = teacher
#         self.course_name = course_name
#         self.period = period
#         self.price = price
# print(Course.language)    #  查看类属性  ['Chinese']
# python = Course("xiaoli","python","6 months",20000)
# linux = Course("zhu","linux","3 montths",13000)
# print(python.language)  # ['Chinese']
# python.language[0] = "English"
# print(python.language)      #  ['English']
# print(linux.language)         #  ['English']
#
# # 类中的静态变量 可以被对象和类调用
# # 对于不可变数据类型来说,类变量最好用类名操作
# # 对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的
静态属性的补充

继承

 

class Animal:
#     def __init__(self,name,aggr,hp):
#         self.name = name
#         self.aggr = aggr
#         self.hp = hp
#     def eat(self):
#         print("吃药回血")
#         self.hp += 100
# class Dog(Animal):
#     def __init__(self,name,aggr,hp,kind):
#         Animal.__init__(self,name,aggr,hp)
#         self.kind = kind    #派生属性
#     def eat(self):    #如果既想实现新的功能也想使用父类原本的功能,还需要在子类中再调用父类
#         Animal.eat(self)
#         self.teeth = 2
#     def yao(self,person):        #派生方法
#         person.hp -= self.aggr
# class Person(Animal):
#     def __init__(self,name,aggr,hp,sex):
#         super().__init__(name,aggr,hp)    #等同于Animal.__init__(self,name,aggr,hp),新式类才有,py3 都是新式类
#         self.sex = sex
#     def gongji(self,dog):
#         dog.hp -= self.aggr
# p = Person("小利",100,100,"男")
# d = Dog("疯狗",2,500,"泰迪")
# print(Person.__bases__)  #查看 Person类的继承情况 #(<class '__main__.Animal'>,)
View Code

 

# # python3 -新式类# 没有继承父类默认继承object
# 父类中没有的属性 在子类中出现 叫做派生属性
# 父类中没有的方法 在子类中出现 叫做派生方法
# 只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
# 如果父类 子类都有 用子类的
# 如果还想用父类的,单独调用父类的:
# 父类名.方法名 需要自己传self参数
# super().方法名 不需要自己传self
# 正常的代码中 单继承 === 减少了代码的重复
# 继承表达的是一种 子类是父类的关系

多继承

 #class F:
#     def f(self):
#         print("F")
# class C(F):
#     def f(self):
#         print("C")
# class D(F):
#     def f(self):
#         print("D")
# class B(D,C):
#     def f(self):
#         print("B")
# b = B()
# b.f() # B  如果B类里的代码用pass,则找类D中的值,D离B进   B>D>C>A    广度优先 
砖石
# class E:
#     def f(self):
#         print("E")
# class C(E):
#     def f(self):
#         print("C")
# class D:
#     def f(self):
#         print("D")
# class B(D):
#     def f(self):
#         print("B")
# class A(B,C):
#     def f(self):
#         print("A")
# a = A()
# a.f() #  A  #  A>B>D>C>E 
漏斗
# class E:
#     def f(self):
#         print("E")
# class C(E):
#     def f(self):
#         print("C")
# class D:
#     def f(self):
#         print("D")
# class B(D):
#     def f(self):
#         print("B")
# class A(B,C):
#     def f(self):
#         print("A")
# a = A()
# a.f() #  A  #  A>B>D>C>E 
乌龟

继承原理

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

>>> A.mro() #等同于A.__mro__
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>]

 

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

继承小结

继承的作用

减少代码的重用
提高代码可读性
规范编程模式

几个名词

抽象:抽象即抽取类似或者说比较像的部分。是一个从具题到抽象的过程。
继承:子类继承了父类的方法和属性
派生:子类在父类方法和属性的基础上产生了新的方法和属性

抽象类与接口类

复制代码
1.多继承问题
在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口


2.方法的实现
在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
复制代码

钻石继承

新式类:广度优先
经典类:深度优先

 

# class A(object):
#     def func(self): print('A')
#
# class B(A):
#     def func(self):
#         super().func()
#         print('B')
#
# class C(A):
#     def func(self):
#         super().func()
#         print('C')
#
# class D(B,C):
#     def func(self):
#         super().func()
#         print('D')
# d = D()        #A>C>B>D
# d.func()
# # super 只在python3中存在
# # super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的
super()

 

继承有两种用途:

一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)  

二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

#接口类 单继承
# from abc import abstractmethod,ABCMeta
# class Pay(metaclass=ABCMeta):  #元类
#     @abstractmethod
#     def pay(self,money):
#         pass
# # 规范 :接口类或者抽象类都可以
# # 接口类 支持多继承,接口类中的所有的方法都必须不能实现 —— java演化来的
# # 抽象类 不支持多继承,抽象类中方法可以有一些代码的实现 —— java
# class Wechat(Pay):
#     def pay(self,money):
#         print("已经用微信支付了%s元"%money)
# class Ali(Pay):
#     def pay(self,money):
#         print("已经用支付宝支付了%s元"%money)
# class Apple(Pay):
#     def pay(self,money):
#         print("已经用苹果支付了%s元"%money)
# def s(pay_obj,money):  #统一支付入口
#     pay_obj.pay(money)
# ali = Ali()
# ali.pay(200)
# we = Wechat()
# we.pay(1)
# s(ali,10)
# s(we,123)

#接口类 多继承
# from abc import abstractmethod,ABCMeta
# class Swim_Animal(metaclass=ABCMeta):
#     @abstractmethod
#     def swim(self):
#        pass
# class Walk_Animal(metaclass=ABCMeta):
#     @abstractmethod
#     def walk(self):
#         pass
# class Fly_Animal(metaclass=ABCMeta):
#     @abstractmethod
#     def fly(self):
#         pass
#
# class Tiger(Swim_Animal,Walk_Animal):
#     def swim(self):
#         print("f")
#     def walk(self):
#         pass
#     def h(self):
#         print("s")
# t = Tiger()
# t.swim()


# 接口类  刚好满足接口隔离原则 面向对象开发的思想 规范
View Code

抽象类

什么是抽象类

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

为什么要有抽象类

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

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

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

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

在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)
复制代码

 

抽象类与接口类

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

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

在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念。

1.多继承问题

在继承抽象类的过程中,我们应该尽量避免多继承;
而在继承接口的时候,我们反而鼓励你来多继承接口

接口隔离原则:
使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

2.方法的实现

在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现

 


# 抽象类 : 规范
# 一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
# 多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中


# 抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
# java :
# java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
# 但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题

# python
# python中没有接口类 :
# python中自带多继承 所以我们直接用class来实现了接口类
# python中支持抽象类 : 一般情况下 单继承 不能实例化
# 且可以实现python代码

多态

多态

多态指的是一类事物有多种形态

动物有多种形态:人,狗,猪

复制代码
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')
复制代码

文件有多种形态:文本文件,可执行文件

复制代码
import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass

class Text(File): #文件的形态之一:文本文件
    def click(self):
        print('open file')

class ExeFile(File): #文件的形态之二:可执行文件
    def click(self):
        print('execute file')
复制代码

 

多态性

一 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)

多态性是指在不考虑实例类型的情况下使用实例

复制代码
在面向对象方法中一般是这样表述多态性:
向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。
也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
复制代码

 

多态性

复制代码
peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()
复制代码

 

鸭子类型

逗比时刻:

  Python崇尚鸭子类型,

# list tuple
# 不崇尚根据继承所得来的相似
# 我只是自己实现我自己的代码就可以了。
# 如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
# list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
# 优点 : 松耦合 每个相似的类之间都没有影响
# 缺点 : 太随意了,只能靠自觉

封装

# 广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
# 只让自己的对象能调用自己类中的方法
# 狭义上的封装 —— 面向对象的三大特性之一
# 属性 和 方法都藏起来 不让你看见

class Person:
    __key = 123       #私有静态属性
    def __init__(self,name,pwd):
        self.name = name
        self.__pwd = pwd      #对象私有属性
    def __get_pwd(self):          #私有方法
        return self.__pwd
    def s(self):                    #正常调用私有方法
        return self.__get_pwd()
p = Person("xiaoli",123456)
print(p.__dict__)        #查看对象p的属性值
print(p._Person__pwd)   #查看对象p的密码  _类名__属性名
print(Person._Person__key)     #查看Person类的私有静态属性
print(p.s())  #正常调用

# 所有的私有 都是在变量的左边加上双下划綫
# 对象的私有属性
# 类中的私有方法
# 类中的静态私有属性
# 所有的私有的 都不能在类的外部使用

class Foo:
    __key = '123'       # _Foo__key

class Son(Foo):
    print(Foo.__key)     # _Son__key

# 会用到私有的这个概念de场景
#1.隐藏起一个属性 不想让类的外部调用
#2.我想保护这个属性,不想让属性随意被改变
#3.我想保护这个属性,不被子类继承
# property
# 内置装饰器函数 只在面向对象中使用

#属性 查看 修改 删除
class Person:
    def __init__(self,name):
        self.__name = name
    @property      # 把属性伪装成一个方法 不能传参数
    def name(self):
        return self.__name
    @name.deleter     # 在外部调用同属性一样的方法名来删除属性,不能传参数   与del配合使用
    def name(self):
        del self.__name
    @name.setter        #在外部调用同属性名一样的方法来修改属性值,只可传一个值
    def name(self,new_name):
        self.__name = new_name
brother2 = Person('二哥')
brother2.name = 'newName'
del brother2.name
print(brother2.name)
@property
class Goods:
    __discount = 0.8
    def __init__(self,name,price):
        self.name = name
        self.__price = price
    @property
    def price(self):
        return self.__price * Goods.__discount
    @classmethod   # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
    def change_discount(cls,new_discount):  # 修改折扣
        cls.__discount = new_discount
apple = Goods('苹果',5)
print(apple.price)
Goods.change_discount(0.5)   # Goods.change_discount(Goods)
print(apple.price)
# 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
@classmethod
class Login:
    def __init__(self,name,password):
        self.name = name
        self.pwd = password
    def login(self):pass

    @staticmethod
    def get_usr_pwd():   # 静态方法
        usr = input('用户名 :')
        pwd = input('密码 :')
        Login(usr,pwd)

Login.get_usr_pwd()
# 在完全面向对象的程序中,
# 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
@staticmethod

# 类方法和静态方法 都是类调用的
# 对象可以调用类方法和静态方法么? 可以 一般情况下 推荐用类名调用
# 类方法 有一个默认参数 cls 代表这个类 cls 同对象的self 一样
# 静态方法 没有默认的参数 就象函数一样

反射

 

class Person:
    key = 123
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
    def da(self):
        print("打人")
    @classmethod
    def f(cls):
        print("人生")
    @staticmethod
    def login():
        print("hh")

s = getattr(Person,"key")  #通过反射,类名获取静态属性
print(s)   #   123
s1 = getattr(Person,"da") #通过反射,类名获取公共方法
print(s1) #    <function Person.da at 0x000001AB42A73840> 是一个地址
s1(s) # 打人    #地址加()才能执行这个方法 而必须要传一个参数(因为上面self)
s2 =getattr(Person,"f")  #  通过反射,类名获取 类方法
print(s2) # <bound method Person.f of <class '__main__.Person'>>
s2() # 人生
s3 = getattr(Person,"login")  #通过反射,类名调用静态方法
s3() # hh

p = Person("h","nan")
s4 = getattr(p,"key")   #通过反射 对象名获取静态属性
print(s4) # 123
s5 = getattr(p,"da")
s5() #  打人          #通过反射,对象名获取方法

#s6 = getattr(p,"ky")   # 不论类名 还是 对象名 调用没有值的时候 都是报错
#print(s6)   # AttributeError: 'Person' object has no attribute 'ky'

if hasattr(p,"ky"): # hasattr 检验是否有这个值,如果有 getattr可以取到,没有则什么都不显示
    s7 = getattr(p,"ky")
    print(s7)   #没有任何显示

if hasattr(Person,"key"):    #   hasattr  和 getattr  是一个组合用
    s8 = getattr(Person,"key")
    print(s8)   #123
View Code

 

posted @ 2019-04-22 19:35  暴走的路人  阅读(131)  评论(0编辑  收藏  举报