面向对象基础

锲子

 

# 参加工作
# 游戏公司
# 人狗大战
# 角色 的属性固定下来
# 人 :昵称、性别、血、攻击力
# 狗 :名字、品种、血、攻击力
def Person(name,sex,hp,ad):
    # 人模子
    self = {'name': name, 'sex':sex, 'hp': hp, 'ad': ad}
    def attack(dog): # 闭包
        # 人攻击狗
        print('%s攻击%s' % (self['name'], dog['name']))
        # 狗掉血,狗的血量-人的攻击力
        dog['hp'] -= self['ad']
    self['attack'] = attack
    return self

def Dog(name,kind,hp,ad):
    # 狗模子
    self = {'name': name, 'kind':kind, 'hp': hp, 'ad': ad}
    def bite(person):
        print('%s咬了%s' % (self['name'], person['name']))
        # 人掉血,人的血量-狗的攻击力
        person['hp'] -= self['ad']
        if person['hp'] <= 0: print('game over,%s win' % self['name'])
    def bite2():pass
    self['bite'] = bite
    self['bite2'] = bite2
    return self

# 人 规范了属性的个数 简化了创造任务的代码
alex = Person('a_sb','不详',1,5)
boss_jin =Person('金老板','',2,50)

#
chen = Dog('旺财','teddy',50,20)
alex['attack'](chen)
print(chen['hp'])

一、面向对象编程基础

1.1、概念

  类的概念 : 具有相同属性和技能的一类事物
        人类 抽象
  对象 : 就是对一个类的具体的描述
      具体的人 具体

  使用面向对象的好处:

  • 使得代码之间的角色关系更加明确
  • 增强了代码的可扩展性
  • 规范了对象的属性和技能
  • 面向对象的特点:结局的不确定性

1.2、语法

  类名:

  引用静态变量

   1.类名.__dict__['静态变量名']可以查看,但是不能删除

   2.类名.静态变量名 直接就可以访问,可以删除

      删除一个静态变量  del  类名.静态变量名

  引用动态变量

   1.类名.方法名  查看这个方法的内存地址

   2.类名.方法名(实参)  调用了这个方法,必须传一个实参,这个实参传给了self

  创造一个对象--实例化

    产生一个实例(对象)的过程

    对象 = 类名()

  例子:alex = Person()  #创造一个对象

     alex是对象、实例

     Person是类

     对象 = 类名()

# class Person:
#     role = 'person'   # 静态属性
#     def f1(self):     # 动态属性 方法(函数)  默认带一个参数self
#         print(1234567)
# 查看静态变量的第一种方式
# print(Person.__dict__)   # 内置的双下方法
# print(Person.__dict__['静态变量'])
# Person.__dict__['静态变量'] = 456  # 报错
# print(Person.__dict__['静态变量'])

# 查看静态变量的第二种方式
# print(Person.静态变量)   # 123 值
# print(Person.role)
# Person.静态变量 = 456
# print(Person.静态变量)
# del Person.静态变量
# print(Person.__dict__)

  实例化的过程:

    1、创造一个实例,将会作为一个实际参数  #python

    2、自动触发一个__init__的方法,并且把实例以参数的形式传递给__init__方法中的self形参

    3、执行完__init__方法之后,会将self自动返回给alex

  __init__方法:初始化方法,给一个对象添加一些基础属性的方法,一般情况下是针对self的赋值

  对象

    在类的内部  self是本类的一个对象

    在类的外部,每一个对象都对应着一个名字,这个对象指向一个对象的内存空间

    属性的调用:

      对象名.属性名  第一种调用方法

      对象名.__dict__[‘属性名’]  第二种调用方法

    方法的调用:

      类名.方法名(对象名)  那么方法中的self参数就指向这个对象

      对象名.方法名()    这样写相当于方法中的self参数直接指向这个对象

class Person:
    role = 'person'   # 静态属性
    def __init__(self,name,sex,hp,ad):
        self.name = name     # 对象属性 属性
        self.sex = sex
        self.hp = hp
        self.ad = ad
    def attack(self):
        print('%s发起了一次攻击'%self.name)

alex = Person('a_sb','不详',1,5)
boss_jin = Person('金老板','',20,50)

alex.attack()      # Person.attack(alex)
boss_jin.attack()  # Person.attack(boss_jin)

# alex = Person('a_sb','不详',1,5)
# alex.__dict__['name'] = 'alex'
# print(alex.name)
# alex.name = 'a_sb'
# print(alex.name)
# boss_jin = Person('金老板','女',20,50)
# print(boss_jin.name)

1.3、交互

class Person:
    role = 'person'   # 静态属性
    def __init__(self,name,sex,hp,ad):
        self.name = name     # 对象属性 属性
        self.sex = sex
        self.hp = hp         #血量
        self.ad = ad         #攻击力
    def attack(self,d):
        d.hp -= self.ad
        print('%s攻击了%s,%s掉了%s点血'%(self.name,d.name,d.name,self.ad))

