python面型对象知识


python面型对象知识

python笔记2021.12.15面向对象的基础、实例化

1.面向对象的楔(xie)子

  • 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人拿棍打狗, 狗可以咬人,怎么描述这种不同的角色和他们的功能呢?

    def person(name,age,sex,job):
        def walk(p):
            print("person %s is walking..." % p['name'])
     
        data = {
            'name':name,
            'age':age,
            'sex':sex,
            'job':job,
            'walk':walk
        }
     
        return data
     
    def dog(name,dog_type):
     
     
        def bark(d):
            print("dog %s:wang.wang..wang..."%d['name'])
        data = {
            'name':name,
            'type':dog_type,
            'bark':bark
        }
     
        return data
    
    限制功能全新代码
    

2.面向过程 VS 面向对象

面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。

优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。

缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。

应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直 到最后取得真经。如来根本不会管师徒四人按照什么流程去取。

面向对象的程序设计的

优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。

缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。

应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。

在python 中面向对象的程序设计并不是全部。

面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

了解一些名词:类、对象、实例、实例化

类:具有相同特征的一类事物(人、狗、老虎)

对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)

实例化:类——>对象的过程

3.初始类和对象

class Person:
    def __init__(self):
        self.name = 'cookie'
        self.sex = '男'
        self.job = '搓澡工'
        self.level = 0
        self.hp = 250
        self.weapon = '搓澡巾'
        self.ad = 1
        print('这里是__init__!')

#类名+()会执行__init__方法
alex = Person() 

4.创建类和实例化

#实例化所经历的步骤                                       
    #1.类名()后的第一个事,开辟一块内存空间                       
    #2.调用__init__方法把内存空间地址作为self参数传递到函数内部        
    #3.所有的对象需要使用的属性都要和self关联起来                   
    #4.执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方) 

