面向对象

一.面向对象

1.先来定义模子,用来描述一类事物,具有相同的属性和动作

class Person:   #类名

    def __init__(self,name,sex,job):  #必须叫__init__这个名字,不能改变,所有的在一个具体的人物出现之后的拥有的属性l;'
        self.men.name=name
        self.sex=sex
        self.job = job
        alex = Person('alex','不详','搓澡工')
        #alex就是对象  
        #alex = Person()的过程 是通过类获取一个对象的过程 - 实例化
        # Person是一个类 :alex wusir都是这个类的对象
# 类有一个空间,存储的是定义在class中的所有名字
# 每一个对象又拥有自己的空间,通过对象名.__dict__就可以查看这个对象的属性和值
        

 


class 类名:
    def __init__(self,参数1,参数2):
        self.对象的属性1 = 参数1
        self.对象的属性2 = 参数2

    def 方法名(self):pass

    def 方法名2(self):pass

对象名 = 类名(1,2)  #对象就是实例,代表一个具体的东西
                  #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
                  #括号里传参数,参数不需要传self,其他与init中的形参一一对应
                  #结果返回一个对象
对象名.对象的属性1   #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名()     #调用类中的方法,直接用 对象名.方法名() 即可


类名()会自动调用类中___init__方法

2.属性的操作

 print(alex.name)   # print(alex.__dict__['name'])  属性的查看
 alex.name = 'alexsb'    # 属性的修改
alex.money = 1000000     # 属性的增加
 del alex.money           # 属性的删除

3.类和对象的关系

类 是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值

对象 是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性赋上具体的值

4.实例化经历的步骤

1.类名() 之后的第一个事儿 :开辟一块儿内存空间

2.调用 init 把空间的内存地址作为self参数传递到函数内部

3.所有的这一个对象需要使用的属性都需要和self关联起来

4.执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方)

5.类的方法使用

class Person:       # 类名
    def __init__(self,n=[],sex,job,hp,weapon,ad):
        # 必须叫__init__这个名字,不能改变的,所有的在一个具体的人物出现之后拥有的属性
        self.name = n          # 对象的属性/实例变量
        self.sex = sex
        self.hp = hp
        self.ad = ad

    def 搓(self,dog):    # 方法,又有一个必须传的参数-->self对象
        dog.hp -= self.ad
        print('%s给%s搓了澡,%s掉了%s点血,%s当前血量%s'%(self.name,dog.dog_name,
                                            dog.dog_name,self.ad,dog.dog_name,dog.hp))

6.类的成员和命名空间

class A:
    Country = '中国'     # 静态变量/静态属性 存储在类的命名空间里的
    def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的
        self.name = name
        self.age = age
    def func1(self):
        print(self)
    def func2(self):pass
    def func3(self):pass
    def func4(self):pass
    def func5(self):pass

a = A('alex',83,'印度')
b = A('wusir',74,'泰国人')
A.Country = '日本人'
print(a.Country)
print(b.Country)
print(A.Country)
# 命名空间
    # 在类的命名空间里 : 静态变量 绑定方法
    # 在对象的命名空间里 : 类指针 对象的属性(实例变量)

    # 调用的习惯
        # 类名.静态变量
        # 对象.静态变量 (对象调用静态变量的时候,不能对变量进行赋值操作 对象.静态变量 = 1UI27)

        # 绑定方法
        # 对象.绑定方法()

        # 对象.实例变量
# 组合
    # 一个类的对象是另一个类对象的属性
    # 两个类之间 有 什么有什么的关系 : 班级有学生 学生有班级 班级有课程 图书有作者 学生有成绩

类中的变量是静态变量,

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

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

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

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

# 实现一个类,能够自动统计这个类实例化了多少个对象
class A:pass
A.Country = 123   # 属性的增加
print(A.Country)  # 查看或者引用

class A:
    count = 0
    def __init__(self):
        A.count += 1

a1 = A()
print(a1.count)
a2 = A()
print(A.count)

