面向对象

面向对象编程 是一种思想
对象就是具体的拥有准确属性值的一些变量
类:一类具有相同属性和方法的事物

 

类的定义 class关键字 类名的首字母大写
类中直接定义属性:静态属性(变量)动态属性(函数)
类名的两个作用:属性引用实例化对象
类和属性的操作:类名.属性名 类名.__dict__['属性名'](不能修改)

class Person:  # 类名有两个作用
    country = '中国'  # 静态属性、数据属性
    def __init__(self,life_value,aggr,name,job):  # 初始化方法
        self.lv = life_value  # 属性,对象属性
        self.aggr = aggr
        self.name = name
        self.job = job
    def walk(self):  # 动态属性、函数属性、方法
        print('%s is walking'%self.name)

属性引用

print(Person.walk)
# print(Person.walk())  # 报错 少参数
print(Person.__dict__)
print(Person.__dict__['country'])  # 中国
# Person.__dict__['country'] = '印度'  # 报错 不能改变
print(Person.country)  # 中国 静态属性的查看
Person.role = ''  # 添加一个新静态属性
print(Person.role)  #
del Person.role  # 删除一个静态属性
Person.country = '印度'  # 修改一个静态属性
print(Person.country)  # 印度

实例化对象

实例化:从一个类中创造一个具体的对象的过程

print(callable(Person))  # True
p = Person()
print(p)  # <__main__.Person object at 0x00000000028CD198> Person的对象

实例化——类名(参数)
构造方法:造对象
初始化:给这个对象添加一些属性 __init__
返回了一个初始化之后的对象
如何让对象拥有具体的属性
__init__方法:初始化方法,可以没有,给对象添加一些必要的基础属性
self的含义:就是这个对象本身

p = Person(1000,2,'金老板','boss')
print(p.lv)  # 1000
print(p.aggr)  # 2
print(p.name)  # 金老板
print(p.job)  # boss
print(p.__dict__)  # {'lv': 1000, 'aggr': 2, 'name': '金老板', 'job': 'boss'}
print(p.__dict__['lv'])  # 1000
p.__dict__['lv'] = 998  # 对象名.__dict__中的属性值可以被修改
print(p.__dict__['lv'],p.lv)  # 998 998
p.__dict__['sex'] = 'ladyboy'  # 对象名.__dict__中的属性值可以增加
print(p.sex)  # ladyboy
p.__dict__.pop('sex')  # 对象名.__dict__中的属性值可以被删除

p.sex = 'ladyboy'  # 添加一个属性
print(p.sex)
p.sex = 'girl'  # 属性的修改
del p.sex  # 删除一个属性
# 对象和属性的操作:对象名.属性名 对象名.__dict__['属性名']

# Person.walk(p)  # 金老板 is walking
p.walk()  # Person.walk(p)

 

面向对象交互

简单的人狗大战

class Person:
    def __init__(self,life_value,aggr,name,job):
        self.name = name
        self.aggressive = aggr
        self.life = life_value
        self.job = job
    def attack(self,dog_obj):
        print('%s 攻击了 %s'%(self.name,dog_obj.name))
        dog_obj.life = dog_obj.life - self.aggressive



class Dog:
    def __init__(self,life_value,aggr,name,kind):
        self.life = life_value
        self.aggressive = aggr
        self.name = name
        self.kind = kind
    def bite(self,person):
        print('%s 攻击了 %s'%(self.name,person.name))
        person.life = person.life - self.aggressive

dog = Dog(1000,100,'铁蛋','土狗')
boss_gold = Person(100,2,'太黑','old_driver')
boss_gold.attack(dog)
print(dog.life)
dog.bite(boss_gold)
print(boss_gold.life)

 

面向对象的命名空间

属性:静态属性(直接和类名关联的对象或者直接定义在class下的变量)、对象属性(在类内和self关联,在类外和对象名关联的变量)

类名操作变量 不管操作可变还是不可变数据类型 都是类中对应的变量发生变化
对象名操作静态变量
引用变量:先在自己的命名空间中查找,找不到就去类的命名空间找
修改变量:
如果是对可变数据类型中的元素进行修改,那么全局生效
如果是对变量进行重新赋值,那么只是在对象自己的命名空间里增加了一个新的属性

class Foo:
    country = 'China'
    country_lst = ['China']
    def __init__(self,name):
        self.name = name

alex = Foo('alexander')
egg = Foo('egon')
alex.age = 90
Foo.role = 'Person'
print(Foo.country)
print(alex.name)
print(egg.name)
print(alex.country)
print(alex.role)
alex.country = '印度'
print(alex.country)  # 印度
print(egg.country)  # China
print(Foo.country)  # China
del alex.country
alex.country_lst.append('印度')
print(alex.country_lst)  # ['China', '印度']
print(egg.country_lst)  # ['China', '印度']
print(Foo.country_lst)  # ['China', '印度']