class Person:
    def __init__(self, name, sex, 
        self.name = name
        self.sex = sex
        self.job = job
        self.level = level
        self.hp = hp
        self.weapon = weapon
        self.ad = ad
        print('这里是__init__!')

#类名+()会执行__init__方法
alex = Person('cookie', '男', '搓澡工'

print(alex.name)#属性查看
alex.name = 'alex'#属性修改
alex.money = 10000000#属性的增加
print(alex.__dict__)  #打印这个类的字典
del alex.money #属性的删除
              
#实例化所经历的步骤
    #1.类名()后的第一个事,开辟一块内存空间
    #2.调用__init__方法把内存空间地址作为self参数传递到函数内部
    #3.所有的对象需要使用的属性都要和self关联起来
    #4.执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方)


class Dog:
    def __init__(self, name, blood, aggr, kind):
        #必须叫__init__这个名字,不能改变,所有的在一个具体的人物出现之后拥有的属性
        self.name = name #对象的属性/实例变量
        self.blood = blood
        self.aggr = aggr
        self.kind = kind
Dog('晓丽', '100', '10', '金毛')#实例化过程
print(Dog.__dict__)
              
class Round():
    def __init__(self, r):
        self.r = r

class User():
    def __init__(self, user_name, passwd):
        self.user_name = user_name
        self.passwd = passwd
              
    def 搓(self):#方法,有一个必须传递的参数-->self对象(开辟的空间地址)
        pass
r1 = Round(5)
print(r1.r)
r2 = Round(10)
print(r2.r)
user1 = User('cookie', 123456)
print(user1.user_name)
print(user1.passwd)
              
#有关self的问题:同一个类的函数的self地址是一样的,不同类的地址是不一样的
class User:
    def __init__(self, user_name, passwd):
        self.user_name = user_name
        self.passwd = passwd
        print(self)

    def 搓(self):#方法,有一个必须传递的参数-->self对象(开辟的空间地址)
        print(self.__dict__)
        print(self)

#<__main__.User object at 0x00000225326FAFD0>
#{'user_name': 'cookie', 'passwd': 123456}
#<__main__.User object at 0x00000225326FAFD0>
              
class Dog:
    def __init__(self, name, blood, aggr, kind):
        self.name = name
        self.hp = blood
        self.ad = aggr
        self.kind = kind

class Person:
    def __init__(self, name, sex, job, level, hp, weapon, ad):
        self.name = name
        self.sex = sex
        self.job = job
        self.level = level
        self.hp = hp
        self.weapon = weapon
        self.ad = ad

    def 搓(self,dog):  # 方法,有一个必须传递的参数-->self对象(开辟的空间地址)
        dog.hp -= self.ad
        print(f'{self.name}给{dog.name}搓了澡,{dog.name}掉了{self.ad}点血,{dog.name}当前血量{dog.hp}')

alex = Person('cookie', '男', '搓澡工', 0, 250, '搓澡巾', 1)#alex就是对象, alex=Person()的过程就是通过类获取一个对象的过程 叫做实例化
小白 = Dog('晓丽', 100, 10, '金毛')
alex.搓(小白)
              

5.命名空间和组合

class A:
    Country = '中国'
    def __init__(self, name, age, country):
        self.name = name
        self.age = age

    def func1(self):
        print(self)

a = A('cookie', 18, '秦国人')
b = A('诸葛亮', 50, '蜀国人')
A.Country = '魏国人'
print(a.Country)#魏国人
print(b.Country)#魏国人
print(A.Country)#魏国人
print(id(a))#1261515685840
print(id(b))#1261515685744
print(id(A))#1261506989696
#开辟的三个不同的空间,相互之间有联系 

  • 类中的变量是静态变量

  • 对象中的变量只属于对象本身,每个变量有属于自己的空间来存储对象的变量

  • 当使用对象名去调用某一个属性的时候会优先在对象自己的变量空间去找,找不到的时候再去对应的类中去找

  • 如果自己没有就引用类的,如果类也没有就报错

  • 对于类来说,类中的变量的所有的对象都是可以读取的并且读取的是同一份变量

  • 类中的静态变量的用处

    • 如果一个变量是所有对象的共享值,那么这个变量应该被定义为静态变量

    • 所有和静态变量相关的增删改查都应该使用类名来处理

    • 而不应该直接使用对象名进行操作和修改

6.组合

  • 一个类的对象是另外一个类对象的属性
    • 将两个对象关联起来
class Student:
     def __init__(self, name, sex, age, number, clas, phone):
         self.name = name
         self.sex= sex
         self.age =  age
         self.number = number
         self.clas = clas
         self.phone = phone

class Clas:
     def __init__(self, cname, begint, teacher):
         self.canme = cname
         self.begint = begint
         self.teacher = teacher

xsfh = Clas('xsfh', '2021-06-07', 'feng')
ldj = Clas('ldj', '2020-12-17', 'wen')
zhengbo = Student('zhengbo', 'male', 18, 27, ldj, 13674295813)
yihe = Student('yihe', 'male', 18, 17, xsfh, 18874962544)#如要这样引用那么必须先定义xsfh和ldj对象,不然就会发生为定义就使用的错误
print(yihe.clas,xsfh)
print(xsfh.begint)
print(yihe.clas.begint)
#<__main__.Clas object at 0x0000018A4C1CAFD0> <__main__.Clas object at 0x0000018A4C1CAFD0>
# 2021-06-07
# 2021-06-07

易错

#此方法就避免了未定义先使用的情况
class Clas:
    def __init__(self, cname, begint, teacher):
        self.canme = cname
        self.begint = begint
        self.teacher = teacher

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

linux = Clas('linux基础', '2020', 'feng')
Python = Clas('Python进阶', '2020', 'wen')
linux基础 = Course('linux基础', '1个月', 14800)
Python进阶 = Course('Python进阶', '4个月', 16800)

linux基础.cname = linux#将两者关联起来
print(linux基础.cname.teacher)#feng

#此方法有未定义先使用的的可能性
class Course:
    def __init__(self, name, period, price):
        self.name = name
        self.period = period
        self.price = price

class Clas:
    def __init__(self, cname, begint, teacher):
        self.canme = cname
        self.begint = begint
        self.teacher = teacher

linux基础 = Course('linux基础', '1个月', 14800)
Python进阶 = Course('Python进阶', '4个月', 16800)
linux = Clas(linux基础, '2020', 'feng')
Python = Clas(Python进阶, '2020', 'wen')

print(linux.canme.period)#1个月

python笔记,关于队列、栈的简单实现、Pickle的自定义

1.队列

#FIFO:简单思路实现
class Queue:
    def __init__(self):
        self.l = []
    def put(self,item):
        self.l.append(item)
    def pop(self):
        return self.l.pop(0)

q = Queue()
q.put(1)
q.put(5)
q.put(3)
print(q.pop())#1
print(q.pop())#3
print(q.pop())#5

2.栈

#栈:后进先出
class Stack:
    def __init__(self):
        self.l = []
    def put(self,item):
        self.l.append(item)
    def pop(self):
        return self.l.pop()

q = Stack()
q.put(1)
q.put(5)
q.put(3)
print(q.pop())#5 
print(q.pop())#3
print(q.pop())#1

3.栈和队列构造继承

class Foo:
    def __init__(self):
        self.l = []
    def put(self,item):
        self.l.append(item)

#栈
class Stack(Foo):
    def pop(self):
        return self.l.pop()
#队列
class Queue(Foo):
    def pop(self):
        return self.l.pop(0)

q = Stack()
q.put(1)
q.put(5)
q.put(3)
print(q.pop())
print(q.pop())
print(q.pop())
s = '*'
print(s.center(50, '#'))
q = Queue()
q.put(1)
q.put(5)
q.put(3)
print(q.pop())
print(q.pop())
print(q.pop())

#方法二
class Foo:
    def __init__(self):
        self.l = []
    def put(self,item):
        self.l.append(item)
    def pop(self):
        if self.index == 0:
            return self.l.pop(0)
        else:
            return self.l.pop()
#return self.l.pop() if self.index else self.l.pop(0 )        
#栈
class Stack(Foo):
    def __init__(self):
        self.index = 0
        Foo.__init__(self)#既要执行本函数init方法,还要执行父类函数的init方法
         
#队列
class Queue(Foo):
    def __init__(self):
        self. index = 1
        Foo.__init__(self)#既要执行本函数init方法,还要执行父类函数的init方法

4.Pickle的自定义

class Foo:
    def __init__(self):
        self.l = []
    def put(self,item):
        self.l.append(item)
    def pop(self):
        if self.index == 0:
            return self.l.pop(0)
        else:
            return self.l.pop()
#return self.l.pop() if self.index else self.l.pop(0 )        
#栈
class Stack(Foo):
    def __init__(self):
        self.index = 0
        Foo.__init__(self)#既要执行本函数init方法,还要执行父类函数的init方法
         
#队列
class Queue(Foo):
    def __init__(self):
        self. index = 1
        Foo.__init__(self)#既要执行本函数init方法,还要执行父类函数的init方法

import pickle
class My_pickle:
    def __init__(self, path):
        self.file = path
    def dump(self, obj):
        with open(self.file, 'ab') as f:
            pickle.dump(obj, f)
    def load(self):
        with open(self.file, 'rb') as f:
            while True:
                try:
                    yield pickle.load(f)
                except EOFError:
                    break

pic = My_pickle('Stack.file')#文件问号打不开是因为文件尾缀问题
s1 = Stack()
s1.put('aaa')
s1.put(123)
s1.put(456)
pic.dump(s1)
s2 = Stack()
s2.put('bbb')
s2.put('segsd')
pic.dump(s2)

for i in pic.load():
    print(i.l)#把每一行以列表的形式打印出来,我目前暂时也为理解
  • python学习笔记2021.12.18-继承-封装-多态

    1.单继承:解决代码重复的问题

    # class A:
    #     pass
    # class B(A):
    #     pass
    # #B继承A,A是父类,B是子类
    # #A是父类,基类,超类
    # #B是子类,派生类
    
    # #子类可以使用父类中的: 方法 静态变量
     	
    class Animal:
        def __init__(self,name):
            self.name = name
        def eat(self):
            print(f'{self.name} is eating')
        def drink(self):
            print(f'{self.name} is drinking')
        def sleep(self):
            print(f'{self.name} is sleeping')
    
    class Cat(Animal):
        def climb_tree(self):
            print(f'{self.name} is climbing')
    
    class Dog(Animal):
        def bark(self):
            print(f'{self.name} is barking')
    
    小白 = Dog('cooikie')
        #先开辟空间,空间里有一个类指向Cat
        #先调用init方法,在对象自己空间中找init没找到,到Cat类中也没有找到
        #去父类Animal中找init
    
    小白.eat()#cooikie is eating
    
    

    • 子类既想调用自己的方法同时也想执行父类同名的方法

      • 在子类的方法中调用父类的方法:父类名.方法名(self)

        #先开辟空间,空间里有一个类指向Cat
            #先调用init方法,在对象自己空间中找init没找到,到Cat类中也没有找到
            #去父类Animal中找init
        class Animal:
            def __init__(self, name, food):
                self.name = name
                self.food =food
                self.blood = 100
                self.waise = 100
            def eat(self):
                print(f'{self.name} is eating{self.food}')
            def drink(self):
                print(f'{self.name} is drinking')
            def sleep(self):
                print(f'{self.name} is sleeping')
        
        class Cat(Animal):
            def climb_tree(self):
                print(f'{self.name} is climbing')
                self.dring()#调用父类方法
            def eat(self):
                self.blood += 100
                Animal.eat(self)#此方法在调用本身同名方法的时候还调用父类同名方法
        
        class Dog(Animal):
            def bark(self):
                print(f'{self.name} is barking')
            def eat(self):
                self.waise += 100
                Animal.eat(self)
        小白 = Dog('cooikie', '狗粮')
        小黑 = Cat('小黑', '猫粮')
        小白.eat()
        小黑.eat()
        print(小白.__dict__)
        print(小黑.__dict__)
        # cooikie is eating狗粮
        # 小黑 is eating猫粮
        # {'name': 'cooikie', 'food': '狗粮', 'blood': 100, 'waise': 200}
        # {'name': '小黑', 'food': '猫粮', 'blood': 200, 'waise': 100}
        

    • 定义自己的个性属性

    2.多继承

    • java语言不支持·多继承,但是python语言支持多继承

      多继承语法:类里面可以传多个参数

      #基本语法
      class A:
          pass
      class B:
          pass
      class C(A, B):#哪个类在前面就先找哪个类
          pass
      print(C.__bases__)#查看继承了哪些父类
      

    3.object类

    ? 类祖宗:所有的类都默认继承object

    ? 在python3中class A == class A(object), 但是在python2中不是的,所有为了兼容两者以后可以写上object

    4.类属性的补充

     # 一:我们定义的类的属性到底存到哪里了?有两种方式查看
    # dir(类名):查出的是一个名字列表
    # 类名.__dict__:查出的是一个字典,key为属性名,value为属性值
    # 
    # 二:特殊的类属性
    # 类名.__name__# 类的名字(字符串)
    # 类名.__doc__# 类的文档字符串
    # 类名.__base__# 类的第一个父类(在讲继承时会讲)
    # 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
    # 类名.__dict__# 类的字典属性
    # 类名.__module__# 类定义所在的模块
    # 类名.__class__# 实例对应的类(仅新式类中)
    

    5.继承的进阶知识点

    • 新式类

      • 只要继承object的类就是新式类
    • 经典类

      • 在python3中不存在
      • 在python2中不继承object类的就是经典类
    • 多继承的继承顺序问题(项目和源码)‘

    • 红色的是新式类

    • 绿色的是经典类

    • C3算法

      • 参考链接:http://hanjianwei.com/2013/07/25/python-mro/
    • 通过继承实现的类的开发规范(工作中)

    python笔记2021.12.23规范类、抽象类、多态和鸭子类

    1.规范类即抽象类

    # 这种类称为规范类也是抽象类
    class Payment:
        def pay(self, money):
            '''只要你见到了项目中有这种类,你的子类中必须实现和pay同名的方法'''
            raise NotImplementedError('请在子类中重写同名方法')  # 主动抛出异常并作出提示
    
    
    class Alipay(Payment):
        def __init__(self, name):
            self.name = name
    
        def pay(self, money):
            dic = {'uname': self.name, 'price': money}
            # 想办法调用支付宝支付,url连接,把dic传递过去
            print(f'{self.name}通过支付宝付{money}钱成功!')
    
    
    class We_pay(Payment):
        def __init__(self, name):
            self.name = name
    
        def pay(self, money):
            dic = {'name': self.name, 'number': money}
            # 想办法调用微信支付,url连接,把dic传递过去
            print(f'{self.name}通过微信付{money}钱成功!')
    
    
    class Ap_pay(Payment):
        def __init__(self, name):
            self.name = name
    
        def pay(self, money):
            dic = {'name': self.name, 'money': money}
            # 想办法调用苹果支付,url连接,把dic传递过去
            print(f'{self.name}通过苹果付{money}钱成功!')
    
    
    ali_pay = Alipay('cookie')
    we_pay = We_pay('cookie')
    ap_pay = Ap_pay('cookie')
    
    al = ali_pay.pay(1000)
    we = we_pay.pay(100)
    ap = ap_pay.pay(200)
    
     #实现抽象类的另一种方式,约束性强,但是依赖于abc模块
    from abc import ABCMeta, abstractmethod
    
    class Payment(metaclass=ABCMeta):
        @abstractmethod
        def pay(self, money):
            '''只要你见到了项目中有这种类,你的子类中必须实现和pay同名的方法'''
            # raise NotImplementedError('请在子类中重写同名方法')  # 主动抛出异常并作出提示
            pass
    
    class Alipay(Payment):
        def __init__(self, name):
            self.name = name
    
        def f(self, money):
            dic = {'uname': self.name, 'price': money}
            # 想办法调用支付宝支付,url连接,把dic传递过去
            print(f'{self.name}通过支付宝付{money}钱成功!')
    
    
    class We_pay(Payment):
        def __init__(self, name):
            self.name = name
    
        def pay(self, money):
            dic = {'name': self.name, 'number': money}
            # 想办法调用微信支付,url连接,把dic传递过去
            print(f'{self.name}通过微信付{money}钱成功!')
    
    
    class Ap_pay(Payment):
        def __init__(self, name):
            self.name = name
    
        def pay(self, money):
            dic = {'name': self.name, 'money': money}
            # 想办法调用苹果支付,url连接,把dic传递过去
            print(f'{self.name}通过苹果付{money}钱成功!')
    
    
    ali_pay = Alipay('cookie')
    we_pay = We_pay('cookie')
    ap_pay = Ap_pay('cookie')
    
    al = ali_pay.pay(1000)
    we = we_pay.pay(100)
    ap = ap_pay.pay(200)
    
    

    2.多态类和鸭子类型(了解)

    #多态一个类型表现出来的两种状态
    #支付表现出微信支付或支付宝支付两种状态
    #鸭子类型:
     
    

python笔记2021.12.24super方法,封装,property装饰器、反射

1.super方法

class A:
    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()
        #super(D,self).func()默认这样传参
        print('D')

D().func()
#super是按照mro顺序来寻找当前类的下一个类
#py3中super不需要传递参数,自动帮我们寻找当前类的mro顺序的下一个类中的同名方法
#py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名()这样才能狗帮助我们调用这个子类的mro顺序的下一个类的方法、
#在py2的经典类中,并不支持使用super来找下一个类

#在D类中找super的func,super(D, self).func()(可以兼容py2)

#在单继承中super方法就是找父类
class User:
    def __init__(self, name):
        self.name = name
        
class VIP_User:
    def __init__(self, name, start_time, end_time):
        #User.__init__(self, name)#手动调用
        super.__init__(self, name)#自动调用
        self.start_time = start_time
        self.end_time = end_time

2.封装

封装:就是把属性和方法封装起来

广义:把属性和方法封装起来,外面不能直接调用,要通过类的名字来调用

狭义:把属性和方法藏起来,外面不能调用,只能在能部调用

class User:#外部无法调用私有变量和对象
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd #变量前面加双下划线:私有的实例变量/私有的对象属性

    def get_pwd(self):#让外部查看私有变量的方法
        return self.__pwd    

alex =User('alex', 123546)
print(alex.get_pwd())

#私有变量
class User:
    __Country = 'china' #私有的静态变量
    def func(self):
        print(User.__Country)#私有变量只能在内部使用,不可以在外部调用

#私有方法
import hashlib
class User:
    def __init__(self, name, passwd):
        self.name = name
        self.__pwd = passwd

    def __get_md5(self):
        md5 = hashlib.md5(self.name.encode('utf-8'))
        md5.update(self.__pwd.encode('utf-8'))
        return md5.hexdigest()

    def get_pwd(self):
        return self.__get_md5()

alex = User('alex', '123456')
print(alex.get_pwd())

#所有的私有化都是为了让用户不在外部调用类中的某个名字
#如果完成私有化,那么这个类的封装度就更高了,封装度越高各种属性和方法的安全性也越高但是代码越复杂

3.私有变量的特点和原理还有类中变量的级别:

? 1.

? 2.结果是in son

.结果是in foo

所有私有类不能被继承:即子类不能去实现父类中的私有方法

4.property装饰器

from math import pi
class Cricle:
    def __init__(self, r):
        self.r = r

    @property #把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
    def area(self):
        return pi * self.r**2

c1 = Cricle(5)
print(c1.r)
print(c1.area)
#变量的属性和方法?
    #属性:圆的半径和圆的面积
    #方法:登录 注册
    
#被装饰的方法一定不能有参数    
import time
class Person:
    def __init__(self, name, brith):
        self.name = name
        self.brith = brith

    @property#被装饰的方法一定不能有参数
    def age(self):
        age1 = time.localtime().tm_year - self.brith
        return age1

cookie = Person('cookie', 2001)
print(cookie.age)

#property的第二个运用场景:一般是和私有的属性合作的
class User:
    def __init__(self, usr, pwd):
        self.usr = usr
        self.__pwd = pwd

    @property
    def pwd(self):
        return self.__pwd

cookie = User("cookie", 123546)
print(cookie.pwd)

5.property进阶

class Goods:
    discount = 0.8
    def __init__(self, name, origin_price):
        self.name = name
        self.__price = origin_price

    @property
    def price(self):
        return self.__price * self.discount

    @price.setter
    def price(self, new_value):
        if isinstance(new_value, int):#当传入的new_value为int类型的时候才替换
            self.__price = new_value

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

apple = Goods('apple', 20)
print(apple.price) #调用的是被@property装饰的price
apple.price = 10   ##调用的是被@setter装饰的price
print(apple.price)
del apple.price  #并没有真的删除price,只是调用了被@price.delter装饰的方法而已,原有方法删除函数方法
print(apple.price)

6.反射getattr函数

  • 用字符串数据类型的名字来操作这个名字对应的函数、实例变量、绑定方法、各种方法
  • 有时候你你明明知道一个变量的字符串数据类型的名字,你想直接调用它但是调不到,便要使用反射

作用:返回object的名称为name的属性的属性值,如果属性name存在,则直接返回其属性值;如果属性name不存在,则触发AttribetError异常或当可选参数default定义时返回default值。

这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。这样,你就可以把一个类可能要调用的方法放在配置文件里,在需要的时候动态加载。

class Payment:
    def pay(self, money):
        '''只要你见到了项目中有这种类,你的子类中必须实现和pay同名的方法'''
        raise NotImplementedError('请在子类中重写同名方法')  # 主动抛出异常并作出提示


class Alipay(Payment):
    def __init__(self, name):
        self.name = name

    def pay(self, money):
        dic = {'uname': self.name, 'price': money}
        # 想办法调用支付宝支付,url连接,把dic传递过去
        print(f'{self.name}通过支付宝付{money}钱成功!')


class We_pay(Payment):
    def __init__(self, name):
        self.name = name

    def pay(self, money):
        dic = {'name': self.name, 'number': money}
        # 想办法调用微信支付,url连接,把dic传递过去
        print(f'{self.name}通过微信付{money}钱成功!')


class Ap_pay(Payment):
    def __init__(self, name):
        self.name = name

    def pay(self, money):
        dic = {'name': self.name, 'money': money}
        # 想办法调用苹果支付,url连接,把dic传递过去
        print(f'{self.name}通过苹果付{money}钱成功!')



import sys
def pay(name, price, kind):
    #减少判断,完善代码
    class_name = getattr(sys.modules['__main__'], kind)#kind是用字符串表示的方法或属性,前者是空间地址
    obj = class_name(name) #__init__文件里面需要传name,即初始化
    obj.pay(price) #调用实例化对象的pay函数

pay('cookie', 400, 'We_pay')
pay('cookie', 400, 'Alipay')
pay('cookie', 400, 'Ap_pay')

#1.反射对象的实例变量
#2.反射类的 静态变量/绑定方法/其他方法
#3.模块中的 所有变量
    #被导入的模块
    #当前执行的py文件
class A:
    Role = '治疗'
    # name = 'cookei'
    def __init__(self):
        self.name = 'cookie'
        self.age = 84
        print('555')

    def func(self):
        print('wahaha')
        return 666

a = A()
print(getattr(a, 'name')) #反射对象的实列变量
print(getattr(a, 'func')()) #反射对象的绑定方法
print(getattr(A, 'Role'))
#
#引用模块中的任意的变量
import a
print(getattr(a, 'sww'), a.sww)
getattr(a, 'sww')()
print(getattr(a, 'lst'),a.lst)
print(getattr(a, 'dic'),a.dic)
print(getattr(a, 'we'),a.we)

# 反射本模块的名字
import sys
cat = '小a'
dog = '小b'
def pig():
    print('小p')
print(getattr(sys.modules['__main__'], 'cat'))
print(getattr(sys.modules['__main__'], 'dog'))
getattr(sys.modules['__main__'], 'pig')()#加()执行反

7.反射hasattr(object, name)

参考链接:http://www.zzvips.com/article/97990.html

作用:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的)。

>>> hasattr(list, 'append')
True >>> hasattr(list, 'add')
False
#
#
class A:
    Role = '治疗'
    def __int__(self):
        self.name = 'cookei'
        self.age = 84

    def func(self):
        print('wahaha')
        return 666
    
if hasattr(a, 'func'):
    if callable(getattr(a, 'func')):
        getattr(a, 'func')()