# 类中的静态变量的用处
# 如果一个变量 是所有的对象共享的值,那么这个变量应该被定义成静态变量
# 所有和静态变量相关的增删改查都应该使用类名来处理
# 而不应该使用对象名直接修改静态变量

实例化对象未被引用内存地址为同一个,实例

class Person:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def __hash__(self):
        return hash(self.name+self.sex)

    def __eq__(self, other):
        if self.name == other.name and self.sex == other.sex:return True


p_lst = []
for i in range(84):
    # print(id(Person('egon',i,'male')))
    # p_lst.append(Person('egon', i, 'male'))
    a = Person('egon',i,'male')
    print(id(a))
    p_lst.append(a)

7.组合

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

# 学生类
    # 姓名 性别 年龄 学号 班级 手机号
# 班级信息
    # 班级名字
    # 开班时间
    # 当前讲师
# 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.cname = cname
#         self.begint = begint
#         self.teacher = teacher

# 查看的是大壮的班级的开班日期是多少
# 查看的是雪飞的班级的开班日期是多少
# py22 = Clas('python全栈22期','2019-4-26','小白')
# py23 = Clas('python全栈23期','2019-5-28','宝元')
# 大壮 = Student('大壮','male',18,27,py23,13812012012)
# 雪飞 = Student('雪飞','male',18,17,py22,13812012013)
# print(大壮.clas,py23)
# print(py23.begint)
# print(大壮.clas.begint)

# 练习 :
# 对象变成了一个属性
# 班级类
    # 包含一个属性 - 课程
# 课程
    # 课程名称
    # 周期
    # 价格

# 创建两个班级 linux57
# 创建两个班级 python22
# 查看linux57期的班级所学课程的价格
# 查看python22期的班级所学课程的周期

class Clas:
    def __init__(self,cname,begint,teacher):
        self.cname = cname
        self.begint = begint
        self.teacher = teacher
class Course:
    def __init__(self,name,period,price):
        self.name = name
        self.period = period
        self.price = price
py22 = Clas('python全栈22期','2019-4-26','小白')
linux57 = Clas('linux运维57期','2019-3-27','李导')
linux58 = Clas('linux运维58期','2019-6-27','李导')
python = Course('python','6 months',21800)
linux = Course('linux','5 months',19800)
py22.course = python
linux57.course = linux
linux58.course = linux
print(py22.course.period)
print(linux57.course.price)
linux.price = 21800
print(linux57.course.price)
print(linux58.course.price)

# class Clas:
#     def __init__(self,cname,begint,teacher,cprice,cperiod):
#         self.cname = cname
#         self.begint = begint
#         self.teacher = teacher
#         self.cprice = cprice    # 课程价格
#         self.cperiod = cperiod  # 课程周期
# linux57 = Clas('linux运维57期','2019-3-27','李导',19800,'5 months')
# linux58 = Clas('linux运维58期','2019-3-27','李导',19800,'5 months')
# linux59 = Clas('linux运维59期','2019-3-27','李导',19800,'5 months')
# linux60 = Clas('linux运维60期','2019-3-27','李导',19800,'5 months')
# linux61 = Clas('linux运维51期','2019-3-27','李导',19800,'5 months')
# linux57.cprice = 21800
# linux58.cprice = 21800

8.继承

 ___需要解决代码的重复

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('%s is eating'%self.name)
    def drink(self):
        print('%s is drinking'%self.name)
    def sleep(self):
        print('%s is sleeping'%self.name)
class Cat(Animal):
    def climb_tree(self):
        print('%s is climbing'%self.name)

class Dog(Animal):
    def house_keep(self):
        print('%s house keeping'%self.name)

小白 = Cat('小白')
    # 先开辟空间,空间里有一个类指针-->指向Cat
    # 调用init,对象在自己的空间中找init没找到,到Cat类中找init也没找到,
    # 找父类Animal中的init
# 当子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了

