面向对象编程
类与对象
class 类名:
属性
类名.属性
类名的作用:操作属性 查看属性
类
对象 = 类名()
过程:
类名()首先会创造出一个对象,创建一个self变量
调用init方法,类名括号里的参数会被质量接收
执行init方法
返回self
调用方法 :
类名.方法名(对象名)
对象名.方法名
对象能做的事:
查看属性
调用方法
__dict__对于对象的增删改查操作都可以通过字典的语法进行
类名能做的事:
实例化
调用方法 要自己传递self参数
调用类中的属性,也就是调用静态属性
__dict__类中的名字只能看 不能操作
self
一个可以存储很多属性的大字典
往字典里添加属性的方式改变了一些变化
class Dog:
def __init__(self,name,blood,aggr,kind):
self.name = name
self.hp = blood
self.aggr = aggr
self.kind = kind
def bite(self, person):
person.blood -= self.aggr
if person.blood <= 0:
print('%s咬了%s,%s被打死了'%(self.name,person.name,person.name))
else:
print('%s咬了%s,掉了%s的血'%(self.name,person.name,self.aggr))
class Person:
def __init__(self, name, blood, aggr, sex):
self.name = name
self.blood = blood
self.aggr = aggr
self.sex = sex
def attack(self,dog):
dog.hp -= self.aggr
if dog.hp <= 0:
print('%s打了%s,%s被打死了'%(self.name,dog.name,dog.name))
else:
print('%s打了%s,掉了%s的血'%(self.name,dog.name,self.aggr))
jin = Dog('金老板',100,20,'teddy')
alex =Person('alex',999,998,'不祥')
jin.bite(alex)
print(alex.blood)
alex.attack(jin)
print(jin.hp)
class Person:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def hiking(self):
print('姓名:%s,年龄:%s,性别:%s,喜欢爬爬山'%(self.name,self.age,self.sex))
def drive(self):
print('姓名:%s,年龄:%s,性别:%s,喜欢开车'%(self.name,self.age,self.sex))
def favor(self):
print('姓名:%s,年龄:%s,性别:%s,喜欢看电视'%(self.name,self.age,self.sex))
ming = Person('小明',20,'男')
ming.hiking()
ming.drive()
ming.favor()
class Circle:
def __init__(self,r):
self.r = r
def area(self):
return pi*self.r**2
def perimeter(self):
return 2*pi*self.r
c1 = Circle(5)
print(c1.area())
print(c1.perimeter())
class Square:
def __init__(self, le):
self.le = le
def area(self):
return self.le*self.le
def perimeter(self):
return self.le*4
s = Square(3)
print(s.area())
print(s.perimeter())
非常明显的处理一类事物,这些事物都具有想死的属性和功能
当有几个函数需要反复传入相同的参数的时候,可以考虑面向对象
这些参数都是对象的属性
类和对象的命名空间
类中的静态变量可以被对象和类调用
对于不可变数据类型,类变量最好用类名操作
对于可变数据类型,修改是共享的,重新赋值是独立的
class Course:
language = 'Chinese'
def __init__(self,teacher,course_name,period,price):
self.teacher = teacher
self.name = course_name
self.period = period
self.price = price
Course.language = 'English'
print(Course.language)
python = Course('egon', 'python', '6 month', 20000)
linux = Course('oldboy', 'linux', '6 month', 20000)
print(python.language)
print(linux.language)
python.language = 'Chinese'
print(python.language)
print(linux.language)
print(python.__dict__)
print(linux.__dict__)
class Course:
language = ['Chinese']
def __init__(self,teacher,course_name,period,price):
self.teacher = teacher
self.name = course_name
self.period = period
self.price = price
# Course.language[0] = 'English'
# print(Course.language)
python = Course('egon', 'python', '6 month', 20000)
linux = Course('oldboy', 'linux', '6 month', 20000)
# print(python.language)
# print(linux.language)
python.language[0] = 'English'
print(python.language)
print(linux.language)
print(Course.language)
print(python.__dict__)
print(linux.__dict__)
# ['English']
# ['English']
# ['English']
# {'teacher': 'egon', 'name': 'python', 'period': '6 month', 'price': 20000}
# {'teacher': 'oldboy', 'name': 'linux', 'period': '6 month', 'price': 20000}
修改
python.language = ['English']
print(python.language)
print(linux.language)
print(Course.language)
print(python.__dict__)
print(linux.__dict__)
# ['English']
# ['Chinese']
# ['Chinese']
# {'teacher': 'egon', 'name': 'python', 'period': '6 month', 'price': 20000, 'language': ['English']}
# {'teacher': 'oldboy', 'name': 'linux', 'period': '6 month', 'price': 20000}
重新赋值
class Foo:
count = 0
def __init__(self):
Foo.count += 1
f1 = Foo()
f2 = Foo()
print(f1.count)
print(f2.count)
f3 = Foo()
print(f1.count)
绑定方法
def func():pass
print(func)
class Foo:
def func(self):
print('func')
f1 =Foo()
print(Foo.func)
print(f1.func)
# <function func at 0x0000027994822A60>
# <function Foo.func at 0x0000027994822E18>
# <bound method Foo.func of <__main__.Foo object at 0x0000027994821588>>
组合
在一个对象的属性值是另外一个类的对象
from math import pi
class Circle:
def __init__(self,r):
self.r = r
def area(self):
return pi*self.r**2
def perimeter(self):
return 2*pi*self.r
class Ring:
def __init__(self,outside_r,inside_r):
self.outside_c = Circle(outside_r)
self.inside_c = Circle(inside_r)
def area(self):
return self.outside_c.area() - self.inside_c.area()
def perimeter(self):
return self.outside_c.perimeter() - self.inside_c.perimeter()
ring = Ring(20,10)
print(ring.area())
print(ring.perimeter())
组合例子
class Dog:
def __init__(self,name,aggr,hp,kind):
self.name = name
self.aggr = aggr
self.hp = hp
self.kind = kind
def bite(self,person):
person.hp -= self.aggr
class Person:
def __init__(self,name,aggr,hp,sex):
self.name = name
self.aggr = aggr
self.hp = hp
self.sex = sex
self.money = 0
def attack(self,dog):
dog.hp -= self.aggr
def get_weapon(self,weapon):
if self.money >= weapon.price:
self.money -= weapon.price
self.weapon = weapon
self.aggr += weapon.aggr
else:
print('余额不足,请充值')
class Weapom:
def __init__(self,name,aggr,njd,price):
self.name = name
self.aggr = aggr
self.njd = njd
self.price = price
def hand18(self, person):
if self.njd > 0:
person.hp -= self.aggr*2
self.njd -= 1
alex = Person('alex',0.5,100,'不祥')
jin = Dog('jin',100,500,'不祥')
w = Weapom('打狗棒',100,3,998)
alex.money += 1000
alex.get_weapon(w)
print(alex.weapon)
print(alex.aggr)
alex.attack(jin)
print(jin.hp)
alex.weapon.hand18(jin)
print(jin.hp)
class Teacher:
def __init__(self,name,age,sex,birthday):
self.name = name
self.age = age
self.sex = sex
self.birthday = birthday
self.course = Course(self,'python','6个月','20000')
b = Birthday(2018,1,16)
egg = Teacher('egon',0,'女',b)
print(egg.name)
print(egg.birthday.year)
print(egg.course.price)
继承
正常代码中 单继承 减少了代码的重复
继承表达的是一种子类是父类的关系
class A:pass 父类、基类、超类
class B(A) 子类、派生类
一个类 可以被多个类继承
一个类可以继承多个父类 --Python里
__bases__查看继承关系
没有继承父类默认继承object,是所有类的父类
class Animal:
def __init__(self,name,aggr,hp):
self.name = name
self.aggr = aggr
self.hp = hp
class Dog(Animal):
def bite(self,person):
person.hp -= self.aggr
class Person(Animal):
def attack(self,dog):
dog.hp -= self.aggr
jin = Dog('jin',200,500)
print(jin.name)
派生属性、派生方法
父类中没有的属性,在子类中出现,叫派生属性
父类中没有的方法,在子类中出现,叫派生方法
只要子类的对象调用,子类中有的名字,一定用子类的,子类中没有才找父类
如果还想用父类的,单独调用父类的
父类名.方法名 需要自己传self参数
super().方法名 不需要自己传self
单继承
class Animal:
def __init__(self,name,aggr,hp):
self.name = name
self.aggr = aggr
self.hp = hp
def eat(self):
print('吃药回血')
self.hp += 100
class Dog(Animal):
def __init__(self,name,aggr,hp,kind):
Animal.__init__(self,name,aggr,hp)
self.kind = kind #派生属性
def eat(self):
Animal.eat(self)#如果既想实现新的功能,也想使用父类原有的功能,还需要再调用一次父类
self.teeth = 2
def bite(self,person):
person.hp -= self.aggr
class Person(Animal):
def __init__(self,name,aggr,hp,sex):
Animal.__init__(self, name, aggr, hp)
self.sex = sex
self.money = 0
def attack(self,dog):
dog.hp -= self.aggr
def get_weapon(self,weapon):
if self.money >= weapon.price:
self.money -= weapon.price
self.weapon = weapon
self.aggr += weapon.aggr
else:
print('余额不足,请充值')
jin = Dog('进',100,500,'teddy')
jin.eat()
print(jin.hp)
# alex = Person('alex',100,200,'男')
# alex.eat()
# print(alex.hp)
# jin.bite(alex)
# print(alex.hp)
super
class Animal:
def __init__(self,name,aggr,hp):
self.name = name
self.aggr = aggr
self.hp = hp
def eat(self):
print('吃药回血')
self.hp += 100
class Dog(Animal):
def __init__(self,name,aggr,hp,kind):
super().__init__(name,aggr,hp) #只在新试类中有,python3中所有的类都是新试类
self.kind = kind #派生属性
def eat(self):print('dog eating')
jin = Dog('进',200,500,'tt')
print(jin.name)
jin.eat()
super(Dog,jin).eat()
# 进
# dog eating
# 吃药回血
多继承
不会超过三个父类,如果子类有 用自己的,如果没有就用离子类最近的那个父类的方法
python2.7 新试类和经典类共存
python3 只要新试类,默认继承object
新试类 继承object类才是新试类 广度有限
经典类 如果创建一个类在2.7中国就是经典类 深度优先
super只在python3中存在, mro方法只在新试类中存在
super的本质,不是直接找父类,而是根据调用者的节点位置的广度有限顺序来的
接口类
满足接口隔离原则 面向对象开发的思想规范
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些不需要的接口
from abc import abstractmethod,ABCMeta
python原生不支持,默认多继承,接口类中的所有方法都有必须不实现
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
raise NotImplemented
class Wechat(Payment):
def pay(self,money):
print('已经使用微信支付了%s元'%money)
class ALipay(Payment):
def pay(self,money):
print('已经使用支付宝支付了%s元'%money)
class APPlepay(Payment):
def fuqian(self,money):
print('已经使用苹果支付了%s元'%money)
def pay(pay_obj,money):
pay_obj.pay(money)
# wechat = Wechat()
# ali = ALipay()
app =APPlepay()
# pay(wechat,100)
# pay(ali,200)
接口类的多继承
from abc import abstractmethod,ABCMeta
class Swim_Animal(metaclass=ABCMeta):
@abstractmethod
def swim(self):
pass
class Walk_Animal(metaclass=ABCMeta):
@abstractmethod
def walk(self):
pass
class Fly_Animal(metaclass=ABCMeta):
@abstractmethod
def fly(self):
pass
class Tiger(Walk_Animal,Swim_Animal):pass
class Eagle(Fly_Animal,Walk_Animal):pass
class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
接口类的多继承
抽象类 python原生支持
不支持多继承,抽象类中的方法可以有一些代码的实现
一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的功能实现
多继承的情况 由于功能比较复杂,不容易抽象出相同的功能的具体实现写在父类中
抽象类,接口类:面向对象的开发规范,
python中没有接口类,java里有接口Intereface这个概念
python字典多继承 可以直接用class来实现接口类
python支持抽象类: 一般情况下单继承且可以实现代码 不能实例化
# 操作系统中 一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
with open('filaname') as f:
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法')
def write(self):
print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法')
def write(self):
print('硬盘数据的读取方法')
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('进程数据的读取方法')
def write(self):
print('进程数据的读取方法')
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
抽象类
多态 一类事物有多种形态
python天生支持多态
多态性 在不考虑实例类型的情况下使用实例
class ALipay():
def pay(self,money):
print('已经使用支付宝支付了%s元'%money)
class APPlepay():
def fuqian(self,money):
print('已经使用苹果支付了%s元'%money)
def pay(pay_obj,money):
pay_obj.pay(money)
多态
鸭子类型:不崇尚根据继承所得来的相似,自己实现自己的代码,如果两个类刚好相似,并不产生父类的兄弟关系,而是鸭子类型 eg:list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
优点:松耦合,每个相似的类之间都没有影响
缺点:过于随意
强类型语言 多态
python语言 鸭子类型
接口类和抽象类 在python当中的应用点并不是非常重要
封装
广义上面向对象的封装:代码包含,蜜饯相对性的思想本身就是一种,只让自己的对象调用自己累中的方法
狭义上的封装
属性和方法藏起
所有的私有 在变量的左边加上双下划线,都不能在类的外部使用
对象的私有属性
类中的私有方法
类中的静态属性
父类的私有属性不能被子类调用
用到私有概率的场景:
隐藏起一个属性,不想让类的外部调用
保护属性,不想让属性随意被改变
保护属性,不被子类继承
property 装饰器函数,只在面向对象中使用
from math import pi
class Circle:
def __init__(self,r):
self.r = r
@property
def perimeter(self):
return 2*pi*self.r
@property
def area(self):
return self.r**2*pi
c1 = Circle(4)
print(c1.area)
print(c1.perimeter)
class Person:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name + 'sb'
@name.setter
def name(self,new_name):
self.__name = new_name
tai = Person('tai')
print(tai.name)
tai.name = '全部'
print(tai.name)
class Person:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name
@name.deleter
def name(self):
del self.__name
brother2 = Person('二哥')
print(brother2.name)
del brother2.name
print(brother2.name) #报错 属性被删除
静态方法 staticmethod
在完全面向对象的程序中,既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
class Login:
def __init__(self,name,password):
self.name = name
self.password = password
def login(self):pass
@staticmethod
def get_user_pwd():
use = input('用户名:')
pwd = input('密码:')
Login(use,pwd)
Login.get_user_pwd()
类方法 classmethod
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
@classmethod
def change_discount(cls,new_discount):
cls.__discount = new_discount
apple = Goods('苹果',5)
print(apple.price)
Goods.change_discount(0.5)
print(apple.price)
把一个方法 变成一个类中的方法,这个方法就直接可以被调用,不需要依托任何对象
当这个方法的操作至设计静态属性的时候,就应该使用classmethod来装饰这个方法
类方法和静态方法 都是类调用的
对象可以调用 类方法和静态方法,一般情况下推进用类名调用
类方法有一个默认参数 cls 代表这个类
静态方法没有默认参数 就像函数一样
反射
getattr
class Teacher:
dic = {'查看学生信息':'','查看讲师信息':''}
def show_student(self):
print('show_student')
def show_teacher(self):
print('show_teacher')
@classmethod
def func(selfcls):
print('ff')
#hasattr getattr delattr
ret = getattr(Teacher,'dic') #Teacher.dic
ret2 = getattr(Teacher,'func') #Teacher.func
print(ret)
print(ret2)
ret2()
# {'查看学生信息': '', '查看讲师信息': ''}
# <bound method Teacher.func of <class '__main__.Teacher'>>
# ff
hasattr
class Teacher:
dic = {'查看学生信息':'','查看讲师信息':''}
def show_student(self):
print('show_student')
def show_teacher(self):
print('show_teacher')
@classmethod
def func(selfcls):
print('ff')
#hasattr getattr delattr
if hasattr(Teacher,'dic'):
ret = getattr(Teacher,'dic') #Teacher.dic
print(ret)
delattr
isinstance(obj,cls)检查obj是否是cls类的对象
issubclass(sub,super)检查sub是否是super的子类
class A:pass
class B(A):pass
a = A()
print(isinstance(a,A))
print(issubclass(B,A))
# True
# True
反射:用字符串类型的名字,去操作变量
反射对象中的属性和方法 hasattr getattr setattr delattr
反射对象的属性
class A:
def func(self):
print('in func')
a = A()
a.name = 'alex'
ret = getattr(a,'name') # 通过变量min的字符串 形式取到的值
print(ret)
变量名 = input('>>>')
print(getattr(a,变量名))
反射对象的属性
反射对象的方法
class A:
def func(self):
print('in func')
a = A()
ret = getattr(a,'func')
ret()
反射对象的方法
反射类的属性和方法
class A:
price = 20
@classmethod
def func(self):
print('in func')
print(getattr(A,'price'))
if hasattr(A,'func'):
getattr(A,'func')()
反射类的属性和方法
反射模块的属性
import my
print(my.day)
print(getattr(my,'day'))
反射模块属性
反射模块的方法
import my
ret = getattr(my,'whh')
ret()
反射模块方法
内置函数也能使用反射
反射自己模块中的变量和模块中的函数
def qq():
print('qq')
year = 2019
import sys
# print(sys.modules['__main__'].year)
print(getattr(sys.modules['__main__'],'year'))
getattr(sys.modules['__main__'],'qq')()
反射自己模块中的变量和函数
def qq():
print('qq')
year = 2019
import sys
变量名 = input('>>')
print(getattr(sys.modules[__name__],变量名))
反射的函数有参数 在函数字符串后面加上参数即可
import time
print(time.strftime('%Y-%m-%d %H:%M:%S'))
print(getattr(time,'strftime')('%Y-%m-%d %H:%M:%S'))
一个模块中的类可以被反射得到
import my
getattr(my,'C')()
if hasattr():
getattr()
setattr 设置 修改变量
class A:
pass
a = A()
setattr(A,'name','alex')
setattr(a,'name','a')
print(A.name)
print(a.name)
delattr 删除一个变量
class A:
pass
a = A()
setattr(A,'name','alex')
setattr(a,'name','a')
delattr(a,'name')
print(a.name)
几个内置方法
obj.__str__ obj.repr__
object 里有一个__str__,一定被调用就返回调用这个方法对象的内存地址
__str__ 打印一个对象的时候,就是调用对象.__str__
class A:
def __str__(self):
return 'A`s object'
a = A()
print(a) # A`s object
__str__
class Teacher:
def __init__(self,name,salary):
self.name = name
self.salary = salary
def __str__(self):
return 'Teacher`s object:%s'%self.name
def func(self):
return 'www'
na = Teacher('哪吒',250)
print(na) #Teacher`s object:哪吒
__repr__
class Teacher:
def __init__(self,name,salary):
self.name = name
self.salary = salary
def __str__(self):
return 'Teacher`s object:%s'%self.name
def __repr__(self):
return str(self.__dict__)
def func(self):
return 'www'
na = Teacher('哪吒',250)
print(na) #Teacher`s object:哪吒
print(repr(na)) # {'name': '哪吒', 'salary': 250}
print('%r'%na) # {'name': '哪吒', 'salary': 250}
%s str() 直接打印 实际上都是走的__str__
%r repr() 实际上是走的__repr__
repr 是str的备胎,但str不能做repr的备胎
str(obj)的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么返回的必定是一个字符串
如果没有__str__方法,会找本类中的__repr__方法,再没有,再找父类中的__str__
repr(),只会找__repr__,如果没有就找父类的
__del__
析构函数 删除一个对象之前,进行一些收尾工作
__call__
一个对象加上括号,调用__call__
class A:
def __del__(self): # 析构函数
print('执行了')
a = A()
a.f = open()
lst = []
for i in range(1000):
lst.append(A())
a = lst.pop()
import time
time.sleep(3)
print(a)
del a # 执行了这个方法,又删除了变量
print(a)
class A:
def __init__(self,name):
pass
def __call__(self):
print('执行了')
a = A('alex')
a()
item系列 用于类似字典的操作
__getitem__
__setitem__
__delitem__
class Foo:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def __getitem__(self, item):
if hasattr(self,item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
del self.__dict__[key]
f = Foo('egon',38,'男')
print(f['name'])
f['hobby'] = '男'
print(f.hobby,f['hobby'])
del f['hobby']
print(f.__dict__)
item系列
__new__ 构造方法 创建一个方法
class A:
def __init__(self):
self.x = 1
print('in init')
def __new__(cls, *args,**kwargs):
print('in new')
return object.__new__(A,*args,**kwargs)
a = A()
print(a.x)
单例模式 一个类始终只有一个实例
class A:
__instance = False
def __init__(self,name,age):
self.name = name
self.age = age
def __new__(cls, *args,**kwargs):
if cls.__instance:
return cls.__instance
cls.__instance = object.__new__(A)
return cls.__instance
a = A('rgg',23)
a.cloth = '衣服'
b = A('na',25)
print(b)
print(a)
print(b.name)
print(a.name)
print(b.cloth)
# <__main__.A object at 0x0000026A8E0A7A58>
# <__main__.A object at 0x0000026A8E0A7A58>
# na
# na
# 衣服
单例模式
当你第一次实例化这个类的时候就创建一个实例化的对象
当你之后再实例化的时候 就业之前创建的对象
__hash__
class A:
def __init__(self,name,sex):
self.name = name
self.sex = sex
def __hash__(self):
return hash(self.name+self.sex)
a = A('egon','男')
b = A('egon','男')
print(hash(a))
print(hash(b))
# -237336835754499130
# -237336835754499130
a = A('egon','男')
b = A('egon','nan')
print(hash(a))
print(hash(b))
# 4366271411327963305
# 4193967196857736331
__eq__
class A:
def __init__(self,name):
self.name = name
def __eq__(self, other):
if self.name == other.name:
return True
else:
return False
obj1 = A('egg')
obj2 = A('egg')
print(obj1 == obj2)#True