class Dog:
    def __init__(self,name,kind,hp,ad):
        self.name = name
        self.kind = kind
        self.hp = hp
        self.ad = ad
    def bite(self,p):
        p.hp -= self.ad
        print('%s咬了%s一口,%s掉了%s点血' % (self.name, p.name, p.name, self.ad))

alex = Person('a_sb','不详',1,5)
boss_jin = Person('金老板','',20,50)
teddy = Dog('笨笨','teddy',50,10)
teddy.bite(alex)
print(alex.hp)
boss_jin.attack(teddy)
print(teddy.hp)

1.4、命名空间和作用域

# class Person:
#     role = 'person'   # 静态属性
#     def __init__(self,name,sex,hp,ad):
#         self.name = name     # 对象属性 属性
#         self.sex = sex
#         self.hp = hp
#         self.ad = ad
#     def attack(self):
#         self.hobby = 'girl'
#         print('%s发起了一次攻击'%self.name)
#
# alex = Person('a_sb','不详',1,5)
# alex.attack()   # Person.attack(alex)
# alex.age = 81
# # alex --> Person
# # Person实例化了alex
# print(alex.__dict__)

# alex.name   #alex 指向我自己的内存空间 在自己的内存空间里找到name
# alex.attack #alex 先找自己的内存空间 再找到类对象指针 再根据类对象指针找到类 再通过类找到attack
# 对象的内存空间里: 只存储对象的属性,而不存储方法和静态属性
# 方法和静态属性都存储在类的内存空间中
# 为了节省内存,让多个对象去共享类中的资源


# class Person:
#     role = 'person'   # 静态属性
#     def __init__(self,name,sex,hp,ad):
#         self.name = name     # 对象属性 属性
#         self.sex = sex
#         self.hp = hp
#         self.ad = ad
#         self.attack = 'hahaha'
#     def attack(self):
#         print('%s发起了一次攻击'%self.name)
#
# alex = Person('a_sb','不详',1,5)
# boss_jin = Person('金老板','女',50,20)
# print(alex.role)
# print(boss_jin.role)
# alex.role = 'dog'
# print(alex.role)
# print(boss_jin.role)    # dog or ? person



# class Person:
#     role = 'person'   # 静态属性
#     def __init__(self,name,sex,hp,ad):
#         self.name = name     # 对象属性 属性
#         self.sex = sex
#         self.hp = hp
#         self.ad = ad
#         self.attack = 'hahaha'
#     def attack(self):
#         print('%s发起了一次攻击'%self.name)
#
# alex = Person('a_sb','不详',1,5)
# boss_jin = Person('金老板','女',50,20)
# print(alex.role)
# print(boss_jin.role)
# alex.role = 'dog'
# print(alex.role)
# 模拟人生
# class Person:
#     money = 0
#     def __init__(self,name):
#         self.name = name
#     def work(self):
#         print(self.name,'工作,赚了1000块钱')
#         Person.money += 1000
#
# father = Person('father')
# mother = Person('mother')
# mother.work()
# father.work()
# print(Person.money)


# 写一个类 完成一个功能 : 可以统计这个类有几个对象
# class Foo:
#     count = 0
#     def __init__(self):
#         Foo.count += 1
# f1 = Foo()
# f2 = Foo()
# f3 = Foo()
# f4 = Foo()
# f5 = Foo()
# print(Foo.count)  #



# class Person:
#     money = [1]
#     def __init__(self,name):
#         self.name = name
#     def work(self):
#         print(self.name,'工作,赚了1000块钱')
#         self.money[0] += 1000
#
# father = Person('father')
# mother = Person('mother')
# mother.work()
# father.work()
# print(Person.money)   # 2000 or 0?

# class Person:
#     money = [0]
#     def __init__(self,name):
#         self.name = name
#     def work(self):
#         print(self.name,'工作,赚了1000块钱')
#         Person.money =  [Person.money[0] + 1000]
#
# father = Person('father')
# mother = Person('mother')
# mother.work()
# father.work()
# print(Person.money)

# 对象属性是独有的,静态属性和方法是共享的
# 对象使用名字:先找自己内存空间中的,再找类的内存空间中的
# 类名.静态变量名 :对于静态属性的修改,应该使用类名直接修改
#
# 计算圆的周长 2 pi r
# 计算圆的面积 pi r**2
# 5个圆
# 1,3,5,7,9
from math import pi
class Circle:
    def __init__(self,r):
        self.r = r
    def cal_area(self):
        '''
        计算圆面积的方法
        :return:返回值是float数据类型的面积
        '''
        return pi*self.r**2
    def cal_perimeter(self):
        '''
        计算圆周长的方法
        :return:返回值是float数据类型的周长
        '''
        return pi * self.r * 2