# 子类想要调用父类的方法的同时还想执行自己的同名方法
# 猫和狗在调用eat的时候既调用自己的也调用父类的,
# 在子类的方法中调用父类的方法 :父类名.方法名(self)

class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food
        self.blood = 100
        self.waise = 100
    def eat(self):
        print('%s is eating %s'%(self.name,self.food))
    def drink(self):
        print('%s is drinking'%self.name)
    def sleep(self):
        print('%s is sleeping'%self.name)

class Cat(Animal):
    def eat(self):
        self.blood += 100
        Animal.eat(self)
    def climb_tree(self):
        print('%s is climbing'%self.name)
        self.drink()

class Dog(Animal):
    def eat(self):
        self.waise += 100
        Animal.eat(self)
    def house_keep(self):
        print('%s is keeping the house'%self.name)
小白 = Cat('小白','猫粮')
小黑 = Dog('小黑','狗粮')
小白.eat()
小黑.eat()
print(小白.__dict__)
print(小黑.__dict__)
# 继承语法 class 子类名(父类名):pass
# 父类和子类方法的选择:
    # 子类的对象,如果去调用方法
    # 永远优先调用自己的
        # 如果自己有 用自己的
        # 自己没有 用父类的
        # 如果自己有 还想用父类的 : 直接在子类方法中调父类的方法 父类名.方法名(self)

        
# 单继承  只有一个爹
# 调子类的 : 子类自己有的时候
# 调父类的 : 子类自己没有的时候
# 调子类和父类的 :子类父类都有,在子类中调用父类的

# 多继承  有多个爹
# 一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找

继承分为经典类和新式类

# 只要继承object类就是新式类
# 不继承object类的都是经典类

# python3 所有的类都继承object类,都是新式类
# 在py2中 不继承object的类都是经典类
#          继承object类的就是新式类了

# 经典类 :在py3中不存在,在py2中不主动继承object的类

# 在py2中
# class A:pass         # 经典类
# class B(object):pass # 新式类
# 在py3中
# class A:pass         # 新式类
# class B(object):pass # 新式类

# 在单继承方面(无论是新式类还是经典类都是一样的)
# class A:
#     def func(self):pass
# class B(A):
#     def func(self):pass
# class C(B):
#     def func(self):pass
# class D(C):
#     def func(self):pass
# d = D()
# 寻找某一个方法的顺序:D->C->B->A
# 越往父类走,是深度

# 多继承
class A:
    def func(self):
        print('A')

class B(A):
    pass
    # def func(self):
    #     print('B')
class C(A):
    pass
    # def func(self):
    #     print('C')
class D(B,C):
    pass
    # def func(self):
    #     print('D')
print(D.mro())   # 只在新式类中有,经典类没有的
# d = D()
# d.func()
# 在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
# 在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了

# C3算法
# A(O) = [AO]
# B(A) = [BAO]
# C(A) = [CAO]
# D(B) = [DBAO]
# E(C) = [ECAO]

# F(D,E) = merge(D(B) + E(C))
#          = [F] + [DBAO] + [ECAO]
#        F = [DBAO] + [ECAO]
#     FD   = [BAO] + [ECAO]
#     FDB  = [AO] + [ECAO]
#     FDBE = [AO] + [CAO]
#     FDBEC= [AO] + [AO]
#     FDBECA= [O] + [O]
#     FDBECAO

# 算法的内容
    # 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
    # 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,...
    # merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个
                # 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
                # 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类

# 经典类 - 深度优先 新式类 - 广度优先
# 深度优先要会看,自己能搞出顺序来
# 广度优先遵循C3算法,要会用mro,会查看顺序
# 经典类没有mro,但新式类有

9.抽象类多态和鸭子类型

# 普通的类
# 抽象类 是一个开发的规范 约束它的所有子类必须实现一些和它同名的方法
# 支付程序
    # 微信支付 url连接,告诉你参数什么格式
        # {'username':'用户名','money':200}
    # 支付宝支付 url连接,告诉你参数什么格式
        # {'uname':'用户名','price':200}
    # 苹果支付