设计一个类,统计这个类被实例化的次数,且所有的对象共享这个属性

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

f1 = Foo()
f2 = Foo()
print(f1.count)

对象使用名字的顺序:先用自己的,再用类的
对象可以使用类的
而类无法使用对象的

 

组合

组合:什么有什么的关系
一个对象的属性是另外一个类的对象

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

# 老师有生日:年月日
class Birthday:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
birthday1 = Birthday(1968,12,31)
boss_gold = Teacher('太亮',40,'不详')
boss_gold.birth = birthday1
boss_gold.birth.year
# 将一个类的对象拥有的属性 再将其定义成一个类以提高代码的复用

class Teacher:
    def __init__(self,name,age,sex,year,month,day):
        self.name = name
        self.age = age
        self.sex = sex
        self.birth = Birthday(year,month,day)
class Birthday:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
boss_gold = Teacher('太亮',40,'不详',1968,12,31)

圆和圆环

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

class Ring:
    def __init__(self,outer_r,inner_r):
        self.outer_circle = Circle(outer_r)
        self.inner_circle = Circle(inner_r)
    def perimeter(self):
        return self.outer_circle.perimeter()+self.inner_circle.perimeter()
    def area(self):
        return self.outer_circle.area()-self.inner_circle.area()

r1 = Ring(10,5)
print(r1.area())

人狗大战组合

class Dog:  # 定义一个狗类
    def __init__(self, name, breed, aggressivity, life_value):
        self.name = name  # 每一只狗都有自己的昵称;
        self.breed = breed  # 每一只狗都有自己的品种;
        self.aggressivity = aggressivity  # 每一只狗都有自己的攻击力;
        self.life_value = life_value  # 每一只狗都有自己的生命值;
    def bite(self,person):
        person.life_value -= self.aggressivity

class Person:  # 定义一个人类
    def __init__(self, name, aggressivity, life_value,money):
        self.name = name  # 每一个角色都有自己的昵称;
        self.aggressivity = aggressivity  # 每一个角色都有自己的攻击力;
        self.life_value = life_value  # 每一个角色都有自己的生命值;
        self.money = money
    def attack(self,dog):
        dog.life_value -= self.aggressivity
    def get_weapon(self,weapon_obj):
        if self.money > weapon_obj.price:
            self.money -= weapon_obj.price
            self.weapon = weapon_obj
            self.aggressivity += weapon_obj.aggr

boss_gold = Person('金老板',5,250,100)
huang = Dog('大黄','藏獒',100,3000)
huang.bite(boss_gold)
print(boss_gold.life_value)
# 人有武器——组合
class Weapon:
    def __init__(self,name,price,aggr):
        self.name = name
        self.price = price
        self.aggr = aggr
dgb = Weapon('打狗棒',99.8,100)
boss_gold.get_weapon(dgb)

 

继承

继承:至少两个类 什么是什么的关系,为了避免几个类之间有相同的代码
父类:Animal
子类:Dog、Person

class Animal:
    def __init__(self,name, aggressivity, life_value):
        self.name = name
        self.aggressivity = aggressivity
        self.life_value = life_value
class Dog(Animal):
    def bite(self,person):
        person.life_value -= self.aggressivity
class Person(Animal):
    def attack(self,dog):
        dog.life_value -= self.aggressivity

huang = Dog('大黄',100,3000)  # __init__ 找父类
boss_gold = Person('',10,100)

查看继承的类

print(Dog.__bases__)  # (<class '__main__.Animal'>,)
print(Animal.__bases__)  # (<class 'object'>,)

python两种类:经典类 新式类
python3 所有类都是新式类——都默认继承object class Animal(object): == class Animal:
python2 经典类和新式类并存:
class Animal: 经典类 —— 继承顺序 个别使用方法
class Animal(object): 新式类

两个类中有相同的代码
继承:把相同的代码放在父类中,子类的对象在子类中没有找到方法的时候,使用父类的
单继承和多继承

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
    pass

父类 超类 基类
子类 派生类
抽象和继承

人 狗 有相同属性的同时 还有一些不同的属性

class Animal:
    def __init__(self,name, aggressivity, life_value):
        self.name = name
        self.aggressivity = aggressivity
        self.life_value = life_value
    def eat(self):
        self.life_value += 10

class Dog(Animal):
    def __init__(self,name,breed,aggressivity,life_value):
        Animal.__init__(self,name,aggressivity,life_value)
        self.breed = breed  # 派生属性:父类没有的属性
    def bite(self,person):  # 派生方法:父类没有的方法
        person.life_value -= self.aggressivity
    def eat(self):
        Animal.eat(self)
        print('dog is eating')