for i in range(1,10,2):
    c1 = Circle(i)
    print(c1.cal_area())
    print(c1.cal_perimeter())
# 类 属性 和 方法
    # 半径
    # 计算面积 计算周长
# 程序的解耦
    # 当计算的规模足够大的时候 我们应该在编码的过程当中让操作尽量原子化
    # 尽量用返回值来代替print

# 面向对象的基础

# 用面向对象的思想
# 1.博客上的练一练
# 2.计算圆环的面积和周长
# 3.默写 交互
# 4.校园管理系统第一步

 1.5、组合

  组合:一个类的对象作为另一个类对象的属性

    表示的  一种  什么有什么的关系

class Person:
    def __init__(self,name,sex,hp,ad):
        self.name = name
        self.sex = sex
        self.hp = hp
        self.ad = ad
        self.money = 0
    def attack(self,d):
        d.hp -= self.ad
        print('%s攻击了%s,%s掉了%s点血' % (self.name,d.name,d.name,self.ad))
    def pay(self):
        money = int(input('请输入充值金额'))
        self.money += money
        print('您的余额是:%s' % self.money)
    def wear(self,weapon):
        if self.money >= weapon.price:
            self.weapon = weapon
            self.money -= weapon.price
            print('购买成功,您已经顺利装备了%s' % weapon.name)
        else:
            print('余额不足,请充值')
class Dog:
    def __init__(self,name,kind,hp,ad):
        self.name = name
        self.kind = kind
        self.hp = hp
        self.ad = ad
    def bite(self,p):
        p.hp -= self.ad
        print('%s咬了%s一口,%s掉了%s点血' % (self.name,p.name,p.name,self.ad))
class Weapon:
    def __init__(self,name,price,ad,level):
        self.name = name
        self.price = price
        self.level = level
        self.ad = ad * self.level
    def skill(self,dog):
        dog.hp -= self.ad
        print('%s受到了%s的伤害,%s掉了%s点血' % (dog.name,self.name,dog.name,self.ad))

a_alex = Person('张凯峻','',300,200)
a_dog = Dog('小白','teddy',200,100)
a_alex.pay()
wear = Weapon('打狗棒',100,20,2)
a_alex.wear(wear)
a_alex.weapon.skill(teddy)

# 组合 :一个对象的属性值是另外一个类的对象
#     a_alex.weapon 是 Weapon类的对象

# 圆形类
# 写一个圆环类 组合 圆形类 去完成 计算圆环的面积和周长
# 一个类的对象作为另一个类对象的属性
# 圆环中有圆

# 圆形类 : 计算圆形面积 和 周长
# 圆环类 :
    # 圆环的周长 : 大圆周长加小圆周长
    # 圆环的面积 :  大圆的面积 - 小圆的面积

# class Ring1:
#     def __init__(self,out_r,in_r):
#         self.out_r = out_r
#         self.in_r = in_r
#     def cal_area(self):
#         return abs(pi*self.out_r**2 - pi*self.in_r**2)
#     def cal_perimeter(self):
#         return pi * self.out_r * 2 + pi * self.in_r * 2

# from math import pi
# class Circle:   # 圆形的面积公式不会变
#     def __init__(self,r):
#         self.r = r
#     def cal_area(self):
#         return pi*self.r**2
#     def cal_perimeter(self):
#         return pi * self.r * 2

#
# class Ring2:  # 圆环
#     def __init__(self,out_r,in_r):
#         c1_obj = Circle(out_r)
#         self.out_circle = c1_obj
#         self.in_circle = Circle(in_r)
#     def area(self):
#         return self.out_circle.cal_area() - self.in_circle.cal_area()
#     def cal_perimeter(self):
#         return self.out_circle.cal_perimeter() + self.in_circle.cal_perimeter()
#
#
# r1 = Ring2(10,5)
# print(r1.area())
# print(r1.cal_perimeter())

# 老师
# 姓名 年龄 性别 班级 : s11

# 班级
# 班级名 班级人数 科目 性质

class Clas:
    def __init__(self,name,num,course,type):
        self.name = name
        self.num = num
        self.course = course
        self.type = type

class Teacher:
    def __init__(self,name,sex,age,py11):
        self.name = name
        self.sex = sex
        self.age = age
        self.cls = py11

py11 = Clas('超级无敌s11',89,'python','脱产全栈')
print(py11.course)

boss_jin = Teacher('太白','',40,py11)
print(py11.course)          # 11期的课程
print(boss_jin.cls.course)  # 金老板所带的班级的课程
print(boss_jin.cls.name)  # 金老板所带的班级的课程
print(boss_jin.cls.num)  # 金老板所带的班级的课程

1.6、继承