# class Payment:     # 抽象类
#     def pay(self,money):
#         '''只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法'''
#         raise NotImplementedError('请在子类中重写同名pay方法')
#
# class Alipay(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'uname':self.name,'price':money}
#         # 想办法调用支付宝支付 url连接 把dic传过去
#         print('%s通过支付宝支付%s钱成功'%(self.name,money))
#
# class WeChat(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'username':self.name,'money':money}
#         # 想办法调用微信支付 url连接 把dic传过去
#         print('%s通过微信支付%s钱成功'%(self.name,money))
#
# class Apple(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'name': self.name, 'number': money}
#         # 想办法调用苹果支付 url连接 把dic传过去
#         print('%s通过苹果支付%s钱成功' % (self.name, money))

# aw = WeChat('alex')
# aw.pay(400)
# aa = Alipay('alex')
# aa.pay(400)
# 归一化设计
# def pay(name,price,kind):
#     if kind == 'Wechat':
#         obj = WeChat(name)
#     elif kind == 'Alipay':
#         obj = Alipay(name)
#     elif kind == 'Apple':
#         obj = Apple(name)
#     obj.pay(price)
#
# pay('alex',400,'Wechat')
# pay('alex',400,'Alipay')
# pay('alex',400,'Apple')

# appa = Apple('alex')
# appa.fuqian(500)


# 实现抽象类的另一种方式,约束力强,依赖abc模块
# from abc import ABCMeta,abstractmethod
# class Payment(metaclass=ABCMeta):
#     @abstractmethod
#     def pay(self,money):
#         '''只要你见到了项目中有这种类,你要知道你的子类中必须实现和pay同名的方法'''
#         raise NotImplementedError('请在子类中重写同名pay方法')
#
# class Alipay(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'uname':self.name,'price':money}
#         # 想办法调用支付宝支付 url连接 把dic传过去
#         print('%s通过支付宝支付%s钱成功'%(self.name,money))
#
# class WeChat(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'username':self.name,'money':money}
#         # 想办法调用微信支付 url连接 把dic传过去
#         print('%s通过微信支付%s钱成功'%(self.name,money))
#
# WeChat('alex')


# 多态
# def add(int a,int b):
#     return a+b
#
# print(add(1,'asuhjdhDgl'))

# class Payment:pass
# class WeChat(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'username':self.name,'money':money}
#         # 想办法调用微信支付 url连接 把dic传过去
#         print('%s通过微信支付%s钱成功'%(self.name,money))
#
# class Apple(Payment):
#     def __init__(self,name):
#         self.name = name
#     def pay(self,money):
#         dic = {'name': self.name, 'number': money}
#         # 想办法调用苹果支付 url连接 把dic传过去
#         print('%s通过苹果支付%s钱成功' % (self.name, money))

#JAVA
# def pay(Payment a, int b):
#     a.pay(b)
# obj = Apple('alex')
# pay(obj,400)
# obj = WeChat('alex')
# pay(obj,400)

# 一个类型表现出来的多种状态
# 支付 表现出的 微信支付和苹果支付这两种状态
# 在java情况下: 一个参数必须制定类型
# 所以如果想让两个类型的对象都可以传,那么必须让这两个类继承自一个父类,在制定类型的时候使用父类来指定

# 鸭子类型
# class list:
#     def __init__(self,*args):
#         self.l = [1,2,3]
#     def __len__(self):
#         n = 0
#         for i in self.l:
#             n+= 1
#         return n
# l = [1,2,3]
# l.append(4)
# def len(obj):
#     return obj.__len__()

# 所有实现了__len__方法的类,在调用len函数的时候,obj都说是鸭子类型
# 迭代器协议 __iter__ __next__ 是迭代器
# class lentype:pass
# class list(lentype):pass
# class dict(lentype):pass
# class set(lentype):pass
# class tuple(lentype):pass
# class str(lentype):pass
#
# def len(lentype obj):
#     pass

