面向过程 VS 面向对象
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
面向对象初识
面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化。
面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板,对象就从具体的模板实例化出来。
初识类和对象
python中一切皆为对象,类型的本质就是类
在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个。
初识类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
def functionName(args): '函数文档字符串' 函数体
类
''' class 类名: '类的文档字符串' 类体 ''' #创建一个类 class Data: pass class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
查看一个类
class Dog: name = '小黑' kind = '哈士奇' # 查看类当中的变量,方法一 print(Dog.__dict__) #{'__module__': '__main__', 'name': '小黑', 'kind': '哈士奇', '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None} print(Dog.__dict__['name']) #小黑 print(Dog.__dict__['kind']) #哈士奇
#方法二 class Dog: name = '小黑' kind = '哈士奇' print(Dog.name) #小黑 print(Dog.kind) #哈士奇
以人狗大战为例 来说明类的相关:
class Dog: hp = 300 #静态变量 def __init__(self,name,hp,ad,kind): # 初始化方法 设置狗的参数:名字,血量,攻击,种类 self.name = name # 实例变量 对象属性 self.hp = hp self.ad = ad self.type = kind def bite(self, person): # 动态变量 定义 狗咬人 的方法 person.hp -= self.ad # 人的血量减去狗的攻击就是人新的血量 print('%s咬了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad)) class Person: def __init__(self,name,hp,ad,sex): # 初始化方法 设置人的参数:名字,血量,攻击,性别 self.name = name # 实例变量 对象属性 self.hp = hp self.ad = ad self.sex = sex def fight(self,dog): # 动态变量 方法 人打狗 # 狗掉血,就是人的攻击力 dog.hp -= self.ad print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad)) hei = Dog('小黑',300,20,'哈士奇') # 小黑 对象 实例 alex = Person('alex',100,10,'male') # alex 对象 实例 print(hei.hp) # 300 print(alex.hp) # 100 hei.bite(alex) # 小黑咬了alex,alex掉了20点血 alex.fight(hei) # alex攻击了小黑,小黑掉了10点血 print(hei.hp) # 290 print(alex.hp) # 80
实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
实例化的过程 :
1.开辟了一块空间,创造了一个self变量来指向这块空间
2.调用init,自动传self参数,其他的参数都是按照顺序传进来的
3.执行init
4.将self自动返回给调用者
1.类名可以调用所有定义在类中的名字
变量
函数名
2.对象名 可以调用所有定义在对象中的属性
在init函数中和self相关的
调用函数的,且调用函数的时候,会把当前的对象当做第一个参数传递给self
类的加载顺序
1.类内部一个缩进的所有代码都是在py文件从上到下解释的时候就已经被执行了
2.类中的代码永远是从上到下依次执行的
class A: country = 'China' def __init__(self): print('执行我了') def func(self): print('1111111') def func(self): print('2222222') A.country = 'English' a = A() #执行我了 a.func() #2222222
类 和 对象 的命名空间
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Student: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex a = 1 b = 2 def func(self): pass yang = Student('杨鹏',20,'male')
# 类 和 对象 存储在两块命名空间里的 class Student: country = 'China' def __init__(self,name,country): self.name = name self.country = country zhang = Student('张尧','日本人') zou = Student('邹路','法国人') print(Student.country) #China print(zou.country) #法国人 print(zhang.country) #日本人 # 对象去找类空间中的名字的前提 : 在自己的空间中没有这个名字
class Student: country = 'China' def __init__(self,name): self.name = name zhang = Student('张尧') zou = Student('邹路') print(zhang.country) #China Student.country = '法国人' print(zhang.country) #法国人 zhang.country = '日本人' # 给一个对象添加了一个属性 print(zou.country) #法国人 print(zhang.country) #日本人 # 在操作静态变量的时候应该尽量的使用类名来操作而不是使用对象名
![](https://i-blog.csdnimg.cn/blog_migrate/4a82d9cd45632dbd1920990e15d7a996.png)
# 练习 :写一个类,能够自动的统计这个类有多少个对象 class A: Count = 0 def __init__(self,name): self.name = name A.Count += 1 a = A('alex') # 创建了一个新对象 a2 = A('alex2') print(A.Count) #2
class B: l = [0] def __init__(self,name): self.name = name b1 = B('颜海清') b2 = B('孙晶晶') print(B.l) #[0] print(b1.l) #[0] print(b2.l) #[0] b1.l[0] += 1 print(b2.l[0]) #1 b1.l = [123] print(b2.l) #[1]
只要是对一个对象.名字直接赋值,那么就是在这个对象的空间内创建了新的属性
只要是对一个可变的数据类型内部的变化,那么仍然是所有的对象和类共享这个改变的成果
所有的静态变量都是用类名来操作,这样修改就能被所有的对象感知到
如果是对于可变数据类型的静态变量 操作的是这个数据内部的内容,也可以使用对象来调用
面向对象的三大特性 :继承 多态 封装
(一)继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
#单继承 class Parent: pass class Son(Parent): pass print(Son.__bases__)
# 多继承 class Parent1: pass class Parent2: pass class Son(Parent1,Parent2): pass print(Son.__bases__) #(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
#__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
单继承
class Animal(object): def __init__(self,name,kind): self.name = name self.kind = kind def eat(self,food): print('%s eat %s'%(self.name,food)) class Cat(Animal): def __init__(self,name,kind,eyes_color): self.eyes_color = eyes_color Animal.__init__(self,name,kind) # 在子类和父类有同名方法的时候,默认只执行子类的方法 # 如果想要执行父类的方法,可以在子类的方法中再 指名道姓 的调用父类的方法 class Dog(Animal):pass hua = Cat('小花','橘猫','蓝色') print(hua.__dict__) # {'eyes_color': '蓝色', 'name': '小花', 'kind': '橘猫'} # 当Cat自己拥有__init__的时候,就不再调用父类的了
class Animal: def __init__(self,name,kind): self.name = name self.kind = kind def eat(self,food): print('%s eat %s'%(self.name,food)) class Cat(Animal): def __init__(self,name,kind,eyes_color): self.eyes_color = eyes_color # super(Cat,self).__init__(name,kind) # super().__init__(name,kind) # 相当于执行父类的init方法 # Animal.__init(self,name,kind) class Dog(Animal):pass hua = Cat('小花','橘猫','蓝色') print(hua.__dict__) #{'eyes_color': '蓝色'}
class Animal(object): def __init__(self,name,kind): self.name = name self.kind = kind def eat(self,food): print('%s eat %s'%(self.name,food)) def drink(self): print('%s drink water'%(self.name)) def catch(self): print('%s catch mouse'%(self.name)) class Cat(Animal): def __init__(self,name,kind,eyes_color): self.eyes_color = eyes_color # 派生属性 # super(Cat,self).__init__(name,kind) super().__init__(name,kind) # 相当于执行父类的init方法 # Animal.__init(self,name,kind) def climb(self): # 派生方法 print('%s climb tree'%self.name) class Dog(Animal): def chai(self): print('%s cha'%(self.name)) hua = Cat('小花','橘猫','蓝色') hua.eat('小鱼干') hua.climb()
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Animal(object): def __init__(self,name,blood,ad): self.name = name self.hp = blood self.ad = ad class Dog(Animal): def __init__(self,name,blood,ad,kind): super().__init__(name,blood,ad) self.kind = kind def bite(self,person): person.hp -= self.ad print('%s攻击了%s,%s掉了%s点血' % (self.name, person.name, person.name, self.ad)) class Person(Animal): def __init__(self,name,hp,ad,sex): super().__init__(name,hp,ad) self.sex = sex def fight(self,dog): dog.hp -= self.ad print('%s攻击了%s,%s掉了%s点血'%(self.name,dog.name,dog.name,self.ad)) hei = Dog('小黑',300,20,'哈士奇') alex = Person('alex',20,1,'不详') alex.fight(hei) print(hei.hp) hei.bite(alex) print(alex.hp)
子类 父类
子类的对象
想要使用某一个名字
如果自己有 就用自己的
如果自己没有 就用父类的
# 如果父类也没有 就报错
如果想要使用的名字父类子类都有
既想使用子类的,也想使用父类的,那就在子类的方法中使用
1. 父类名.方法名(self,参数1,参数2)
2. super().方法名(参数1,参数2)
在python3当中,所有的类都继承object类,所有的类都是新式类
父类是object的类 —— 新式类
class A(object): pass a = A() # 总是要调用init的,如果我们不写,实际上就调用父类object的__init__方法了
多继承
多继承 是python语言中特有的继承方式
java语言中不支持多继承的,C#也不支持多继承
C++支持多继承
多继承和单继承是一样的
如果对象使用名字
是子类中有的,那么一定用子类的
子类没有,可以到多个父类中去寻找
钻石继承
# 钻石继承问题 class A(object): 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()) #[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
# 乌龟继承问题 class A(object): 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(C): pass # def func(self): # print('e') class F(D,E): pass # def func(self): # print('f') print(F.mro()) #[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
.__mro__ #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
在多继承中,super就只和mro顺序有关系,和父类子类没有关系了
C3算法
L(G)=L(G(o))=[G,o] L(E)=L(E(G(o))) =E +merge(L(G(o))) =E+[G,o]=[E,G,o] L(D)=L(D(o))=[D,o] L(F)=L(F(o))=[F,o] L(B)=L(B(D,E))=B+merge(L(D),L(E),DE) =B+merge(Do,EGo,DE) #D 合格 =B +D +merge(o,EGo,E) # E合格 =B +D + E +merge(G,o,)= [B,D,E,G,o] L(C)=L(C(D,F))=C+merge(L(D),L(F),DF) =C+merge(Do,Fo,DF) #D 合法 =C+D+merge(o,Fo,F) # F合法 =C+D+F+merge(o)=[C,D,F,o] L(A)=L(A(B,C))=A+merge(L(B),L(C),BC) =A +merge(BDEGo,CDFo,BC) #B合法 =A + B+merge(DEGo,CDFo,C) # D不合法,看第二元素C合格 =A + B+C+merge(DEGo,DFo,) #D合格 =A + B+C+D+merge(EGo,Fo,)# E合格 =A + B+C+D+E+merge(Go,Fo,) =A + B+C+D+E+G+F+o=[A,B,C,D,E,G,F,o] 运算代码
type 与class
class Course: def __init__(self,name,price): self.name = name self.price = price python = Course('python',20000) print(type(python)) #<class '__main__.Course'> # type一个对象的时候,结果总是这个对象所属的类 # 类是什么类型???所有的类的类型都是type print(type(Course)) #<class '__main__.Course'> print(type(int)) #<class 'type'> print(type(str)) #<class 'type'>
对象是被创造出来 被类实例化出来的
类也是被创造出来的 特殊的方式来创造类
常规创造的类 总是有几个特性
能够实例化
能有属性
能有方法
元类 能够帮助你创造不同寻常的类
特殊的需求一 : 不能实例化
特殊的需求二 : 只能有一个实例
类 = type(对象)
type = type(类)
所有的类型 说的都是这个对象是属于哪一个类的
所有的用class常规语法创造出来的类 都是type类型
进阶
元类 :是能够帮助我们创造一些有特殊要求的类
抽象类
什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 抽象类 def __init__(self, name, money): self.name = name self.money = money @abstractmethod # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器 def pay(self): # # 创建的这个pay并没有内容, pass # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法 @abstractmethod def back(self): pass class WechatPay(Payment): def pay(self): print('%s通过微信支付了%s元' % (self.name, self.money)) def back(self): print('退款') class AliPay(Payment): def pay(self): print('%s通过支付宝支付了%s元' % (self.name, self.money)) def back(self): print('退款') class ApplePay(Payment): def pay(self): print('%s通过apple pay支付了%s元' % (self.name, self.money)) def back(self): print('退款') def pay(person): person.pay() def back(person): person.back() apple = ApplePay('alex', 20000) pay(apple) #alex通过apple pay支付了20000元 back(apple) #退款
抽象类 :Payment这个类是一个抽象类
抽象类做什么事儿 : 约束所有的子类 必须实现被abstractmethod装饰的方法名给我们的代码指定规范
特点 : 抽象类不能实例化,只是作为具体的类的规范
抽象类长什么样
class 类名(metaclass = 'ABCMeta'):
@abstractmethod
def 规定的方法名(self):pass
@abstractmethod
def 规定的方法名(self):pass
@abstractmethod
def 规定的方法名(self):pass
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1.抽象类的意义是?或者说为什么要有抽象类? 抽象类是对多个类中共同方法的抽取,但是子类又有不同的实现,父类只能抽取出方法的名字,而不明确方法的具体实现. 这种只规定子类拥有哪些方法,而不明确具体实现的父类,就应该定义为抽象类. 抽象类只用来规范子类应该具有哪些行为,而不明确具体的动作. 2.抽象类的特点是? 抽象类和普通类的最主要区别在于: 1.抽象类继承的()中写的是metaclass=ABCMeta 2.在类体中有用@abstractmethod修饰的方法(需要子类重写的方法) 3.抽象类中是否可以有非抽象方法? 可以. 4.抽象类中的抽象方法是否可以有方法体? 可以. 5.抽象类中是否可以有__init__方法?为什么? 可以,因为抽象类中也可以有实例属性供子类继承. 而实例属性必须在父类中初始化,子类对象才能继承. 抽象类的__init__方法不能手动调用,只能是子类创建对象时自动调用的.
接口类
类只能单继承,所以抽象类 只能是所有的子类只有一个规范
java 当中没有多继承的类
接口 接口可以多继承
在python里没有接口的专用语法
我们只是通过类的多继承 模仿接口的效果
from abc import ABCMeta,abstractmethod class NormalAnnimal(metaclass=ABCMeta): @abstractmethod def eat(self):pass @abstractmethod def drink(self):pass class FlyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self):pass class SwimAnimal(metaclass=ABCMeta): @abstractmethod def swim(self):pass class WalkAnimal(metaclass=ABCMeta): @abstractmethod def walk(self):pass class Frog(NormalAnnimal,SwimAnimal,WalkAnimal): def eat(self): pass class Tiger(NormalAnnimal,SwimAnimal,WalkAnimal):pass class Swan(NormalAnnimal,FlyAnimal,SwimAnimal,WalkAnimal):pass class Parrot(NormalAnnimal,FlyAnimal,WalkAnimal): def talk(self): pass
抽象类 是单继承的规范
接口类 是多继承的规范
java
接口里面定义的所有的方法 都不能写具体的实现 pass
抽象类里面定义的所有的抽象方法 内部是可以完成一些简单的代码
(二)多态
在python当中 处处是多态,一切皆对象
广义的多态 一个类能表现出的多种形态
#在java 中 在python中报错 class Payment:pass class Alipay(Payment): def __init__(self,name,money): self.name = name self.money = money def pay(self): print('%s通过支付宝支付了%s元'%(self.name,self.money)) class ApplePay(Payment): def __init__(self,name,money): self.name = name self.money = money def pay(self): print('%s通过apple pay支付了%s元' % (self.name, self.money)) # 归一化设计 def pay(Payment person): person.pay() # 支付有多种形态 : 支付宝 微信支付 apple支付
鸭子类型
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用 class TxtFile: def read(self): pass def write(self): pass class DiskFile: def read(self): pass def write(self): pass
鸭子类型
python当中写程序的一种特殊的情况
其他语言中 正常的我们说一个数据类型具有某个特点,通常是通过继承来实现
继承迭代器类,来证明自己本身是个迭代器
继承可哈希的类,来证明自己本事是可哈希的
但是所有的这些都不是通过继承来完成的
我们只是通过一种潜规则的约定,如果具有__iter__,__next__就是迭代器
如果具有__hash__方法就是可哈希
如果具有__len__就是可以计算长度的
这样数据类型之间的关系并不仅仅是通过继承来约束的 而是通过约定俗成的关系来确认的
多态
在传递参数的时候,如果要传递的对象有可能是多个类的对象
我们又必须在语言中清楚的描述出到底是那一个类型的对象
我们就可以使用继承的形式,有一个父类作为这些所有可能被传递进来的对象的基类
基础类型就可以写成这个父类
于是所有子类的对象都是属于这个父类的
在python当中,因为要传递的对象的类型在定义阶段不需要明确,所以我们在python中处处都是多态
数据的类型不需要通过继承来维护统一
namedtuple (例如扑克牌)
from collections import namedtuple Course = namedtuple('Course',['name','price','period']) python = Course('python',20000,'6 month') print(python.name) #python print(python.price) #20000 print(python.period) #6 month print(type(python)) #<class '__main__.Course'> #属性不可修改,并且没有方法
pickle 类 (写入,读取文件)
import pickle class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period # python = Course('python',20000,'6 months') # linux = Course('linux',15800,'5 months') # import pickle # with open('pickle_file','ab') as f: # pickle.dump(python,f) # pickle.dump(linux,f) import pickle with open('pickle_file','rb') as f: # obj1 = pickle.load(f) # obj2 = pickle.load(f) while True: try: obj = pickle.load(f) print(obj.__dict__) except EOFError: break
(三)封装
广义上的封装 : 把方法和属性根据根据类别装到类中
狭义上的封装 : 私有化的方法和属性
方法\静态变量\实例变量(对象属性)都可以私有化
所谓的私有化 : 就是只能在类的内部可见,类的外部是不能访问或者查看的
私有变量和私有方法
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class Goods: def __init__(self,name,price): self.name = name self.__price = price # 私有属性 def get_price(self): print(self.__price) apple= Goods('苹果',5) print(apple.name) apple.get_price() # print(apple.__price) #报错
#私有的静态变量 class Role: __Country='China' # 静态变量的私有化 def func(self): print(self.__Country) print(Role.__Country) # 报错 : 因为不能再类的外部引用变量 Role().func()
# 私有的方法 import hashlib class Auth: def __init__(self,user,pwd): self.username = user self.password = pwd def __md5_code(self): md5 = hashlib.md5(self.username.encode('utf-8')) md5.update(self.password.encode('utf-8')) return md5.hexdigest() def login(self): if self.username == 'alex' and 'ee838c58e5bb3c9e687065edd0ec454f' == self.__md5_code(): # pwd = alex3714 return True user = input('>>>') pwd = input('>>>') obj = Auth(user,pwd) # obj.__md5_code() # 报错的,私有的方法不能在类的外部被使用 obj._Auth__md5_code() # 不报错的 ret = obj.login() if ret: print('登陆成功') #>>>alex #>>>alex3714 #登陆成功
# 私有化是怎么完成的? class Goods: def __init__(self,name,price): self.name = name self.__price = price # 私有属性 def get_price(self): print(self.__price) def set_num(self): self.__num = 20 apple = Goods('苹果',5) print(apple.__dict__) #{'name': '苹果', '_Goods__price': 5} print(apple._Goods__price) # 私有的形成 # 所有的私有的变化都是在类的[内部]定义的时候完成的 apple.__num = 10 print(apple.__dict__) #{'name': '苹果', '_Goods__price': 5, '__num': 10} apple.set_num() print(apple.__dict__) #{'name': '苹果', '_Goods__price': 5, '__num': 10, '_Goods__num': 20}
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Foo: def __init__(self): self.func() def func(self): print('in foo') class Son(Foo): def func(self): print('in son') Son() # in son
# 私有的属性可以被继承么? class Foo: def __init__(self): self.__func() def __func(self): print('in foo') class Son(Foo): def __func(self): print('in son') Son() #in foo
私有的所有内容 :实例变量(对象属性),静态变量(类变量),方法都不能被子类继承
公有的 public 在类的内部外部随便用
私有的 private 只能在类的内部使用 既不能被继承 也不能在类的外部使用
property
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Circle: def __init__(self,r): self.r = r def area(self): return 3.14*self.r**2 def perimeter(self): return 2*3.14*self.r c1 = Circle(5) c1.r=10 print(c1.area()) #调用方法 print(c1.perimeter()) #需要加()
class Circle: def __init__(self,r): self.r = r @property # 把装饰的一个方法伪装成一个属性 def area(self): return 3.14*self.r**2 @property def perimeter(self): return 2*3.14*self.r c1 = Circle(5) c1.r=10 print(c1.area) #类似调用属性 print(c1.perimeter)
import time class Person: def __init__(self,name,birth): self.name = name self.birth = birth @property def age(self): struct_t = time.localtime() age = struct_t.tm_year - int(self.birth.split('-')[0]) return age alex = Person('alex','1965-5-12') print(alex.age)
property与私有
class Goods: discount = 0.8 # 静态变量 (代表打折) def __init__(self,name,price): self.name = name self.__price = price #价格设置私有 def price(self): return self.__price * self.discount apple = Goods('苹果',5) banana = Goods('香蕉',10) print(apple.name) #苹果 print(apple.price()) #4.0 print(banana.price()) #8.0 Goods.discount = 1 print(apple.price()) #5 print(banana.price()) #10
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property def price(self): p = self.__price * self.discount return p apple = Goods('苹果', 5) banana = Goods('香蕉', 10) print(apple.name) print(apple.price) print(banana.price) Goods.discount = 1 print(apple.price) print(banana.price)
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter def price(self,value): if type(value) is int or type(value) is float: self.__price = value apple = Goods('苹果', 5) banana = Goods('香蕉', 10) apple.price = 16 # 对应的调用的是被setter装饰的price方法 print(apple.price) # 对应调用的是被property装饰的price方法
如果我们定义的是普通的变量或者属性
那么这个属性可以从外部直接访问
可以任意的修改 obj.attr = 123
甚至可以删除 del obj.attr
私有化
把一个属性加上双下划线 __属性名
这个属性就连在外面看都看不见了
我们实际上有些场景允许别人看,不许改
__属性
@property装饰的属性名
def 属性():
我们允许别人看,也允许别人改,但是不能瞎改,有一些要求:数据类型 范围
__属性
@property装饰的属性名
def 属性():return __属性
@属性.setter
def 属性(self,value):
加点儿条件
修改__属性
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter def price(self,value): if type(value) is int or type(value) is float: self.__price = value @price.deleter def price(self): del self.__price # 想删除一个属性 apple = Goods('苹果', 5) del apple.price print(apple.__dict__) apple.price # 'Goods' object has no attribute '_Goods__price' apple.price = 9
classmethod
class Fruits: __discount = 0.8 #将类中静态变量变为私有 def __init__(self, name, price): print('init',self) self.name = name self.__price = price @classmethod # 把一个方法从对象方法,变成一个类方法 def change_discount(cls,value): cls.__discount = value # cls到底是谁??? Fruits @classmethod def get_discount(cls): return cls.__discount print(Fruits.get_discount()) Fruits.change_discount(1) print(Fruits.get_discount()) # 类方法 # 1. 有些时候我们要修改的是类中的静态变量/类变量 # 此时根本不会和self有任何的操作关联 # 这时传一个self参数对我们来说完全没有用 # 我们希望接受的是当前我们所在的类 apple = Fruits('apple',8) apple.change_discount(0.5) print(Fruits.get_discount()) # 类方法推荐使用类名调用而不是使用对象名调用
staticmethod
class A: @staticmethod # 声明这个方法只是一个普通的不会使用任何和这个类中的变量相关的方法 def func(): # 此时 func是一个静态方法 print('既不操作和self相关的内容') print('也不操作和类名相关的内容') A.func() # login 登录 class Student: def __init__(self,name): self.name = name @staticmethod def login(): pass # 先获取这个学生的用户名和密码 # 判断他登录成功之后进行实例化 # Student.login() # stu = Student('alex')
面向对象的反射
class Student: def __init__(self,name): self.name = name def show_courses(self): #查看课程 print('调用了 show courses') def select_course(self): #选择课程 print('调用了 select course') def show_selected_course(self): #查看所选课程 print('调用了 show_selected_course') def quit(self): #退出 print('调用了 quit') wu = Student('吴彪') # print(wu.name) # wu.show_courses() # wu 'name' # 反射 通过字符串属性名 得到真正的这个字符串的名字对应的对象的属性值 # ret = getattr(wu,'name') # 内置函数 # print(ret) # wu.show_courses() # print(getattr(wu,'show_courses')) # wu.show_courses # getattr(wu,'show_courses')() # getattr(wu,'select_course')() while True: name = input('>>>') if hasattr(wu,name): func_attr = getattr(wu,name) if callable(func_attr): func_attr() else: print(func_attr)