# 类与类之间的关系: 什么是什么的关系
# 单继承
# class Parent:pass
# class Son(Parent):pass   # 继承关系
# # Son继承了Parent
# print(Son.__bases__)  # 内置的属性
# print(Parent.__bases__)  # 内置的属性
#
# 在python3中,所有的类都会默认继承object类
# 继承了object类的所有类都是新式类
# 如果一个类没有继承任何父类,那么__bases__属性就会显示<class 'object'>

# 多继承
# class Parent1:pass
# class Parent2(Parent1):pass
# class Parent3:pass
# class Son(Parent2,Parent3):pass   # 继承关系
# print(Parent2.__bases__)
# print(Son.__bases__)

# 父类 :基类 超类
# 子类 :派生类
class Animal:
    role = 'Animal'
    def __init__(self,name,hp,ad):
        self.name = name     # 对象属性 属性
        self.hp = hp         #血量
        self.ad = ad         #攻击力

    def eat(self):
        print('%s吃药回血了'%self.name)

class Person(Animal):
    r = 'Person'
    def attack(self,dog):   # 派生方法
        print("%s攻击了%s"%(self.name,dog.name))

    def eat2(self):
        print('执行了Person类的eat方法')
        self.money = 100
        self.money -= 10
        self.hp += 10

class Dog(Animal):
    def bite(self,person):  # 派生方法
        print("%s咬了%s" % (self.name, person.name))

# 先有了人 狗两个类
# 发现两个类有相同的属性、方法
# 人和狗 都是游戏里的角色
# 抽象出一个animal类型
# 继承

# 继承中的init
# alex = Person('alex',10,5)
# print(Person.__dict__)   # role
# print(Person.role)
# print(alex.__dict__)
# dog = Dog('teddy',100,20)
# print(dog)
# print(dog.__dict__)

# 继承中的派生方法
# alex = Person('alex',10,5)
# dog = Dog('teddy',100,20)
# alex.attack(dog)
# dog.bite(alex)

# 继承父类的方法:自己没有同名方法
# alex = Person('alex',10,5)
# dog = Dog('teddy',100,20)
# alex.eat2()
# alex.eat()
# dog.eat()

# 对象使用名字的顺序: 先找对象自己内存空间中的,再找对象自己类中的,再找父类中的
# alex = Person('alex',10,5)
# alex.eat = 'aaa'
# print(alex.eat())  # 报错

# self.名字的时候,不要看self当前在哪个类里,要看这个self到底是谁的对象
class Parent:
    def func(self):
        print('in parent func')
    def __init__(self):
        self.func()

class Son(Parent):
    def func(self):
        print('in son func')

s = Son()

 

class Animal:
    def __init__(self,name,hp,ad):
        self.name = name     # 对象属性 属性
        self.hp = hp         #血量
        self.ad = ad         #攻击力
    def eat(self):
        print('eating in Animal')
        self.hp += 20

class Person(Animal):
    def __init__(self,name,hp,ad,sex):        # 重写
        # Animal.__init__(self,name,hp,ad)
        # super(Person,self).__init__(name,hp,ad)   # 在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传self
        super().__init__(name,hp,ad)   # 在单继承中,super负责找到当前类所在的父类,在这个时候不需要再手动传self
        self.sex = sex      # 派生属性
        self.money = 100
    def attack(self,dog):   # 派生方法
        print("%s攻击了%s"%(self.name,dog.name))
    def eat(self):                         # 重写
        super().eat()  # 在类内 使用 super()方法找父类的方法
        print('eating in Person')
        self.money -= 50

class Dog(Animal):
    def __init__(self,name,hp,ad,kind):
        Animal.__init__(self,name,hp,ad)
        self.kind = kind    # 派生属性
    def bite(self,person):  # 派生方法
        print("%s咬了%s" % (self.name, person.name))

# 人 sex
alex = Person('alex',100,10,'female')   # 实例化
print(alex.__dict__)

# 父类有eat 子类没有
# alex.eat() # 找父类的
# 子类有eat 不管父类中有没有
# alex.eat() # 找子类的
# 当子类中有,但是我想要调父类的
# Animal.eat(alex)          #指名道姓
# super(Person,alex).eat()  # super(子类名,子类对象)方法   —— 一般不用
# 子类父类都有eat方法,我想执行父类的eat和子类的eat
alex.eat()  # 执行子类的eat
print(alex.__dict__)
#
# 对象
# Person.attack(alex)   # alex.attack()

# 狗 kind
# tg = Dog('到哥',100,50,'藏獒')
# print(tg.__dict__)
# # 多继承
# 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):
#     pass
#     # def func(self):
#     #     print('D')
# class E(B,C):
#     pass
#     def func(self):
#         print('E')
# class F(D,E):
#     pass
#     # def func(self):
#     #     print('F')
# f = F()
# f.func()
# print(F.mro())  # 广度优先的遍历顺序

# 新式类 多继承 寻找名字的顺序 遵循广度优先
# 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()   # B
#         print('D')
#
# d = D()
# d.func()