# len(list)
# len(dict)
# len(set)
# len(tuple)
# len(str)

# class list:
#     def __len__(self):pass
# class dict:
#     def __len__(self): pass
# class set:
#     def __len__(self): pass
# class tuple:
#     def __len__(self): pass
# class str:
#     def __len__(self): pass
# def len(鸭子类型看起来有没有实现一个__len__ obj):
#     return obj.__len__()

多态抽象类总结

# 类的种类
    # 新式类 : 继承object,存在在py2,py3(py3中都是新式类,py2里主动继承object的才是新式类)
    # 经典类 : 只在py2中,不继承object默认是经典类
# 继承顺序
    # 深度优先 : 经典类
    # 广度优先 : 新式类
        # 查看广度优先的顺序 : 类名.mro()
        # 遵循的算法 :C3
# 抽象类
    # 为什么要用抽象类 : 为了规范子类必须实现和父类的同名方法
    # 抽象类用到的格式(至少会写一种,两种见到了都要认识)
       # 不需要模块的
       # class 父类:
       #     def 子类必须实现的方法名(self,参数们):
       #         raise NotImplementedError('提示信息')
       # class 子类(父类):
       #     def 父类要求实现的方法(self,参数们):
       #         print('''code''')
      # 需要模块的
        # from abc import ABCMeta,abstractmethod
        # class 父类(metaclass = ABCMeta):
        #     @abstractmethod
        #     def 子类必须实现的方法名(self,参数们):pass
        # class 子类(父类):
        #     def 父类要求实现的方法(self,参数们):
        #         print('''code''')
# 归一化设计
    # class A:
    #     def 同名功能(self):pass
    # class B:
    #     def 同名功能(self):pass
    #
    # def 函数名(obj):
    #     obj.同名功能()
# 多态
    # 什么是多态 : 一个类表现出的多种形态,实际上是通过继承来完成的
                #  如果狗类继承动物类,猫类也继承动物类
                #  那么我们就说猫的对象也是动物类型的
                #  狗的对象也是动物类型的
                # 在这一个例子里,动物这个类型表现出了猫和狗的形态
    # java中的多态是什么样
        # def eat(动物类型 猫的对象/狗的对象,str 食物):
        #     print('动物类型保证了猫和狗的对象都可以被传递进来')
    # python中的多态是什么样 : 处处是多态
    # 鸭子类型
        # 子类继承父类,我们说子类是父类类型的(猫类继承动物,我们说猫也是动物)
        # 在python中,一个类是不是属于某一个类型
        # 不仅仅可以通过继承来完成
        # 还可以是不继承,但是如果这个类满足了某些类型的特征条件
        # 我们就说它长得像这个类型,那么他就是这个类型的鸭子类型

# 就记住两件事儿:
    # 所有的类都必须继承object
    # 如果见到了抽象类的写法,一定要知道要在子类中实现同名方法

10.super 封装 类的三个装饰器

super

 # 在py3中怎么用?在py2(新式类/经典类)中怎么用?
    在py3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法
    在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名(), 这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法
    在py2的经典类中,并不支持使用super来找下一个类 
    # 在单继承中执行父类的同名方法的时候怎么用?
    在单继承的程序中,super就是找父类
    # super方法和mro方法的关系是什么?
    super是按照mro顺序来寻找当前类的下一个类
    
 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()
        super(D,self).func()
        print('D')
# D().func()
# D,B,C,A
# 在D类中找super的func,那么可以这样写 super().func()
# 也可以这样写 super(D,self).func() (并且在py2的新式类中必须这样写)

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

广义 :把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
狭义 :把属性和方法藏起来,外面不能调用,只能在内部偷偷调用
class User:
    def __init__(self,name,passwd):
        self.usr = name
        self.__pwd = passwd  # 私有的实例变量/私有的对象属性
alex = User('alex','sbsbsb')
print(alex.__pwd)  # 报错
print(alex.pwd)    # 报错