class Person(Animal):
    def __init__(self,name, aggressivity, life_value,money):
        Animal.__init__(self, name, aggressivity, life_value)
        self.money = money
    def attack(self,dog):
        dog.life_value -= self.aggressivity

snoopy = Dog('太白','京巴',250,500)
print(snoopy.life_value)
snoopy.eat()
print(snoopy.life_value)

派生属性:在自己的init方法里使用父类的init方法——指名道姓调用
派生方法:在子类中增加父类没有的
父类没有 子类有: 子类
子类没有 父类有: 父类
父类有 子类有: 子类
父类有 子类有: 想用父类的 —— Animal.eat(snoopy)
父类有 子类有: 父类子类都想用 —— 在子类中指名道姓的调用父类的方法
只要子类有,就用子类的
只要想用父类,父类名.父类的方法名(子类对象) 2.7经典类中

在新式类中:super()

class Animal:
    def __init__(self,name, aggressivity, life_value):
        self.name = name
        self.aggressivity = aggressivity
        self.life_value = life_value
    def eat(self):
        self.life_value += 10

class Dog(Animal):
    def __init__(self,name,breed,aggressivity,life_value):
        # Animal.__init__(self,name,aggressivity,life_value)
        # super(Dog,self).__init__(name, aggressivity, life_value)
        super().__init__(name, aggressivity, life_value)  # 新式类
        self.breed = breed  # 派生属性:父类没有的属性
    def bite(self,person):  # 派生方法:父类没有的方法
        person.life_value -= self.aggressivity
    def eat(self):
        # Animal.eat(self)
        super().eat()
        print('dog is eating')

class Person(Animal):
    def __init__(self,name, aggressivity, life_value,money):
        # Animal.__init__(self, name, aggressivity, life_value)
        super().__init__(name, aggressivity, life_value)
        self.money = money
    def attack(self,dog):
        dog.life_value -= self.aggressivity

snoopy = Dog('太白','京巴',250,500)
super(Dog,snoopy).eat()

用子类的对象调用父类的方法:
如果子类中没有这个方法,直接就使用父类的
如果子类中有同名方法:
经典类 指名道姓 类名.方法名(子类对象) 类内外一致
新式类 super方法 super(子类名,子类对象).方法名() 类内可以省略super的参数

class Foo:
    def __init__(self):
        self.func()
    def func(self):
        print('Foo.func')

class Son(Foo):
    def func(self):
        print('Son.func')

s = Son()  # Son.func

 

经典类和新式类的多继承问题,继承顺序问题

# python2中
class A:pass  # 经典类
class A(object):pass  # 新式类

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

print(A.mro())  # 查看继承顺序 新式类才有

 

多态

class Person:
    def attack(self):
        pass
class Dog:
    def attack(self):
        pass

def attack(obj):  # 多态
    obj.attack()

d = Dog()
p = Person()
attack(d)  # d.attack()
attack(p)  # p.attack()

鸭子类型
list tuple是一对鸭子类型
切片:字符串 列表 元组
+:字符串 列表 数字

 

接口类

接口类:是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
接口类不能被实例化,它只能被继承
支持多继承
接口隔离原则:使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口

from abc import ABCMeta,abstractmethod
class
Payment(metaclass=ABCMeta): # 元类 模板,接口类 @abstractmethod # 装饰接口类中方法的,加上了这个装饰器,自动检测子类中的方法名 def pay(self,money):pass class Apple_Pay(Payment): def pay(self,money): print('您使用苹果支付了%s元'%money) class Ali_Pay(Payment): def pay(self,money): print('您使用支付宝支付了%s元'%money) class WeChat_Pay(Payment): def pay(self,money): print('您使用微信支付了%s元'%money) def pay(obj,money): return obj.pay(money) apple = Apple_Pay() ali = Ali_Pay() wechat = WeChat_Pay()

 

抽象类

模板 规范
抽象类可以实现一些子类共有的功能和属性
抽象类不鼓励多继承
文件操作:打开文件 关闭文件 写文件 读文件
硬盘操作: 打开 关闭 写 读
进程文件: 打开 关闭 写 读
python没有接口的概念
只能借助抽象类的模块来实现接口类
接口 —— java:没有多继承 —— Interface

抽象类不能被实例化
这个抽象类可以规范子类必须实现抽象类中的抽象方法

from abc import ABCMeta,abstractmethod
class Base(metaclass=ABCMeta):
    def __init__(self,filename):
        self.filename = filename
    @abstractmethod  # 抽象方法
    def open(self):
        return 'file_handler'
    @abstractmethod
    def close(self):pass
    @abstractmethod
    def read(self):pass
    @abstractmethod
    def write(self):pass