# super():
#     在单继承中就是单纯的寻找父类
#     在多继承中就是根据子节点 所在图 的 mro顺序找寻下一个类
# 遇到多继承和super
    # 对象.方法
        # 找到这个对象对应的类
        # 将这个类的所有父类都找到画成一个图
        # 根据图写出广度优先的顺序
        # 再看代码,看代码的时候要根据广度优先顺序图来找对应的super
# print(eval('1+2+3+4'))
code1 = 'for i in range(0,10): print (i)'
compile1 = compile(code1,'','exec')
exec(compile1)
class A(object):
    pass
    # def func(self):
    #     print('A')
class B(A):
    pass
    # def func(self):
    #     print('B')
class C(A):
    def func(self):
        print('C')
class D(B,C):
    def func(self):
        super(D,self).func()
        print('D')

D.mro()
# 经典类 :在python2.*版本才存在,且必须不继承object
#     遍历的时候遵循深度优先算法
#     没有mro方法
#     没有super()方法
# 新式类 :在python2.X的版本中,需要继承object才是新式类
    # 遍历的时候遵循广度优先算法
    # 在新式类中,有mro方法
    # 有super方法,但是在2.X版本的解释器中,必须传参数(子类名,子类对象)
d = D()
d.func()
# 归一化设计
l = [1,2,2]
# l2 = {1,2,3,4}
# l3 = (1,2)
# a = '1234567'
# print(len(l))
# print(l3.__len__())
# len()  和 __len__()
# 只有一个类中实现了__len__()方法,才能使用len()函数
def len2(obj):  # 归一化设计
    return obj.__len__()

print(len(l))
# print(len(l2))
# print(len(l3))
# 抽象类和接口类
# java 编程原则和设计模式
# 设计模式  程序设计 具有里程碑意义的设计方式 从java中演变出来的
    # 单例模式
        # 一个类只有一个实例
## 算法导论  计算的方法 时间和空间的问题 权威通用

# java
    # 面向对象
    # java不能多继承
# 编程原则
    # python
    # 开放封闭原则
        # 开放 对扩展是开放的
        # 封闭 对修改是封闭的
    # 依赖倒置原则
    # 接口隔离原则
# 已经写完的程序代码是不允许修改的

# 支付功能的例子
    # 支付宝支付
    # qq支付
    # apply_pay
    # 微信支付

# 创建一个规范
# from abc import ABCMeta,abstractmethod
# class Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
#     @abstractmethod
#     def pay(self):pass  # 抽象方法
#
# class Alipay(Payment):
#     def pay(self,money):
#         print('使用支付宝支付了%s元'%money)
#
# class QQpay(Payment):
#     def pay(self,money):
#         print('使用qq支付了%s元'%money)
#
# class Wechatpay(Payment):
#     def pay(self,money):
#         print('使用微信支付了%s元'%money)
#     def recharge(self):pass
#
# def pay(a,money):
#     a.pay(money)
#
# a = Alipay()
# a.pay(100)
# pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
# q = QQpay()
# # q.pay(100)
# pay(q,100)
# w = Wechatpay()
# pay(w,100)   # 到用的时候才会报错



# 抽象类和接口类做的事情 :建立规范
# 制定一个类的metaclass是ABCMeta,
# 那么这个类就变成了一个抽象类(接口类)
# 这个类的主要功能就是建立一个规范

# 抽象类中所有被abstractmethod装饰的方法都必须被继承的子类实现
# 如果不实现,那么在实例化阶段将会报错

# 无论是抽象类还是接口类metaclass=ABCMeta 都不可以被实例化
# p = Payment()  # 报错
# 什么叫接口
# python里没有接口的概念
# 那接口是哪儿来的概念呢?
    # java类没有多继承 接口可以实现多继承
# 描述动物园
# 会游泳的 会走路的 会爬树的 会飞的
# 老虎
# 青蛙
# 天鹅
# 猴子
from abc import ABCMeta,abstractmethod
class FlyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass
    @abstractmethod
    def cal_flying_speed(self):pass
    @abstractmethod
    def cal_flying_height(self):pass
class WalkAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):pass
class SwimAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):pass
class Tiger(WalkAnimal,SwimAnimal):
    def walk(self):pass
    def swim(self):pass
class Monkey:
    def walk(self):pass
    def climb(self):pass
class Swan(FlyAnimal,WalkAnimal,SwimAnimal):
    def swim(self):pass
    def walk(self):pass
    def fly(self):pass
    def cal_flying_speed(self):pass
    def cal_flying_height(self):pass
class Parrot(FlyAnimal):
    def fly(self):pass
    def cal_flying_speed(self):pass
    def cal_flying_height(self): pass
# 所有会飞的动物 具有一些会飞的动物的特性
# 所有会走的动物 具有一些会走的动物的特性

