面向对象编程
class 类名:
属性
类名.属性
类名的作用:操作属性 查看属性
对象 = 类名()
过程:
类名()首先会创造出一个对象,创建一个self变量
调用init方法,类名括号里的参数会被质量接收
执行init方法
返回self
调用方法 :
类名.方法名(对象名)
对象名.方法名
对象能做的事:
查看属性
调用方法
__dict__对于对象的增删改查操作都可以通过字典的语法进行
类名能做的事:
实例化
调用方法 要自己传递self参数
调用类中的属性,也就是调用静态属性
__dict__类中的名字只能看 不能操作
一个可以存储很多属性的大字典
往字典里添加属性的方式改变了一些变化
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中没有接口类,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
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__)
__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
原文:https://www.cnblogs.com/rssblogs/p/10976518.html