Python面向对象

三种编程方法论

  • 面向过程:把复杂的任务一步一步分解成简单的任务。
  • 函数式编程:思想上接近于数学运算,根据某种方式,根据方式得出的结果。
  • 面向对象编程:一种编程方式,需要使用“类”和“对象”来实现,其实就是对“类”和“对象的”使用

软件质量属性

软件质量属性包含:成本,性能,可靠性,安全性,可维护性,可移植性,可伸缩性,可扩展性等

面向过程

  • 概念:核心是“过程”二字,“过程”指的是解决问题的步骤,即先干什么再干什么......,把这个大的问题分解成很多个小问题或子过程,这些子过程在执行的过程中继续分解,直到小问题足够简单到可以在一个小步骤范围内解决。
  • 优点:复杂的问题流程化,进而简单化
  • 缺点:扩展性极差
  • 应用场景:一般用于那些功能一旦实现之后就很少需要改变的场景, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,著名的例子有Linux內核,git,以及Apache HTTP Server等。但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。

面向对象编程

  • 概念:核心是“对象”二字,对象就是特征与技能的结合体。
  • 优点:可扩展性高
  • 缺点:编程的复杂度高,易出现过度设计的问题
  • 应用场景:应用于需求经常变化的软件中,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。

一、名词解释

  • :一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型、模板。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
  • 属性:人类包含很多特征,把这些特征用程序来描述的话,叫做属性,比如年龄、身高、性别、姓名等都叫做属性,一个类中,可以有多个属性
  • 方法:人类不止有身高、年龄、性别这些属性,还能做好多事情,比如说话、走路、吃饭等,相比较于属性是名词,说话、走路是动词,这些动词用程序来描述就叫做方法。
  • 实例(对象):一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
  • 实例化:把一个类转变为一个对象的过程就叫实例化 就是类名+括号,就是在执行类的__init__()方法
  • 构造方法:__init__(...)被称为 构造方法或初始化方法,在例实例化过程中自动执行,目的是初始化实例的一些属性。每个实例通过__init__初始化的属性都是独有的
  • 析构方法(解构方法):__del__(self)被称为 析构方法或解构方法,实例在内存中被删除时,会自动执行这个方法。

二、类和对象

  • 类中可以有任意python代码,这些代码在类定义阶段便会执行
  • 因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过 类名.__dict__查看
  • 对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法
  • 点是访问属性的语法,类中定义的名字,都是类的属性
  • isinstance(obj,cls)检查obj是否是类 cls 的对象
  • 类的两种用法:实例化和属性引用(类的属性就两种:变量和函数)
  • 对象也叫实例只有一种用法:属性引用,就对象本身而言它只有数据属性
  • 构造函数中的self表示创建的当前对象。方法中的self表示谁调用的方法,self就是谁。
  • 示例对象访问属性或调用方法时,永远都是先找自己的,找不到就往父类找。
country='American'
def study():
    print('study english')

class Student():
    country = 'China'
    def __init__(self, ID, NAME, SEX, PROVINCE,country):
        self.id = ID
        self.name = NAME
        self.sex = SEX
        self.province = PROVINCE
        self.country = country

    def search_score(self):
        print('全局的',country)
        study() #全局的

        print('类里的', Student.country)
        Student.study(self) #类里的

        print('对象的', self.country) #对象有就从自身找,没有就从类中找
        self.study() #

    def study(self):
        print('study',self.country)

s1 = Student('3718818181', 'alex', 'female', 'shanxi','Singapore')
s1.search_score()

"""
全局的 American
study english
类里的 China
study Singapore
对象的 Singapore
study Singapore
"""
类中调用属性

三、__init__方法

  • 为对象初始化自己独有的特征
  • 该方法内可以有任意的python代码
  • 一定不能有返回值*****

四、属性查找

在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常

  • 类有两种属性:数据属性和函数属性
  • 类的数据属性是所有对象共享的
  • 类的函数属性是绑定给对象用的