# 接口类的作用:
    # 在java中,能够满足接口隔离原则,且完成多继承的约束
    # 而在python中,满足接口隔离原则,由于python本身支持多继承,所以就不需要接口的概念了

# 抽象类和接口类
# 在python中
#     并没有什么不同,都是用来约束子类中的方法的
#     只要是抽象类和接口类中被abstractmethod装饰的方法,都需要被子类实现
#     需要注意的是,当多个类之间有相同的功能也有不同的功能的时候,应该采用多个接口类来进行分别的约束

# 在java中
    # 抽象类和接口截然不同
    # 抽象类的本质还是一个类 是类就必须遵循单继承的规则,所以一个子类如果被抽象类约束,那么它只能被一个父类控制
    # 当多个类之间有相同的功能也有不同的功能的时候 java只能用接口来解决问题

# 面试的时候
    # 抽象类 是python中定义类的一种规范
    # 接口
# 在公司类写代码的时候
    # 如果遇到抽象类 记得按照抽象类中的规范一一实现对应的方法

1.7、多态

# 介于 强类型 与 弱类型之间 —— python 动态强类型语言
# 相同数据类型之间做运算
# def func(a):pass
# class Payment:
#     def pay(self):pass
#
# class QQpay(Payment):
#     def pay(self,money):
#         print('使用qq支付了%s元'%money)
#
# class Wechatpay(Payment):
#     def pay(self,money):
#         print('使用微信支付了%s元'%money)
#     def recharge(self):pass

# def pay(Payment pay_obj,int money):   #  java 多态 在一个类之下发展出来的多个类的对象都可以作为参数传入这里
#     pay_obj.pay(money)

# 无论是python的2.*还是3.* : 天生自带多态效果

# qq_obj = QQpay()
# print(type(qq_obj))  # 一个对象的数据类型就是它所在的类
# # # qq_obj.pay(100)
# pay(qq_obj,100)
# we_obj = Wechatpay()
# # # we_obj.pay(200)
# pay(we_obj,200)
# def len(object obj):pass
# class len_class:pass
# class tuple(len_pass):pass
# class list(len_pass):pass
# class str(len_pass):pass
# tuple list str dict set

# 鸭子类型
# class QQpay():
#     def pay(self,money):
#         print('使用qq支付了%s元'%money)
#
# class Wechatpay():
#     def pay(self,money):
#         print('使用微信支付了%s元'%money)
#
# def pay(pay_obj,money):
#     pay_obj.pay(money)

# 索引
class list:
    def index(self):pass
class str:
    def index(self):pass
class tuple:
    def index(self):pass
# [].index()
# ''.index()
# ().index()


# 多态和鸭子类型
# 多态 通过继承实现
    # java 在一个类之下发展出来的多个类的对象都可以作为参数传入一个函数或者方法
    # 在python中不需要刻意实现多态,因为python本身自带多态效果
# 鸭子类型
    # 不是通过具体的继承关系来约束某些类中必须有哪些方法名
    # 是通过一种约定俗成的概念来保证在多个类中相似的功能叫相同的名字

1.8、封装

# 封装 :
    # 广义上的
    # 狭义上的 :会对一种现象起一个专门属于它的名字

# 把一堆东西装在一个容器里

# 函数和属性装到了一个非全局的命名空间 —— 封装
# class A:
#     __N = 'aaa'  # 静态变量
#
# print(A.__N)

# python
# pulic 公有的
# private 私有的

# java完全面向对象的语言
# public 公有的
# protect 保护的
# private 私有的

# 定义一个私有的名字 : 就是在私有的名气前面加两条下划线 __N = 'aaa'
# 所谓私有,就是不能在类的外面去引用它
# class A:
#     __N = 'aaa'  # 静态变量
#     def func(self):
#         print(A.__N)  # 在类的内部使用正常
#
# a = A()
# a.func()
# print(A.__N)   # 在类的外部直接使用 报错


# class A:
#     __N = 'aaa'  # 静态变量
#     def func(self):
#         print(A.__N)  # 在类的内部使用正常
#
# print(A.__dict__)
# print(A._A__N)   # python就是把__名字当成私有的语法

# 一个私有的名字 在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到。
# python对其的名字进行了修改: _类名__名字
# 只不过在类的外部调用 :需要“_类名__名字”去使用
# 在类的内部可以正常的使用名字

# _A__N
# 在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字


# 私有的属性
# class B:
#     def __init__(self,name):
#         self.__name = name
#     def func(self):
#         print('in func : %s'%self.__name)
# b = B('alex')
# # print(b._B__name)
# b.func()

# 私有的方法
# class C:
#     def __wahaha(self):
#         print('wahaha')
#     def ADCa(self):
#         self.__wahaha()
# c = C()
# # c._C__wahaha()
# c.ADCa()

# 在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__