封装的语法:
#给一个名字前面加上了双下划线的时候,这个名字就变成了一个私有的
# 所有的私有的内容或者名字都不能在类的外部调用,只能在类的内部使用了
  • 使用私有的三种情况

    1.不想让你看也不想让你改
    2.可以让你看 但不让你改
    3.可以看也可以改 但是要求你按照我的规则改

    # class User:
    # __ter = 'ID更多官方' #1.私有的静态变量
    # def init(self,name,passwd):
    # self.usr = name
    # self.__pwd = passwd #2. 私有的实例变量/私有的对象属性
    # def get_pwd(self): #3. 表示的是用户不能改只能看 私有 + 某个get方法实现的
    # return self.__pwd
    # def change_pwd(self):
    pass
    # 表示用户必须调用我们自定义的修改方式来进行变量的修改 私用 + change方法实现

    私有的特点:

    可以在类的内部使用,不可以在类的外部使用,不能在类的子类中使用

    原理:

    # 加了双下划线的名字为啥不能从类的外部调用了?
    # class User:
    # __Country = 'China' # 私有的静态变量
    # __Role = '法师' # 私有的静态变量
    # def func(self):
    # print(self.__Country) # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形
    # print(User._User__Country)
    # print(User._User__Role)
    # __Country -->'_User__Country': 'China'
    # __Role -->'_User__Role': '法师'
    # User.__aaa = 'bbb' # 在类的外部根本不能定义私有的概念

类中变量级别,哪些是python支持,哪些是python不支持的

# public  公有的 类内类外都能用,父类子类都能用         python支持
# protect 保护的 类内能用,父类子类都能用,类外不能用    python不支持
# private 私有的 本类的类内部能用,其他地方都不能用     python支持

  类中的三个装饰器

@property

property作用:1. 把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
            2.给伪装的属性方法赋值@函数名.setter装饰器
    
 from math import pi
# class Circle:
#     def __init__(self,r):
#         self.r = r
#
#     @property  # 装饰的这个方法 不能有参数
#     def area(self):
#         return pi * self.r**2
#
# c1 = Circle(5)
# print(c1.r)
# print(c1.area)

property 的进阶 setter和delter
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):
            self.__price = new_value

    @price.deleter
    def price(self):
        del self.__price
apple = Goods('apple',5)
print(apple.price) # 调用的是被@property装饰的price
apple.price = 'ashkaksk'# 调用的是被setter装饰的price
del apple.price   # 并不能真的删除什么,只是调用对应的被@price.deleter装饰的方法而已
print(apple.price)

判断一个变量是不是可调用的,判断这个变量后面能不能加括号 : callable(名字)

11.反射.

使用条件:有些时候你明明知道一个变量的字符串数据类型的名字,你想调用它,但是调不到,就可以使用反射

反射中的几种情况:

# 1.反射对象的 实例变量/绑定方法
# 2.反射类的 静态变量/绑定方法/其他方法
# 3.模块中的 所有变量
    # 被导入的模块
    # 当前执行的py文件 - 脚本
 
getattr和hasattr
#字符串数据类型的变量名,采用getattr(对象,'变量名')获取变量的值
class A:
    Role = '治疗'
    def __init__(self):
        self.name = 'alex'
        self.age = 84
    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')()

@classmethod : 被装饰的方法会成为一个类方法

把一个对象绑定的方法,修改成一个类方法

  • 什么时候可以使用:1.定义了一个方法,默认传self,但是没有使用self
    2.并且你在这个方法里用到了当前类名,或者你准备使用这个类的内存空间的名字的时候
  • 好处:1.第一个在方法中仍然可以引用类中的静态变量

       2.可以不用实例化对象,就直接用类名在外部调用这个方法

使用方法调用方法及例子