class A:
    def fa(self):
        print('from A')
    def test(self):
        self.fa()

class B(A):
    def fa(self):
        print('from B')

b=B()
b.test()  #from B
"""
从自己找b.test(),没有找类B,也没有找类A,找到后执行self.fa(),
self指的是b对象,然后又从自己找fa(),没有就去类B中找fa(),找到了 所以打印  from B
"""

class C:
    def __fa(self):  #_C__fa
        print('from C')
    def test(self):
        self.__fa()   #slef._C__fa   __在定义阶段就会变形

class D(C):
    def __fa(self):  #_D__fa
        print('from D')

d=D()
d.test()  #from C
"""
__不能被子类继承和覆盖
"""
属性查找顺序

五、特性1:封装

封装在于明确区分内外, 类的实现者不需要让类的调用者知道具体的实现过程,隔离了复杂度,同时也提升了安全性,类的实现者可以修改封装内的东西而不影响外部调用者的代码。

在面向对象思想中是把一些看似无关紧要的内容组合到一起,统一进行存储和使用,这就是封装。

1、构造方法和类本身的包裹

使用构造方法将属性封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的属性,类本身就是一种封装的体现,它将数据与专门操作该数据的功能整合到一起。

2、__双下划线属性隐藏

  • 在python中用双下划线开头的方式将属性隐藏起来,设置成私有的
  • 类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式
  • 变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
  • 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

3、装饰器@property也有封装的思想

  • @property 类的静态属性:
    1. 将一个类的函数定义成特性以后,对象再去使用的时候obj.mbi,根本无法察觉自己的mbi是执行了一个函数然后计算出来的,
    2. @property这种特性的使用方式遵循了统一访问的原则
  • @classmethod
    1. 把一个方法绑定给类,会把类本身当做第一个参数自动传给绑定到类的方法
    2. 类的绑定方法
  • @staticmethod
    1. 被staticmethod装饰器修饰过的方法,都是解除绑定的方法,实际上就函数:就没有自动传值功能了
    2. 解除绑定的方法
  • 凡是定义在类的内部,并且没有被任何装饰器修饰过的方法,都是绑定方法:有自动传值功能
import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property  #被@property装饰的方法,调用的时候可以不用加括号,area=property(area)
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长


c=Circle(3)
print(c.area)
print(c.perimeter)
@property
#被property装饰的属性会优先于对象的属性被使用,只有在属性sex定义property后才能定义sex.setter,sex.deleter
class People:
    def __init__(self,name,SEX):
        self.name=name
        # self.__sex=SEX  #这不调用@sex.setter  def sex(self,value):方法  因为设置的是__sex 不是 sex,或者说__sex没有被@property装饰
        self.sex=SEX      #①因为sex被@property装饰,所以self.sex=SEX是去找@sex.setter  def sex(self,value): 方法,而不是给对象赋值
    @property
    def sex(self):
        return self.__sex #p1.__sex
    @sex.setter
    def sex(self,value):
        print('...')
        if not isinstance(value,str):
            raise TypeError('性别必须是字符串类型')
        self.__sex=value         #② male给了value ,  self.__sex='male'
    @sex.deleter                      #del p1.sex的时候调用
    def sex(self):
        del self.__sex #del p1.__sex