# class D:
#     def __func(self):      # '_D__func'
#         print('in func')
#
# class E(D):
#     def __init__(self):
#         self.__func()      # '_E__func'
# e = E()
# 私有的名字不能被子类继承


# class D:
#     def __init__(self):
#         self.__func()
#     def __func(self):
#         print('in D')
#
# class E(D):
#     def __func(self):
#         print('in E')
# e = E()
# 私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
# 以此为例 :没有双下换线会先找E中的func
# 但是有了双下划线,会在调用这个名字的类D中直接找_D__func

# class F:
#     pass
# F.__name = 'alex'  # 不是在创建私有属性
# print(F.__name)
# print(F.__dict__)
# 变形只在类的内部发生

# class F:
#     def ADCa(self):
#         self.__name = 'alex'   # _F__name
#
# f = F()
# f.ADCa()
# print(f._F__name)

# java中的对比
# public 公有的    在类的内部可以使用,子类可以使用,外部可以使用    python中所有正常的名字
# protect 保护的   在类的内部可以使用,子类可以使用,外部不可以使用  python中没有
# private 私有的   只能在类的内部使用,子类和外部都不可以使用        python中的__名字

# 私有的用法
# 当一个方法不想被子类继承的时候
# 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用

# 描述一个房子
    # 单价
    # 面积
    # 长宽高
# class Room:
#     def __init__(self,name,price,length,width,height):
#         self.name = name
#         self.price = price
#         self.__length = length
#         self.__width = width
#         self.__height = height
#
#     def area(self):
#         return self.__length*self.__width

# r = Room('鹏鹏',100,2,1,0.5)
# print(r.name)
# print(r.price)
# print(r.area())

# class Person:
#     def __init__(self,name,pwd):
#         self.name = name
#         self.__pwd(pwd)
#     def __pwd(self,pwd):
#         # '12345' ---> ascii ---> 2175981070935
#         self.my_secret_pwd = 2175981070935
# 人体BMI指数
# 体质指数(BMI)=体重(kg)÷身高^2(m)
# 写一个类 描述人体BMI指数

class Person:
    def __init__(self,name,weight,height):
        self.name = name
        self.__height = height
        self.__weight = weight
        # self.bmi = self.__weight / self.__height ** 2
        # self.bmi = self.cal_BMI()

    def cal_BMI(self):
        return self.__weight / self.__height ** 2

    @property
    def bmi(self):
        return self.__weight / self.__height ** 2
p = Person('大表哥',92,1.85)
# print(p.cal_BMI())
# p.cal_BMI()   # bmi是一个名词
# print(p.bmi)   # bmi是一个名词
# p._Person__weight = 90
# print(p.bmi)
# 将一个方法伪装成一个属性
    # 并不会让你的代码有什么逻辑上的提高
    # 只是从调用者的角度上换了一种方式,使之看起来更合理

# 单纯的在init中计算
# class Person:
#     def __init__(self,name,weight,height):
#         self.name = name
#         self.__height = height
#         self.__weight = weight
#         self.bmi = self.__weight / self.__height ** 2
#
# p = Person('大表哥',92,1.85)   #
# print(p.bmi)   # bmi是一个名词
# p._Person__weight = 90   # 3天
# print(p.bmi)

# class Person:
#     def __init__(self,name,weight,height):
#         self.name = name
#         self.__height = height
#         self.__weight = weight
#     @property
#     def bmi(self):
#         return self.__weight / self.__height ** 2
#
# p = Person('大表哥',92,1.85)
# print(p.bmi)
# p._Person__weight = 90
# print(p.bmi)

# @property 能够将一个方法伪装成一个属性
# 从原来的的对象名.方法名(),变成了对象名.方法名
# 只是让代码变的更美观

# 如果有重名的名字
# class Person:
#     def __init__(self,name,weight,height):
#         self.name = name
#         self.__height = height
#         self.__weight = weight
#     @property
#     def bmi(self):
#         return self.__weight / self.__height ** 2
# print(Person.__dict__)
# p = Person('大表哥',92,1.85)
# print(p.__dict__)
# print(p.bmi)   # 对这个属性 只能看了

# 被property装饰的bmi仍然是一个方法 存在Person.__dict__
# 对象的.__dict__中不会存储这个属性

# 在一个类加载的过程中,会先加载这个中的名字,包括被property装饰的
# 在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,
# 如果有就不能再在自己对象的空间中创建这个属性了

# 圆形类
# 半径 面积 周长
# from math import pi
# class Circle:
#     def __init__(self,r):
#         self.r = r
#     def cal_area(self):
#         return self.r**2*pi
#     def cal_perimeter(self):
#         return 2*pi*self.r
# c = Circle(10)
# print(c.cal_area())
# print(c.cal_perimeter())