classmethod  被装饰的方法会成为一个类方法
class Goods:
    __discount = 0.8
    def __init__(self):
        self.__price = 5
        self.price = self.__price * self.__discount
    @classmethod   # 把一个对象绑定的方法 修改成一个 类方法
    def change_discount(cls,new_discount):
        cls.__discount = new_discount
        
 # Goods.change_discount(0.6)   # 类方法可以通过类名调用
# apple = Goods()
# print(apple.price)
# apple.change_discount(0.5)  # 类方法可以通过对象名调用
# apple2 = Goods()
# print(apple2.price)

@staticmethod 被装饰的方法会成为一个静态方法

本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加@staticmethod就可以,这个函数的内部既不会用到self变量,也不会用到cls类

例子及调用方式

class User:
    pass
    @staticmethod
    def login(a,b):      # 本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加@staticmethod装饰器就可以了
        print('登录的逻辑',a,b)
        # 在函数的内部既不会用到self变量,也不会用到cls类

obj = User()
User.login(1,2)
obj.login(3,4)

能定义到类中的内容

  • 静态变量 是个所有对象共享的变量 由对象\类调用,但是不能重新赋值
  • 绑定方法 是个自带self参数的函数 由对象调用
  • 类方法 是个自带cls参数的函数 由对象\类调用
  • 静态方法 是个啥也不带的函数 由对象\类调用
  • property属性 是个伪装成属性的方法 由对象调用 但是不加括号

12.内置的魔术方法

1.__new__
#什么时候执行?
 实例化的时候
 1.先创建一块对象的空间,有一个指针能指向类 --> __new__
 2. 调用init --> __init__

#为什么要有,用来做什么?
    创建一个对象需要的空间
#面试会考  单例模式
class Baby:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance
    def __init__(self,cloth,pants):
        self.cloth = cloth
        self.pants = pants
b1 = Baby('红毛衣','绿皮裤')
print(b1.cloth)
b2 = Baby('白衬衫','黑豹纹')
print(b1.cloth)
print(b2.cloth)

2.__call__  对象() 调用这个类中的__call__方法

# callable(对象)
# 对象() 能不能运行就是callable判断的事儿

class A:
    def __call__(self, *args, **kwargs):
        print('-------')

# obj = A()
# print(callable(obj))
# obj()
# A()()
# Flask框架的源码


3.__len__  : len(对象) 需要实现这个类中的__len__方法
 例子及调用方法
class Cls:
    def __init__(self,name):
        self.name = name
        self.students = []
    def len(self):
        return len(self.students)
    def __len__(self):
        return len(self.students)
py22 = Cls('py22')
py22.students.append('杜相玺')
py22.students.append('庄博')
py22.students.append('大壮')
print(py22.len())
print(len(py22))

4.__str__和__rerp__
在打印一个对象的时候 调用__str__方法
在%s拼接一个对象的时候 调用__str__方法
在str一个对象的时候   调用__str__方法

例子
class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period
    def __str__(self):
        return self.name
python = Course('python',21800,'6 months')
linux = Course('linux',19800,'5 months')
mysql = Course('mysql',12800,'3 months')
go = Course('go',15800,'4 months')
print(go)

for index,c in enumerate(lst,1):
    print(index,c)
num = int(input('>>>'))
course = lst[num-1]
print('恭喜您选择的课程为 %s  价格%s元'%(course.name,course.price))

class clas:
    def __init__(self):
        self.student = []
    def append(self,name):
        self.student.append(name)
    def __str__(self):
        return str(self.student)

py22 = clas()
py22.append('大壮')
print(py22)
print(str(py22))
print('我们py22班 %s'%py22)
print(py22)
py22.append('大壮')
print(py22)

__repr__方法
# 当我们打印一个对象 用%s进行字符串拼接 或者str(对象)总是调用这个对象的__str__方法
# 如果找不到__str__,就调用__repr__方法
# __repr__不仅是__str__的替代品,还有自己的功能
# 用%r进行字符串拼接 或者用repr(对象)的时候总是调用这个对象的__repr__方法

转载于:https://www.cnblogs.com/cui-xuefei/p/11232190.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值