首页 > temp > python入门教程 >
-
python--高级语法 11
day20:
1、递归函数
- 递归函数:在一个函数里在调用这个函数本身
- 递归的最大深度:998
def foo(n):
print(n)
n += 1
foo(n)
foo(1)
998Traceback (most recent call last):
面试题:可以修改递归函数的最大深度吗?--可以
import sys
sys.setrecursionlimit(10000)
看电脑性能,最大深度
1.1、递归示例讲解
例一:
现在你们问我,alex老师多大了?我说我不告诉你,但alex比 egon 大两岁。
你想知道alex多大,你是不是还得去问egon?egon说,我也不告诉你,但我比武sir大两岁。
你又问武sir,武sir也不告诉你,他说他比太白大两岁。
那你问太白,太白告诉你,他18了。
这个时候你是不是就知道了?alex多大?
def age(n):
if n == 1:
return 18
else:
return age(n-1)+2
print(age(4))
24
Process finished with exit code 0
day:22 面向对象
一:创建\调用类和类实例化
1.类名()----会自动调用类中的 init 方法
2.类中直接写个打印语句,不用实例化类对象,直接运行可以打印
class Person:
print(123)
def __init__(self):
print('-'*20)
self.name='mike'
print('*' * 20)
print(456)
123
456
Process finished with exit code 0
3、类的实例化
其实实例化一个对象总共发生了三件事:
1,在内存中开辟了一个对象空间。
2,自动执行类中的__init__方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。
3,在__init__ 方法中通过self给对象空间添加属性。
alex=Person() #alex就是对象,Alex=Person()的过程,是通过类获取一个对象的过程,叫类的实例化
4、类调用执行 init 方法的过程
class Person:
print(123)
def __init__(self):
print('-'*20)
self.name='mike'
self.sex='不详'
self.job='搓澡工'
self.level=0
self.hp=250
self.weapon='搓澡巾'
self.ad=1
print('*' * 20)
print(456)
alex=Person() #alex就是对象,Alex=Person()的过程,是通过类获取一个对象的过程,叫类的实例化
123
456
--------------------
********************
Process finished with exit code 0
- 图片解析
5、类和对象之间的关系?
- 类 是一个大范围,是一个模子,它约束了事务有哪些属性,但是不能约束具体的值
- 对象 是一个具体的内容,是模子的产物,它遵循了类的约束,同时给属性赋上具体的值
6、查看类中的所有内容
-
类名.__dict__方式
class Person: def __init__(self,name,sex,job,hp,weapon,ad,): print('-'*20) self.name=name self.sex=sex self.job=job self.level=0 self.hp=hp self.weapon=weapon self.ad=ad print('*' * 20) print(self.__dict__) alex=Person('alex','不详','搓澡工',250,'搓澡巾',1) print(alex.__dict__) print(Person.__dict__) -------------------- ******************** {'name': 'alex', 'sex': '不详', 'job': '搓澡工', 'level': 0, 'hp': 250, 'weapon': '搓澡巾', 'ad': 1} {'name': 'alex', 'sex': '不详', 'job': '搓澡工', 'level': 0, 'hp': 250, 'weapon': '搓澡巾', 'ad': 1} {'__module__': '__main__', '__init__': <function Person.__init__ at 0x0000025A970999D8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} Process finished with exit code 0
7、self 是什么?
-
类有一个空间,存储的是定义在class中所有名字
-
每一个对象又拥有自己的空间,通过对象名.__dict__方法就可以查看这个对象的属性和值
-
类中的方法一般都是通过对象执行的(除去类方法,静态方法外),并且对象执行这些方法都会自动将对象空间传给方法中的第一个参数self.
所以self 是什么?
self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。
8、实例化所经历的过程
- 1.类名()之后的第一件事:开辟一块内存空间,用来存放对象
- 2.调用__init__方法(或者类中其他方法),把空间的内存地址作为self参数,传递到函数内部
- 3.所有的着一个对象需要使用的属性都需要和self关联起来
- 4.执行完init中的逻辑后,self变量会自动的被返回到调用处(发送实例化的地方,方便这个类实例化下一个对象)
对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
9、属性的增,删,改,查
修改 列表/字典/对象 中 的某一个值,都不会影响这个 列表/字典/对象 所在的内存空间地址
class Person:
def __init__(self,name,sex,job,hp,weapon,ad,):
print('-'*20)
self.name=name
self.sex=sex
self.job=job
self.level=0
self.hp=hp
self.weapon=weapon
self.ad=ad
print('*' * 20)
alex=Person('alex','不详','搓澡工',250,'搓澡巾',1)
#属性的增加
alex.momey=1000
#属性的删除
del alex.money
#属性的修改
alex.name='qweewqew'
#属性的查看
print(alex.name)
二、类中定义方法和调用方法
1、案例:人狗大战
需求:
人搓狗,狗掉血,狗掉的血是人的攻击力
狗舔人,人掉血,人掉的血是狗的攻击力
class Person:
def __init__(self,name,sex,job,hp,weapon,ad,):
self.name=name
self.hp=hp
self.ad=ad
def 搓(self,dog):
#人搓狗,狗掉血,狗掉的学是人的攻击力
dog.dog_hp=dog.dog_hp-self.ad
print('{}给{}搓了澡,{}掉了{}点血,{}当前血量是{}'.format(self.name,dog.dog_name,dog.dog_name,self.ad,dog.dog_name,dog.dog_hp))
class Dog:
def __init__(self,name,blood,ad,kind):
self.dog_name = name
self.dog_hp=blood
self.dog_ad=ad
def 舔(self,person):
#狗舔人,人掉血 人掉的血是狗的攻击力
if person.hp >= self.dog_ad :
person.hp=person.hp-self.dog_ad
else:
person.hp=0
print('{}舔了{},{}掉了{}点血,{}当前血量是{}'.format(self.dog_name,person.name,person.name,self.dog_ad,person.name,person.hp))
alex=Person('alex','不详','搓澡工',250,'搓澡巾',1)
小白=Dog('小白',5000,249,'柴犬')
#人攻击狗
alex.搓(小白)
#狗攻击人
小白.舔(alex)
小白.舔(alex)
alex给小白搓了澡,小白掉了1点血,小白当前血量是4999
小白舔了alex,alex掉了249点血,alex当前血量是1
小白舔了alex,alex掉了249点血,alex当前血量是0
Process finished with exit code 0
2、当通过 类名.方法名() 调用类的方法时,会报错,要穿一个参数进入才行
class A:
country='中国'
def __init__(self):
pass
def fun1(self):
print(11)
A.fun1()
TypeError: fun1() missing 1 required positional argument: 'self'
Process finished with exit code 1
class A:
country='中国'
def __init__(self):
pass
def fun1(self):
print(11)
A.fun1(2)
11
Process finished with exit code 0
3、所以通常我们 先实例化一个对象,用对象.方法名 去调用就不会报错
#类:
class A:
country='中国'
def __init__(self):
pass
def fun1(self):
print(11)
obj=A()
obj.fun1() #=A.func1(a)
11
Process finished with exit code 0
4、思考:类和对象的命名空间讲解
print(obj.country) 和 print(A.country) 的区别?
---为什么 print(obj.country) 打印的是'印度';而 print(A.country) 打印的是 '中国'?
前置说明:创建类的时候会创建一块类的空间,用来存放 类里面的属性,方法,和init方法 等等;
实例化类的对象时,会创建一块对象的空间,存放一个类指针(用来指对应的类空间地址),然后对象名作为init方法的第一个位置参数(self),传递给init方法,init方法通过self给对象的空间添加属性(即name='mike',age=83,country='印度')。
解答;
print(obj.country)先在obj对象的空间中找有没有country属性,结果有,并且是'印度',所以打印'印 度'---(如果对象的空间中没有country属性,那在去类的空间去找,这时候打印的就是'中国'了)
print(A.country) 先在A类的空间中找有没有country属性,结果有,并且是'中国',所以打印'中国'
class A:
country='中国'
def __init__(self,name,age,q):
self.name=name
self.age=age
self.country=q
obj=A('mike',83,'印度')
print(obj.country)
print(A.country)
印度
中国
Process finished with exit code 0
- 图片解析:
- 拓展:打印结果是?
class A:
country='中国'
def __init__(self,name,age,q):
self.name=name
self.age=age
self.country=q
a=A('mike',83,'印度')
b=A('wusir',73,'日本')
a.country='泰国'
print(a.country)
print(b.country)
print(A.country)
泰国
日本
中国
Process finished with exit code 0
5、总结
-
类中的变量是静态变量
-
对象中的变量只输入对象本身,每个对象有属于自己的空间来存放对象的变量
-
当使用对象名去调用某一个属性的时候会优先在自己的空间中寻找,找不到再去对应的类中寻找
-
如果自己没有就去类空间去找,如果类也没有就报错
-
对于类来说,类中的变量,所有的对象都是可以读取的,并且读取的是同一个变量
三、组合:一个类的对象是另一个类对象的属性
- 对象变成一个属性
- 或者说对象变成另一个对象的参数了
#组合:一个类的对象是另一个类对象店的属性
#需求:想查看大壮所在班级的开班日期是多少?
#学生类
#属性:姓名,性别,年龄,学号,班级,手机号
#班级信息类
#班级名字
#开班时间
#当前讲师
class student:
def __init__(self,name,sex,age,number,class_name,phone):
self.name=name
self.sex=sex
self.age = age
self.number = number
self.class_name = class_name
self.phone = phone
class banji:
def __init__(self,cname,ctime,teacher):
self.cname=cname
self.ctime = ctime
self.teacher = teacher
py22=banji('python全站22期','2019-4-26','小白')
py23=banji('python全站23期','2019-5-26','宝元')
大壮=student('大壮','male',23,10086,py22,13812345678)
雪飞=student('雪飞','male',18,10088,py23,13812345670)
#想查看大壮所在班级的开班日期是多少?
print(大壮.class_name.ctime)
2019-4-26
Process finished with exit code 0
示例2
#班级类
#属性:课程
#课程:
#课程名称
#周期
#价格
#需求:
#创建两个班级 linux57 python22
#查看linux57期的班级所学课程的价格
#查看python22期的班级所学课程的周期、
class banji:
def __init__(self,kcheng):
self.kcheng=kcheng
class kecheng:
def __init__(self,name,zhouqi,jiage):
self.name=name
self.zhouqi=zhouqi
self.jiage=jiage
#查看linux57期的班级所学课程的价格
linux57_课程=kecheng('mike','6个月',18000)
linux57=banji(linux57_课程)
print(linux57.kcheng.jiage)
#查看python22期的班级所学课程的周期、
python22_课程=kecheng('anuo','3个月',20000)
python22=banji(python22_课程)
print(python22.kcheng.zhouqi)
18000
3个月
Process finished with exit code 0
四、三大特性:继承,封装,多态
(1)继承
1、继承时实例化的过程
class animal:
def __init__(self,name):
self.name=name
def eat(self):
print("{}吃".format(self.name))
class cat(animal):
def pashu(self):
print("{}爬树".format(self.name))
cat('小白')
# 先开辟空间,空间里有一个类指针-->指向Cat
# 调用init,对象在自己的空间中找init没找到,到Cat类中找init也没找到,
# 找父类Animal中的init
- 图片解析
2、子类想要调用父类的方法的同时还想执行自己的同名方法?
# 子类想要调用父类的方法的同时还想执行自己的同名方法
# 猫和狗在调用eat的时候既调用自己的也调用父类的,
# ---在子类的方法中调用父类的方法 :父类名.方法名(self)
animal.eat(self)
class animal:
def __init__(self,name,food):
self.name=name
self.food=food
self.blood = 100
self.waise = 100
def eat(self):
print("{}吃{}".format(self.name,self.food))
def drink(self):
print("{}喝".format(self.name))
def sleep(self):
print("{}睡".format(self.name))
class cat(animal):
def eat(self):
self.blood = self.blood+100
animal.eat(self)
def pashu(self):
print("{}爬树".format(self.name))
class dog(animal):
def eat(self):
self.waise = self.waise+100
def kanjia(self):
print("{}看家".format(self.name))
小猫 = cat('小白','猫粮')
小狗 = dog('小黑','狗粮')
小猫.eat()
小狗.eat()
print(小猫.__dict__,小猫.blood)
print(小狗.__dict__,小狗.waise)
小白吃猫粮
{'name': '小白', 'food': '猫粮', 'blood': 200, 'waise': 100} 200
{'name': '小黑', 'food': '狗粮', 'blood': 100, 'waise': 200} 200
Process finished with exit code 0
- 图片讲解调用过程
3、父类和子类方法的选择
# 继承语法
class 子类名(父类名):pass
# 父类和子类方法的选择:
# 子类的对象,如果去调用方法
# 永远优先调用自己的
# 如果自己有 用自己的
# 自己没有 用父类的
# 如果自己有 还想用父类的:直接在子类方法中调父类的方法 父类名.方法名(self)--animal.eat(self)
# 如果有 父类没有的 想在自己独有的方法内调用父类的方法 : 直self.方法名()---self.drink()
4、思考一:下面代码的输出?
class Foo:
def __init__(self):
self.func()
# 在每一个self调用func的时候,我们不看这句话是在哪里执行,只看self是谁(这里self指向son()这个对象的)
def func(self):
print('in foo')
class Son(Foo):
def func(self):
print('in son')
Son()
in son
Process finished with exit code 0
5、派生属性
class Cat(animal):
def __init__(self,name,food,eye_color):
animal.__init__(self,name,food) # 调用了父类的初始化,去完成一些通用属性的初始化
self.eye_color = eye_color # 派生属性
6、单继承
- 当一个子类只有一个父类时称为单继承
语法:
class 子类名(父类名):
#B继承A A继承C C继承D B-A-C-D
class D:
def func(self):
print('in D')
class C(D):pass
class A(C):
def func(self):
print('in A')
class B(A):pass
B().func()
in A
Process finished with exit code 0
7、多继承
- 多继承指一个子类可以有多个父类,它继承了多个父类的特性。多继承可以看作是对单继承的扩展
语法:
class 子类名(父类名1,父类名2…):
7.1:多继承时,调用多个父类中同名方法时,那个优先级高?
---看那个父类离子类近
class C(B,A):pass ------优先B
class C(A,B):pass ------优先A
举例:
class B:
def func(self):
print('in B')
class A:
def func(self):
print('in A')
class C(B,A):pass
C().func()
in B
Process finished with exit code 0
#*********************************************
class C(A,B):pass
C().func()
in A
Process finished with exit code 0
8、object类
- 类祖宗,所有在python3当中的类都是继承object类的
9、类的继承顺序
-
背诵
- 只要继承object类就是新式类
- 不继承object类的都是经典类
python3 所有的类都继承object类,都是新式类
在py2中 不继承object的类都是经典类,继承object类的就是新式类了
# 算法的内容
# 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
# 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,...
# merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺 序中的一个
# 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中 的一个
# 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
# 经典类 - 深度优先 (总是在一条路走不通之后再换一条路,走过的点不会再走了)
#新式类 - 广度优先
# 深度优先要会看,自己能搞出顺序来
# 广度优先遵循C3算法,要会用mro,会查看顺序
# 经典类没有mro,但新式类有
9.1、C3算法:
在代码中打印调用顺序(mro方法)
语法: 类名.mro()
print(F.mro()) # 只在新式类中有,经典类没有的
class A:
def func(self):
pass
class B(A):
def func(self):
pass
class C(A):
def func(self):
pass
class D(B):
def func(self):
pass
class E(C):
def func(self):
pass
class F(D,E):
def func(self):
pass
print(F.mro())
F-D-B-E-C-A-object
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
Process finished with exit code 0
9.2、深度优先(经典类)
9.3、广度优先(新式类)
10、继承总结:
# 单继承
# 调子类的 : 子类自己有的时候
# 调父类的 : 子类自己没有的时候
# 调子类和父类的 :子类父类都有,在子类中调用父类的
# 多继承
# 一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
10.1、复习实例化对象的过程
1--.前面是什么--就在对应的空间去找(如 A.role 表示在类A的空间中去找role;
如 a=A() a.l 表示在对象的空间中去找l)
2--实例化的时候总是先开空间,再调用init, 调用init的时候总是把新开的的空间作为参数传递给self
(即self 等于对象,比如 self.l 表示在对象的空间中去找l )
3--分析 a=A() a.append(1) 的调用过程?
解答:先在对象a空间中去找append方法,发现没有,再通过类指针去A类中找append方法,找到了,然后执行 self.l.append(obj)--首先self.l 是保存在对象空间中的一个空列表[],然后append(1),表示对象空 间的 self.l 空列表添加了一个元素1 (补充:此时A().l 是空列表[],没有1)
代码:
class A:
role = []
def __init__(self):
self.l = []
def append(self,obj):
self.l.append(obj)
def pop(self,index=-1):
self.l.pop(index)
print(A.role)
a=A()
10.2、复习继承
重点案例:继承的调用过程
(2)多态
一个类型表现出来的多种状态(多态,同一个对象,多种形态)
# 一个类型表现出来的多种状态
# 支付 表现出的 微信支付和苹果支付这两种状态
# 在java情况下: 一个参数必须制定类型
# 所以如果想让两个类型的对象都可以传,那么必须让这两个类继承自一个父类,在制定类型的时候使用父类来指定
# 多态
# 什么是多态? : 一个类表现出的多种形态,实际上是通过继承来完成的
# 如果狗类继承动物类,猫类也继承动物类
# 那么我们就说猫的对象也是动物类型的
# 狗的对象也是动物类型的
# 在这一个例子里,动物这个类型表现出了猫和狗的形态
# java中的多态是什么样
# def eat(动物类型 猫的对象/狗的对象,str 食物):
# print('动物类型保证了猫和狗的对象都可以被传递进来')
# python中的多态是什么样 : 处处是多态
# 鸭子类型
# 子类继承父类,我们说子类是父类类型的(猫类继承动物,我们说猫也是动物)
# 在python中,一个类是不是属于某一个类型
# 不仅仅可以通过继承来完成
# 还可以是不继承,但是如果这个类满足了某些类型的特征条件
# 我们就说它长得像这个类型,那么他就是这个类型的鸭子类型
0、多态是什么?
多态 :不同的 子类对象调用 相同的 父类方法,产生 不同的 执行结果。
- 多态以 继承 和 重写 父类方法 为前提
- 多态是调用方法的技巧,不会影响到类的内部设计
class animal:
def sleep(self):
print("animal睡")
class dog(animal):
def sleep(self):
print("dog睡觉")
class cat(animal):
def sleep(self):
print("cat睡觉")
class pig(animal):
pass
#不同的子类
dog = dog()
cat = cat()
pig = pig()
#调用相同的父类的同名方法,产生 不同的 执行结果
dog.sleep()
cat.sleep()
pig.sleep()
dog睡觉
cat睡觉
animal睡
Process finished with exit code 0
1、多态是什么?
-
同一事件在不同对象上产生不同的相应
- 同一事件:即调用相同函数
- 不同对象:被调用函数的参数是不同的实例
- 不同的相应:输出结果不同
举例分析:
分析:
同一事件:调用 func 函数
不同对象:三个对象本质都是Animal类型的不同实例
不同相应:输出结果不同,输出如下图:
代码:
class animal:
def sleep(self):
print("animal睡")
class dog(animal):
def sleep(self):
print("dog睡觉")
class cat(animal):
def sleep(self):
print("cat睡觉")
#调用函数
def func(x) :
x.sleep()
#创建3个实例,本质都是Animal类型
animal = animal()
dog = dog()
cat = cat()
#重点重点重点
func(animal)
func(dog)
func(cat)
animal睡
dog睡觉
cat睡觉
Process finished with exit code 0
2、Python中【多态】的作用?
- 让具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同功能(内容)的函数。
3、Python中多态的特点
1、只关心对象的实例方法是否同名,不关心对象所属的类型;
2、对象所属的类之间,继承关系可有可无;
3、多态的好处可以增加代码的外部调用灵活度,让代码更加通用,兼容性比较强;
4、多态是调用方法的技巧,不会影响到类的内部设计。
4、多态的应用场景?
4.1、 对象所属的类之间没有继承关系
-
调用同一个函数
fly()
, 传入不同的参数(对象),可以达成不同的功能
class Duck(object): # 鸭子类
def fly(self):
print("鸭子沿着地面飞起来了")
class Swan(object): # 天鹅类
def fly(self):
print("天鹅在空中翱翔")
class Plane(object): # 飞机类
def fly(self):
print("飞机隆隆地起飞了")
def fly(obj): # 实现飞的功能函数
obj.fly()
duck = Duck()
fly(duck)
swan = Swan()
fly(swan)
plane = Plane()
fly(plane)
鸭子沿着地面飞起来了
天鹅在空中翱翔
飞机隆隆地起飞了
Process finished with exit code 0
4.2、 对象所属的类之间有继承关系(应用更广)
class gradapa(object):
def __init__(self, money):
self.money = money
def p(self):
print("this is gradapa")
class father(gradapa):
def __init__(self, money, job):
super().__init__(money)
self.job = job
def p(self):
print("this is father,我重写了父类的方法")
class mother(gradapa):
def __init__(self, money, job):
super().__init__(money)
self.job = job
def p(self):
print("this is mother,我重写了父类的方法")
return 100
# 定义一个函数,函数调用类中的p()方法
def fc(obj):
return obj.p()
gradapa1 = gradapa(3000)
father1 = father(2000, "工人")
mother1 = mother(1000, "老师")
fc(gradapa1) # 这里的多态性体现是向同一个函数,传递不同参数后,可以实现不同功能.
fc(father1)
print(fc(mother1))
this is gradapa
this is father,我重写了父类的方法
this is mother,我重写了父类的方法
100
拓展:函数中 return 的理解
def func():
print('in func')
return 100
def func1(x):
print('in func1')
x() #没有使用return x()
print(func1(func)) #结果没有打印100 打印None --这是因为 func1 这个方法的内存地址里没有存储100
加上 return
def func():
print('in func')
return 100
def func1(x):
print('in func1')
return x() #加上return x()
print(func1(func)) #结果了打印100 --这是因为return 后,100这个值就返回到 func1 这个方法的内存地 址里 所有才可以打印出来
super()方法
-
su po
-
在单继承中,super就是找父类
-
在多继承中。super就是按照mro顺序,去找当前类的下一个类
class User:
def __init__(self,name):
self.name = name
class VIPUser(User):
def __init__(self,name,level,strat_date,end_date):
# User.__init__(self,name)
super().__init__(name) # 推荐的
# super(VIPUser,self).__init__(name)
self.level = level
self.strat_date = strat_date
self.end_date = end_date
太白 = VIPUser('太白',6,'2019-01-01','2020-01-01')
print(太白.__dict__)
{'name': '太白', 'level': 6, 'strat_date': '2019-01-01', 'end_date': '2020-01-01'}
Process finished with exit code 0
(3)封装
1、什么是封装?
- 把 属性 和 方法 装到一个类中,然后通过 对象 直接或者 self 间接获取被封装的内容
广义 :把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
狭义 :把属性和方法藏起来,外面不能调用,只能在内部偷偷调用(私有属性,私有方法)
2、私有属性和私有方法
- 对于私有属性和私有方法,只能在类的内部访问,类的外部无法访问
- 在定义属性或⽅法时,在属性名或者⽅法名前 增加两个下划线,定义的就是私有属性或方法
私有属性:
class User:
def __init__(self,name,passwoed):
self.name=name
self.__passwoed=passwoed
def get_passwoed(self):
return self.__passwoed #只有在类内部才可以通过 self__passwoed 的形式访问到
obj=User('mike','123345')
#print(obj.__passwoed) #类的外部访问不了私有属性,报错
print(obj.get_passwoed()) #类的内部可以调用私有属性,
思考:既然类的外部访问不了了,那为什么我还有在类的内部定义一个 def get_passwoed(self) 方法呢?
----因为有时候我想让你看的私有属性 ,但是我不想让你该我的私有属性
私有方法:
import hashlib
class User:
def __init__(self,name,passwd):
self.usr = name
self.__pwd = passwd # 私有的实例变量
def __get_md5(self): # 私有的绑定方法
md5 = hashlib.md5(self.usr.encode('utf-8'))
md5.update(self.__pwd.encode('utf-8'))
return md5.hexdigest()
def getpwd(self):
return self.__get_md5()
alex = User('alex','sbsbsb')
print(alex.getpwd())
d6170374823ac53f99e7647bab677b92
Process finished with exit code 0
3、使用私有属性或/方法的三种场景?
# 使用私有的三种情况
# 不想让你看也不想让你改
# 可以让你看 但不让你改
# 可以看也可以改 但是要求你按照我的规则改
# 所有的私有化都是为了让用户不在外部调用类中的某个名字
# 如果完成私有化 那么这个类的封装度就更高了 封装度越高各种属性和方法的安全性也越高 但是代码越复杂
4、加了双下划线的名字为啥不能从类的外部调用了?
class User:
__Country = 'China' # 私有的类属性
__Role = '法师'
def func(self):
print(self.__Country) #在内的类别使用的时候,自动的吧当前这句话所在的类的名字拼在私有变量前面,来完成调用
print(User.__dict__)
#非要取私有属性?--可以
print(User._User__Country)
{'_User__Country': 'China', '_User__Role': '法师'}
China
Process finished with exit code 0
5、私有的内容能不能被子类使用呢?
--- 不能,原因看面试题2
面试题1:打印什么结果?
class Foo(object):
def __init__(self):
self.func()
def func(self):
print('in Foo')
class Son(Foo):
def func(self):
print('in Son')
Son()
in Son
Process finished with exit code 0
- 图像解析:
面试题2:打印什么结果?
class Foo(object):
def __init__(self):
self.__func()
def __func(self):
print('in Foo')
class Son(Foo):
def __func(self):
print('in Son')
Son()
in Foo
Process finished with exit code 0
- 图片解析
面试题3:打印什么结果?
---会报错,因为找不到 _son__func() 方法
class Foo(object):
def __func(self):
print('in Foo')
class Son(Foo):
def __init__(self):
self.__func()
Son()
AttributeError: 'Son' object has no attribute '_Son__func'
Process finished with exit code 1
6、类中的三个装饰器(内置函数)
6.1、@property
- pao po t
- 把一个方法伪装成一个属性,在调用这个方法的时候不需要加 () 就可以直接得到返回值
#(1)property
#例子:计算圆得面积
from math import pi
class Circle:
def __init__(self,r):
self.r = r
@property # 把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值
def area(self):
return pi * self.r**2
c1=Circle(5)
print(c1.r)
#print(c1.area()) #area()面积是一个方法,但是其实叫属性会好点,所以引用@property 装饰器
print(c1.area)
# 变量的属性和方法?
# 属性 :圆形的半径\圆形的面积
# 方法 :登录 注册
-
用@property装饰的这个方法 不能有参数
--可以理解属性没发传参数,方法在可以传参数
import time
class Person:
def __init__(self,name,birth):
self.name = name
self.birth = birth
@property
def age(self): # 用@property装饰的这个方法 不能有参数
return time.localtime().tm_year - self.birth
太白 = Person('太白',1995)
print(太白.age)
- @property的第二个应用场景 : 和私有的属性合作的
# property的第二个应用场景 : 和私有的属性合作的
class User:
def __init__(self,usr,pwd):
self.usr = usr
self.__pwd = pwd
@property
def pwd(self):
return self.__pwd
alex = User('alex','sbsbsb')
print(alex.pwd)
sbsbsb
Process finished with exit code 0
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 * self.discount
apple = Goods('apple',5)
#print(apple.price()) #很变扭,因为苹果的价格应该是属性,叫方法很变扭
print(apple.price)
- @property进阶
# property进阶 ---想把苹果的价格该一下?怎么办?
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 * self.discount
@price.setter
def price(self,new_value):
if isinstance(new_value,int): #约束new_value的值是int类型 才执行
self.__price = new_value
apple = Goods('apple',5)
print(apple.price) # 调用的是被@property装饰的price
apple.price = 10 # 调用的是被setter装饰的price
print(apple.price)
6.2、@classmethod(类方法)
普通方法可以访问类方法/类属性,类方法不能访问普通方法,因为访问普通方法需要对象
被装饰的方法会成为一个静态方法(类方法)
- 用@classmethod 修饰的方法为类方法;
- 类方法的参数为 cls (不是self),在类方法内部通过 cls.类属性 或者 cls.类方法 来访问同一个类中的其他类属性和类方法(类方法不能访问普通方法,因为访问普通方法需要对象)
- 类方法不需要实例化就可以调用 (可以通过类名或者对象名调用),类方法只能访问同一个类中的类属性和类方法。
# classmethod 被装饰的方法会成为一个静态方法
class Goods:
__discount = 0.8
def __init__(self):
self.__price = 5
self.price = self.__price * self.__discount
# 想修改折扣0.6====v1.0(不用类方法)
# def change_discount(self,new_discount):
# #self.__discount #这个地方不能用self 这样的话 相当于在self这个空间里创建了__discount
# Goods.__discount=new_discount
# 想修改折扣0.6====v2.0(用类方法)
@classmethod # 把一个对象绑定的方法 修改成一个 类方法
def change_discount(cls,new_discount):
cls.__discount=new_discount #用Goods.__discount也可以,考虑到 类名可能会改
# apple=Goods()
# print(apple.price)
# #想修改折扣0.6
# apple.change_discount(0.6)
# apple2=Goods()
# print(apple2.price)
Goods.change_discount(0.6)
apple=Goods()
print(apple.price)
什么时候用@classmethod?
# 1.定义了一个方法,默认传self,但这个self没被使用
# 2.并且你在这个方法里用到了当前的类名,或者你准备使用这个类的内存空间中的名字的时候
6.3、@staticmethod
帮助我们把一个普通的函数挪到类中直接使用,制造静态方法使用
# @staticmethod 被装饰的方法会成为一个静态方法
class User:
pass
@staticmethod
def login(a,b): # 本身是一个普通的函数,被挪到类的内部执行,那么直接给这个函数添加 @staticmethod装饰器就可以了
print('登录的逻辑',a,b)
# 在函数的内部既不会用到self变量,也不会用到cls类
#用类名调用
User.login(1,2)
#用对象名调用
obj = User()
obj.login(3,4)
7、反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
- 用字符串数据类型的名字 来操作这个名字对应的 函数\实例变量\绑定方法\各种方法
语法:
getatter(对象名,'属性名') ==> 对象名.属性名
7.1、反射的应用:
- 应用场景:现在让我们打开浏览器,访问一个网站,你单击登录就跳转到登录界面,你单击注册就跳转到注册界面,等等,其实你单击的其实是一个个的链接,每一个链接都会有一个函数或者方法来处理
没学反射之前的解决方式:
class User:
def login(self):
print('欢迎来到登录页面')
def register(self):
print('欢迎来到注册页面')
def save(self):
print('欢迎来到存储页面')
while 1:
choose = input('>>>').strip()
if choose == 'login':
obj = User()
obj.login()
elif choose == 'register':
obj = User()
obj.register()
elif choose == 'save':
obj = User()
obj.save()
学了反射之后解决方式:
class User:
def login(self):
print('欢迎来到登录页面')
def register(self):
print('欢迎来到注册页面')
def save(self):
print('欢迎来到存储页面')
user = User()
while 1:
choose = input('>>>').strip()
if hasattr(user, choose):
func = getattr(user, choose)
func()
else:
print('输入错误。。。。')
8、封装总结
8.1、类的成员
属性的成员:
类属性:定义在类的里面,方法的外面(不用实例化就可以【类名.类属性名】直接调用)
普通属性:定义在初始化init方法中
私有属性:定义在类的里面,方法的外面,前面加上两个下划线,只能在类的内部访问,类的外部无法访问
class a:
company_name = '老男孩教育' # 类属性
__iphone = '1353333xxxx' # 私有属性
def __init__(self,age):
self.age=age #普通属性
def func(self,hight):
self.hight =hight #普通属性
return self.hight
#类属性 可以直接打印。不用实例化对象
print(a.company_name)
#打印普通属性
mike=a(18)
print(mike.age)
print(mike.func(180))
#打印使有属性 使用属性外部无法访问,除非用 _类名__私有属性名
print(a._a__iphone)
老男孩教育
18
180
1353333xxxx
Process finished with exit code 0
方法的成员:
普通方法:定义在类里的方法
私有方法:定义在类里的方法,前面加上两个下划线,只能在类的内部访问,类的外部无法访问(不能被继承)
类方法:定义在类里的方法,用@classmethod 修饰,类方法的参数为 cls (不是self),类方法不需要实例化就可 以调用,类方法只能访问同一个类中的类属性和类方法(访问普通方法要先实例化)。
class b:
def __init__(self): #普通方法
pass
def func1(self):
print("普通方法") #普通方法
#self.__func2() #普通方法中调用私有方法
#self.func3() #普通方法中调用类方法
def __func2(self): #私有方法
print('私有方法')
@classmethod
def func3(cls):
print('类方法') #类方法
# c=b() #类方法中调用普通方法 需要实例化
# c.func1()
# d=b() #类方法中调用私有方法 需要实例化
# d.__func2()
#调用普通方法
mike=b()
mike.func1()
#调用私有方法 外部不能调用,只能内部访问
#调用类方法 不用实例化
b.func3()
普通方法
类方法
Process finished with exit code 0
出处:https://www.cnblogs.com/wushaofan/p/17156647.html