# 将方法伪装成属性,方法中一般涉及的都是一些计算过程
# from math import pi
# class Circle:
#     def __init__(self,r):
#         self.r = r
#     @property
#     def area(self):
#         return self.r**2*pi
#
#     @property
#     def perimeter(self):
#         return 2*pi*self.r
# c = Circle(10)
# print(c.area)
# print(c.perimeter)
# c.r = 15
# print(c.area)
# print(c.perimeter)

# __name setter deleter
# class Person0:
#     def __init__(self,name):
#         self.name = name
#
# p = Person0('alex')
# print(p.name)
# p.name = 'sb'
# p.name = 123

# class Person:
#     def __init__(self,name):
#         self.__name = name  # 私有的属性了
#     @property
#     def name(self):
#         return self.__name
#
#     def set_name(self,new_name):
#         if type(new_name) is str:
#             self.__name = new_name
#         else:
#             print('您提供的姓名数据类型不合法')
#
# p = Person('alex')
# print(p.name)
# # 和直接定义name属性有什么区别???
# p.set_name('alex_sb')
# print(p.name)
# p.set_name(123)
# print(p.name)


# 方法伪装成的属性的修改
# class Person:
#     def __init__(self,n):
#         self.__name = n  # 私有的属性了
#     @property
#     def name(self):
#         return self.__name
#
#     @name.setter        # 重要程度 ***
#     def name(self,new_name):
#         if type(new_name) is str:
#             self.__name = new_name
#         else:
#             print('您提供的姓名数据类型不合法')
#
# p = Person('alex')
# print(p.name)       #def name(self):
# p.name = 'alex_sb' #def name(self,new_name):
# print(p.name)       #def name(self):
# p.name = 123 #def name(self,new_name):
# print(p.name)       #def name(self):

# 方法伪装成的属性的删除
class Person:
    def __init__(self,n):
        self.__name = n  # 私有的属性了
    @property            # 重要程度 ****
    def name(self):
        return self.__name
    # @name.deleter
    # def name(self):
    #     print('name 被删除了')
    # @name.deleter         # 重要程度*
    # def name(self):
    #     del self.__name

# p = Person('alex')
# print(p.name)
# del p.name  # 只是执行了被@name.deleter装饰的函数
# print(p.name)

#@property --> func     将方法伪装成属性,只观看的事儿
#@func.setter --> func  对伪装的属性进行赋值的时候调用这个方法 一般情况下用来做修改
#@func.deleter --> func 在执行del 对象.func的时候调用这个方法 一般情况下用来做删除 基本不用

# 商品的 折扣
# 有一个商品 : 原价 折扣
# 当我要查看价格的时候 我想看折后价
# class Goods:
#     def __init__(self,name,origin_price,discount):
#         self.name = name
#         self.__price = origin_price
#         self.__discount = discount
#
#     @property
#     def price(self):
#         return self.__price * self.__discount
#     @price.setter
#     def price(self,new_price):
#         if type(new_price) is int or type(new_price) is float:
#             self.__price = new_price
# apple = Goods('apple',5,0.8)
# print(apple.price)
# # 修改苹果的原价
# apple.price = 8
# print(apple.price)


# 将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
# 将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性
# 店庆 全场八折
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 * Goods.__discount

    @classmethod
    def change_discount(cls,new_discount):     # 类方法 可以直接被类调用 不需要默认传对象参数 只需要传一个类参数就可以了
        cls.__discount = new_discount

Goods.change_discount(1)  # 不依赖对象的方法 就应该定义成类方法 类方法可以任意的操作类中的静态变量
apple = Goods('apple',5)
banana = Goods('banana',8)
print(apple.price)
print(banana.price)

# 折扣变了 店庆结束 恢复折扣
# apple.change_discount(1)   # 如果要改变折扣 是全场的事情 不牵扯到一个具体的物品 所以不应该使用对象来调用这个方法
# print(apple.price)
# print(banana.price)


# staticmethod
# 当一个方法要使用对象的属性时 就是用普通的方法
# 当一个方法要使用类中的静态属性时 就是用类方法
# 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法

# def login():
#     user= input('user :')
#     if user == 'alex':print('success')
#     else :print('faild')
#
# login()
class Student:
    def __init__(self,name):pass

    @staticmethod
    def login(a):                   # login就是一个类中的静态方法 静态方法没有默认参数 就当成普通的函数使用即可
        user = input('user :')
        if user == 'alex':
            print('success')
        else:
            print('faild')

Student.login(1)

# 完全面向对象编程
# 先登录 后 实例化
# 还没有一个具体的对象的时候 就要执行login方法

# 使用什么样的方法要看具体用到了哪些名称空间中的变量
    # 当一个方法要使用对象的属性时 就是用普通的方法
    # 当一个方法要使用类中的静态属性时 就是用类方法
    # 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法

 

posted @ 2018-04-11 16:50  小杰~~  阅读(255)  评论(0编辑  收藏  举报