class File(Base):
    def open(self):pass
    def close(self):pass
    def read(self):pass
    def write(self):pass

 

封装

class Dog:
    __role = 'dog'  # 私有静态属性
    # def func(self):
    #     print(Dog.__role)
    def __func(self):
        print('in__func')
# print(Dog.__role)  # 报错
print(Dog.__dict__)  # '_Dog__role': 'dog'
print(Dog._Dog__role)  # dog 从类的外面不能直接调用,在类外的使用加上了一层密码:_类名

d = Dog()
# d.func()  # dog
d._Dog__func()  # in__func

定义一个私有变量\属性\方法: __名字
在类的内部直接使用: __名字
在类的外部不能直接使用,如果一定要用,在私有方法之前加上: __类名,变成 _类名__名字
在类外的名字 通过__dict__查看

class Room:
    def __init__(self,name,price,length,width):
        self.name = name
        self.price = price
        self.__length = length  # 私有的对象属性
        self.__width = width

    def area(self):
        return self.__length*self.__width

house = Room('房子',1000000,2,1)
print(house.area())

私有的
私有的静态属性、方法、对象属性
使用__名的方式调用,保证在类内部可以调用,外部不行
私有的 不能被继承
当有一个名字,不想被外部使用也不想被子类继承,只想在内部使用的时候就定义私有的

class Person:
    def __init__(self,name,height,weight):
        self.name = name
        self.height = height
        self.weight = weight
    @property
    def bmi(self):
        return self.weight / (self.height**2)
li = Person('李岩',1.75,85)
print(li.bmi)

@property 把一个方法伪装成一个属性
1.属性的值 是这个方法的返回值
2.这个方法不能有参数了

from math import pi
class Circle:
    def __init__(self,r):
        self.radius = r
    @property
    def perimeter(self):
        return 2*pi*self.radius
    @property
    def area(self):
        return pi*self.radius**2
c1 = Circle(5)
print(c1.perimeter)
print(c1.area)

class Goods:
    __discount = 0.8  # 静态属性
    def __init__(self,name,price):
        self.name = name
        self.__price = price  # 原价
    @property
    def price(self):  # 折后价
        return self.__price*Goods.__discount
    @price.setter
    def price(self,new_price):  # 修改原价
        if type(new_price) is int:
            self.__price = new_price

apple = Goods('苹果',10)
apple.kind = '富士'
apple.price = 6
print(apple.price)

封装
__私有+property
让对象的属性变得更安全了
获取到的对象的值可以进行一些加工
修改对象的值的同时可以进行一些验证

伪装后属性的修改和删除

class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')

    @AAA.setter
    def AAA(self,value):
        print('set的时候运行我啊')

    @AAA.deleter
    def AAA(self):
        print('delete的时候运行我啊')

# 只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1 = Foo()
f1.AAA
f1.AAA = 'aaa'
del f1.AAA

 

classmethod和staticmethod

类方法
调用:不需要实例化 直接用类名调用就好
定义:不用接收self参数,默认传cls,cls就代表当前方法所在的类
什么时候用类方法
需要使用静态变量且不需要和对象相关的任何操作的时候

class Goods:
    __discount = 0.8
    @classmethod  # 类方法
    def change_discount(cls,new_discount):
        cls.__discount = new_discount
    @classmethod
    def get_discount(cls):
        return cls.__discount
Goods.change_discount(0.75)
print(Goods.get_discount())

静态方法
如果这个方法既不需要操作静态变量也不需要使用对象相关的操作,就使用静态方法

class A:
    @staticmethod
    def func():
        print(123)

面向对象编程: 专门为面向对象编程提供的一个方法——staticmethod
它完全可以当作普通的函数去用,只不过这个函数要通过类名.函数名()调用
其他 传参 返回值 完全没有区别

类里面:一共可以定义三种方法
普通方法 self
类方法 cls
静态方法

 

绑定方法和非绑定方法

class A:
    @staticmethod
    def func1():
        print(123)
    @classmethod
    def func2(cls):
        print(123)
    def func3(self):pass
a = A()
print(a.func1)  # 静态方法 <function A.func1 at 0x000000000236AA60>
print(a.func2)  # 类方法 <bound method A.func2 of <class '__main__.A'>> 绑定到A类的func
print(a.func3)  # 普通方法 <bound method A.func3 of <__main__.A object at 0x000000000236B668>> 绑定到A类对象的func

静态方法和类方法 都是直接可以使用类名调用
普通方法:对象调用

posted on 2017-11-17 15:08  杨小天  阅读(192)  评论(0编辑  收藏  举报