p1=People('alex','male')  #会调用 @sex.setter  def sex(self,value): 方法是因为__init__中 self.sex=SEX 是给sex设置值了
p1.sex='female' #会调用@sex.setter  def sex(self,value): 方法
del p1.sex
print(p1.sex) #AttributeError: 'People' object has no attribute '_People__sex'
@property @属性.setter @属性.deleter
import time
class Date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

    @classmethod  #把一个方法绑定给类:类.绑定到类的方法(),会把类本身当做第一个参数自动传给绑定到类的方法
    def now(cls): #用Date.now()的形式去产生实例,该实例用的是当前时间
        t=time.localtime() #获取结构化的时间格式
        obj=cls(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
        return obj

    @classmethod
    def tomorrow(cls):#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
        t=time.localtime(time.time()+86400)
        return cls(t.tm_year,t.tm_mon,t.tm_mday)

class EuroDate(Date):
    def __str__(self):
        return '年:%s,月:%s,日:%s' %(self.year,self.month,self.day)

e1=EuroDate.now()
print(e1)

e1=EuroDate(1,1,1)
print(e1)

"""
年:2019,月:3,日:17
年:1,月:1,日:1
"""
@classmethod
import time
class Date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

    @staticmethod
    def now(): #用Date.now()的形式去产生实例,该实例用的是当前时间
        t=time.localtime() #获取结构化的时间格式
        obj=Date(t.tm_year,t.tm_mon,t.tm_mday) #新建实例并且返回
        return obj

    @staticmethod
    def tomorrow():#用Date.tomorrow()的形式去产生实例,该实例用的是明天的时间
        t=time.localtime(time.time()+86400)
        return Date(t.tm_year,t.tm_mon,t.tm_mday)


d1=Date.now()
print(d1.year,d1.month,d1.day)

d2=Date.tomorrow()
print(d2.day)
@staticmethod
##示例对象访问属性或调用方法时,永远都是先找自己的,找不到就往父类找。
class A:
    def __init__(self, num):
        self.num = num

    def func1(self):
        self.func2()

    def func2(self):
        print("A.func2", self.num)


class B(A):
    def func2(self):
        print("B.func2", self.num)


list1 = [A(1), A(2), B(3)]
for i in list1:
    i.func2()
"""
A.func2 1
A.func2 2
B.func2 3
"""

for i in list1:
    i.func1()
"""
A.func2 1
A.func2 2
B.func2 3
"""
##################################################################################

class Person:
    # 类变量(静态变量),所有实例对象都共享这个变量  示例对象只能查看不能修改。想要修改类变量,只能通过类名来修改。
    country = '中国'

    # 方法
    def __init__(self, name, age):
        # 属性
        self.name = name
        self.age = age

    # 方法
    def say(self):
        print('我是{self.name},我今年{self.age}岁!'.format(self=self))


p1 = Person('张三', 18)
p2 = Person('李四', 20)

print(p1.country, p2.country)  # 中国 中国
print(id(p1.country), id(p2.country))  # 4567249032 4567249032

p3 = Person('王五', 3000)
p3.country = '大秦'
print(p3.name)  # 王五
print(p3.country)  # 大秦

p4 = Person('赵六', 30)
print(p4.name)  # 赵六
print(p4.country)  # 中国


"""
在上面的代码中,__init__和say都是属于类的成员方法,又称为实例方法。
self.name和self.age都是实例对象的属性,这些称为成员变量或实例变量。

注意,p3.country = '大秦'的时候,并没有去改变类中的country,
而是给自己添加了一个实例属性,这个属性只有在p3这个实例对象中才是存在的,在p4中是不存在的。
"""
##################################################################################

class Foo:
    count = 0

    def __init__(self):
        Foo.count += 1

print(Foo.count)  # 0
Foo()
Foo()
Foo()
print(Foo.count)  # 3


##################################################################################
class Computer:

    # 实例方法
    def play(self):
        print('玩游戏')

    @staticmethod    # 静态方法和静态变量一样,都可以使用类名直接访问。
    def fire():
        # 方法不需要传入实例对象变量
        print('煎鸡蛋')

    @classmethod
    def calc(cls, a, b):
        print(cls)
        return a + b


#实例方法
c1 = Computer()
c1.play()  #玩游戏     实例对象直接调用实例方法
# Computer.play() #报错
Computer.play(c1)  #玩游戏   类调用的时候,需要把实例作为第一个参数传入

#静态方法
c1.fire()  #煎鸡蛋
Computer.fire()  #煎鸡蛋


#类方法
ret = Computer.calc(10, 20)  #<class '__main__.Computer'>
print(ret)  # 30

ret2 = c1.calc(10, 20)  #<class '__main__.Computer'>
print(ret2)  # 30

#属性方法: 其实就是把类中的方法改造成属性的一种写法,该写法需要在方法上加上@property


##################################################################################
class Goods:
    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


obj = Goods()
print(obj.price)  # 80.0 获取商品价格
obj.price = 200  #  修改商品原价
print(obj.price) #160.0
del obj.price  # 删除商品原价
# print(obj.price)  # AttributeError: 'Goods' object has no attribute 'original_price'

##################################################################################

class A:
    __secret = '密码'

    def __init__(self, salary):
        self.__salary = salary

    def __play(self):
        print('嘿嘿嘿')


class B(A):

    def dazuiba(self):
        self.__play()


b1 = B(200)
# print(b1.__salary)  # 'B' object has no attribute '__salary'
# b1.__play()  # 'B' object has no attribute '__play'
# b1.dazuiba()  # AttributeError: 'B' object has no attribute '_B__play'
# print(b1.__secret)  # AttributeError: 'B' object has no attribute '__secret'
# print(B.__secret)  # AttributeError: type object 'B' has no attribute '__secret'
# print(A.__secret)  # AttributeError: type object 'A' has no attribute '__secret'

"""
私有成员: 1.只能够在类的内部调用,类的外部无法调用
         2.不能被继承。
"""
View Code

六、特性2:继承

继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。解决了代码重复的问题

1、继承顺序

  • python会计算出一个方法解析顺序(mro)列表,这个mro列表就是一个简单的所有基类的线性顺序列表 F.mro()等同于F.__mro__ 注意只有新式类才有这个方法
  • 子类会先于父类被检查
  • 多个父类会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类
  • 经典类的深度优先查找和新式类的广度优先查找

2、子类中调用父类的方法

  • 方法一:父类名.父类方法() 父类名.__init__(self,name,speed,load,power)
  • 方法二:【super只能用于新式类】super(自己的类,self).父类的函数名字
    python3中写法:super().__init__(name,speed,load,power)
    python2中写法:super(Subway,self).__init__(name,speed,load,power)
  • 二者使用哪一种都可以,但最好不要混合使用,注意区分参数self
  • 这两种方式的区别是:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super仍然会按照mro继续往后查找
  • super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
  • issubclass(sub, super)检查sub类是否是 super 类的派生类

3、经典类与新式类

  • 只有在python2中才分新式类和经典类,python3中统一都是新式类
  • 在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
  • 在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
  • 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
  • A.__bases__ 或者 A.__mor__查看类A的继承。mor()方法只在新式类中有

4、继承和抽象(先抽象再继承)

  • 抽象即提取类似的部分。
  • 基类就是抽象多个类共同的属性得到的一个类。

5、派生

  • 派生就是子类在继承父类的基础上衍生出新的属性。
  • 子类中独有的,父类中没有的或子类定义与父类重名的属性,那么在调用子类的这个属性时就以子类自己的为准。
  • 子类也叫派生类。

七、特性3:多态

  • 多态:指的是一类事物有多种形态,比如动物有多种形态:人,狗,猪
  • 多态性:指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性,想想len 函数的使用
  • 静态多态性:如任何类型都可以用运算符+进行运算
  • 动态多态性:
  • 实现:不同的类先继承基类,然后不同类的实例调用相同的方法(这个相同的方法是从基类那继承来的)
  • 作用:增加了程序的灵活性和可扩展性,(使用者都是同一种形式去调用)
#多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
class Animal:
    def run(self):
        raise AttributeError('子类必须实现这个方法')


class People(Animal):
    def run(self):
        print('人正在走')

class Pig(Animal):
    def run(self):
        print('pig is walking')


class Dog(Animal):
    def run(self):
        print('dog is running')

peo1=People()
pig1=Pig()
d1=Dog()

peo1.run()
pig1.run()
d1.run()



#多态性:一种调用方式,不同的执行效果(多态性)
def func(obj):
    obj.run()

func(peo1)
func(pig1)
func(d1)


# peo1.run()
# pig1.run()


# 多态性依赖于:
#     1.继承
#     2.
##多态性:定义统一的接口,
def func(obj): #obj这个参数没有类型限制,可以传入不同类型的值
    obj.run() #调用的逻辑都一样,执行的结果却不一样

func(peo1)
func(pig1)
多态性

其他补充

一、类的组合

软件重用的重要方式除了继承之外还有另外一种方式,即:组合 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

class Teacher:
    def __init__(self,name,sex,course):
        self.name=name
        self.sex=sex
        self.course=course
class Student:
    def __init__(self,name,sex,course):
        self.name=name
        self.sex=sex
        self.course=course
class Course:
    def __init__(self,name,price,peroid):
        self.name=name
        self.price=price
        self.period=peroid
python_obj=Course('python',15800,'7m')
t1=Teacher('egon','male',python_obj)
s1=Student('cobila','male',python_obj)

print(s1.course.name)
print(t1.course.name)
组合

二、抽象类(接口与归一化设计)

1、接口

  • 接口:接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数。
  • 作用:归一化设计,限制实现接口的类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。
  • hi boy,给我开个查询接口。。。此时的接口指的是:自己提供给使用者来调用自己功能的方式\方法\入口
  • raise NotImplementedError('子类必须实现这个方法')

2、归一化

  • 归一化:就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
  • 好处:
    1. 归一化让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
    2. 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
class Animal:
    def run(self):
        raise AttributeError('子类必须实现这个方法')
    def speak(self):
        raise AttributeError('子类必须实现这个方法')

class People(Animal):
    def run(self):
        print('人正在走')

    def speak(self):
        print('说话')

class Pig(Animal):
    def run(self):
        print('pig is walking')
    def speak(self):
        print('哼哼哼')


# peo1=People()
# pig1=Pig()
#
# peo1.run()
# pig1.run()
接口与归一化设计

3、抽象类

  • 抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
  • 类是从一堆对象中抽取相同的内容而来的,抽象类是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
  • 抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。
import abc
#抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
class Animal(metaclass=abc.ABCMeta):
    tag='123123123123123'
    @abc.abstractmethod
    def run(self):
        pass
    @abc.abstractmethod
    def speak(self):
        pass

class People(Animal):
    def run(self):
        pass

    def speak(self):
        pass

peo1=People()
print(peo1.tag)
抽象类

4、抽象类与接口

  • 抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
  • 抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

三、类中定义的函数分成两大类

1、绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入)

  1. 绑定到类的方法:用classmethod装饰器装饰的方法。
    • 为类量身定制
    • 类.bound_method(),自动将类当作第一个参数传入
    • (其实对象也可调用)
  2. 绑定到对象的方法:没有被任何装饰器装饰的方法。
    • 为对象量身定制
    • 对象.bound_method(),自动将对象当作第一个参数传入
    • (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

2、非绑定方法:用staticmethod装饰器装饰的方法

  • 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已
  • 注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

四、反射

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

  • hasattr(object,name) 判断object中有没有一个name字符串对应的方法或属性
  • getattr(object, name, default=None)
  • setattr(x, y, v)
  • delattr(x, y)
import sys
def add():
    print('add')

def change():
    print('change')

def search():
    print('search')

def delete():
    print('delete')

this_module=sys.modules[__name__] #获取当前模块
while True:
    cmd=input('>>:').strip()
    if not cmd:continue
    if hasattr(this_module,cmd):
        func=getattr(this_module,cmd)
        func()

#多分支判断方式1:
# func_dic={
#     'add':add,
#     'change':change,
#     'search':search,
#     'delete':delete
# }

#
# while True:
#     cmd=input('>>:').strip()
#     if not cmd:continue
#     if cmd in func_dic:
#         func=func_dic.get(cmd)
#         func()

#多分支判断方式2:
# class Service:
#     def run(self):
#         while True:
#             inp = input('>>: ').strip()  # cmd='get a.txt'
#             cmds = inp.split()  # cmds=['get','a.txt']
#             if hasattr(self, cmds[0]):
#                 func = getattr(self, cmds[0])
#                 func(cmds)
#
#     def get(self, cmds):
#         print('get.......', cmds)
#
#     def put(self, cmds):
#         print('put.......', cmds)
#
# obj = Service()
# obj.run()
反射的用途1
#ftpclient.py    
class FtpClient:

    'ftp客户端,但是还么有实现具体的功能'
    def __init__(self,addr):
        print('正在连接服务器[%s]' %addr)
        self.addr=addr
    def test(self):
        print('test')
    def get(self):
        print('get------->')
        
#ftpserver.py        
#服务端同学可以不用非等着客户端同学写完代码才去实现
import ftpclient

f1=ftpclient.FtpClient('192.168.1.1')
if hasattr(f1,'get'): #有就执行没有就执行其他逻辑
    func=getattr(f1,'get')
    func()
else:
    print('其他逻辑')
反射用途2:实现可插拔机制
#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
# 先定义类 后产生对象
class Animal:
    def eat(self):
        print('is eating')
 
 
class Student(Animal):  # 继承,可继承多个,用mro()查看继承关系
    school = 'Peking University'  # 类的数据属性
    count = 0
 
    def __init__(self, name, age):  # 类的函数属性,也就是对象的绑定方法()
        self.name = name
        self.age = age
        Student.count += 1
 
    def learn(self):
        print('%s is learning' % self.name)
 
    def eat(self):  # 重写父类方法
        print('Wash your hands before eating')  # 加入自己新功能
        # Peo2.eat(self)                             #重用父类的方法
        # super(Student,self).eat()                  #重用父类的方法
        super().eat()  # 重用父类的方法  super是按照mro的顺序查找
 
"""
类:
1、类的数据属性是所有对象共享的,id都一样
2、类的函数属性是绑定给对象用的,obj.method称为绑定方法,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传给self
    (绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。 )
3、__init__方法
    (1)、该方法内可以有任意的python代码
    (2)、一定不能有返回值
     
继承:
"""
print(issubclass(Student, Animal))# 检查Student类是否是Animal类的派生类
 
#
Student.country = 'China'
#
del Student.country
#
Student.school = 'Tsinghua University'
#
print(Student.__dict__)  # 查看类的名称空间
print(Student.school)
print(Student.learn)
 
print(Student.__mro__)  # 查看类的继承关系
print(Student.__bases__)  # 查看类的父类
 
"""
对象:
属性查找顺序:在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
"""
stu = Student('tom', 18)  # 实例化一个对象
print(isinstance(stu,Student))  #obj是否是类 cls 的对象
 
#
stu.gender = 'male'
#
del stu.gender
#
stu.age = 28
#
print(stu.__dict__)
print(stu.name)
stu.eat()
 
"""
super 按照mro的顺序查找
"""
class A:
    def f1(self):
        print('from A')
        super().f1()
class B:
    def f1(self):
        print('from B')
class C(A, B):
    pass
print(C.mro())
# [<class '__main__.C'>,
# <class '__main__.A'>,
# <class '__main__.B'>,
# <class 'object'>]
c = C()
c.f1()  # 打印  from A   from B
 
"""
封装:类的实现者不需要让类的调用者知道具体的实现过程
"""
 
"""
__私有属性,私有方法 (类的定义极端就已经变形了)
这种变形的特点:
    1、在类外部无法直接obj.__AttrName
    2、在类内部是可以直接使用:obj.__AttrName
    3、子类无法覆盖父类__开头的属性
    4、在定义阶段就会变形,也就是说__开头的属性(变量和函数)不能被子类继承 因为在定义阶段__属性名就变成了_父类名__属性名。
"""
 
class A:
    def __foo(self):  # _A__foo
        print('A.foo')
 
    def bar(self):
        print('A.bar')
        self.__foo()  # self._A__foo()
 
 
class B(A):
    def __foo(self):  # _B__foo
        print('B.foo')
 
 
b = B()
b.bar()
 
"""
@property
类的静态属性,类方法,类的静态方法
在类内部定义的函数,分为两大类:
    一:绑定方法:绑定给谁,就应该由谁来调用,谁来调用就回把调用者当作第一个参数自动传入
        绑定到对象的方法:在类内定义的没有被任何装饰器修饰的
 
        绑定到类的方法:在类内定义的被装饰器classmethod修饰的方法
 
    二:非绑定方法:没有自动传值这么一说了,就类中定义的一个普通工具,对象和类都可以使用
        非绑定方法:不与类或者对象绑定
"""
 
import hashlib, time
class Teacher:
    def __init__(self, name, weight, height):
        self.name = name
        self.weight = weight
        self.height = height
        self.id = self.create_id()
 
    @property  # 类的静态属性@property   封装的部分体现
    def bmi(self):
        return self.weight / (self.height ** 2)
 
    @classmethod  # 绑定到类的方法
    def talk(cls):
        print('is talking')
 
    @staticmethod  # 非绑定方法 类的静态方法,就是一个普通工具
    def create_id():
        m = hashlib.md5(str(time.time()).encode('utf-8'))
        return m.hexdigest()
 
    def play(self):  # 绑定到对象的方法
        print('is playing')
 
 
t = Teacher('jack', 80, 1.8)
print(t.bmi)
print(t.id)
 
"""
多态:
不考虑对象的类型,直接使用对象,也就是不同类的实例调用相同的方法,实现的过程不一样。
多态怎么来的?
1,不同的类先继承基类,
2,然后不同类的实例调用相同的方法(这个相同的方法是从基类那继承来的)
 
抽象类:
本质还是类,于普通类不一样的是,加了装饰器的函数,子类必须实现他们,也就是抽象类的方法必须要重写
"""
import abc
 
class People(metaclass=abc.ABCMeta):  # 抽象类,只能被继承,不能被实例化
    @abc.abstractmethod
    def answer(self):
        pass
 
class Chinese(People):
    def answer(self):  # 抽象类的方法必须要重写
        print('用中文答辩')
 
class English(People):
    def answer(self):  # 抽象类的方法必须要重写
        print('use english')
 
chi = Chinese()
eng = English()
 
def ans(obj):        # 相同的调用方式
    obj.answer()
 
ans(chi)            # 相同的调用方式    多态
ans(eng)            # 相同的调用方式
 
 
"""
类的组合:
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
"""
class Date:
    def __init__(self, year, mon, day):
        self.year = year
        self.mon = mon
        self.day = day
 
    def tell_info(self):
        print('My birthday is %s-%s-%s' % (self.year, self.mon, self.day))
 
 
d = Date(1986, 6, 26)
stu2 = Student('rose', 88)
stu2.birth = d
stu2.birth.tell_info()
 
"""
反射:通过字符串映射到对象的属性
setattr(obj,'sex','male')
getattr(obj,'namexxx',None)
hasattr(obj,'talk')
delattr(obj,'age')
"""
 
 
class Service:
    def run(self):
        while True:
            inp = input('>>: ').strip()  # cmd='get a.txt'
            cmds = inp.split()  # cmds=['get','a.txt']
            if hasattr(self, cmds[0]):
                func = getattr(self, cmds[0])
                func(cmds)
 
    def get(self, cmds):
        print('get.......', cmds)
 
    def put(self, cmds):
        print('put.......', cmds)
 
 
obj = Service()
# obj.run()

转载于:https://www.cnblogs.com/bubu99/p/10192835.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值