面向对象高级语法部分
- 经典类vs新式类
- 静态方法、类方法、属性方法
- 类的特殊方法
- 反射
classical vs new style:
- 经典类:深度优先
- 新式类:广度优先
- super()用法
静态方法
首先看下面的例子
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name def eat(self):#创建eat方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
运行后输出结果
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
蘑菇 在吃猫粮
Process finished with exit code 0
把代码修改一下,
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @staticmethod def eat(self):#把eat()转变为静态方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
运行一下,输出结果报错了,提示eat()方法需要一个self参数,在eat()变成静态方法后,再通过实例调用eat()时,实例不会再把实例当做参数传入到self里了。换言之eat()实际上变成了普通的方法,与类已经没有关系了。
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py Traceback (most recent call last): File "D:/7_Python/S14/Day6/学习笔记.py", line 13, in <module> c1.eat() #c1对象调用eat()类方法 TypeError: eat() missing 1 required positional argument: 'self' Process finished with exit code 1
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给eat方法,即c1.eat(c1)
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @staticmethod def eat(self):#把eat()转变为静态方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat(c1) #c1对象调用eat()类方法
2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @staticmethod def eat():#把eat()转变为静态方法 print("%s 在吃猫粮" %"蘑菇" ) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
类方法
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @classmethod def eat(self):#创建eat方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
运行后报错,提示Cat没有name属性,因为name是个实例变量,类方法是不能访问实例变量的
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py Traceback (most recent call last): File "D:/7_Python/S14/Day6/学习笔记.py", line 13, in <module> c1.eat() #c1对象调用eat()类方法 File "D:/7_Python/S14/Day6/学习笔记.py", line 10, in eat print("%s 在吃猫粮" %self.name) AttributeError: type object 'Cat' has no attribute 'name' Process finished with exit code 1
再修改一下代码:
#创建一个Cat类 class Cat(object): name = "大黄"#添加类变量 def __init__(self,name): self.name = name @classmethod def eat(self):#创建eat方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
执行结果
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
大黄 在吃猫粮
Process finished with exit code 0
属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @property def eat(self):#创建eat方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat() #c1对象调用eat()类方法
运行结果报错:
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py Traceback (most recent call last): 蘑菇 在吃猫粮 File "D:/7_Python/S14/Day6/学习笔记.py", line 14, in <module> c1.eat() #c1对象调用eat()类方法 TypeError: 'NoneType' object is not callable Process finished with exit code 1
由于eat()方法现在已经变成了属性,所以在调用的时候不需要再加(),直接调用就可以了
#创建一个Cat类 class Cat(object): def __init__(self,name): self.name = name @property def eat(self):#创建eat方法 print("%s 在吃猫粮" %self.name) c1 = Cat("蘑菇") #创建一个对象 c1.eat #c1对象调用eat属性方法
结果如下:
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
蘑菇 在吃猫粮
Process finished with exit code 0
我们为什么要使用属性方法呢,直接使用静态属性不就好了吗。但是在很多场景下,我们不能简单的定义静态属性
class Cat(object): def __init__(self,name): self.name = name def checking_status(self): print("看看%s在干什么" %self.name) return 1 @property def cat_status(self): status = self.checking_status() if status == 0: print("睡觉") elif status == 1: print("吃饭") elif status == 2: print("喝水") else: print("不知道") c = Cat("蘑菇") c.cat_status
输出结果
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py
看看蘑菇在干什么
吃饭
Process finished with exit code 0
cat_status既然现在是静态属性,能不能给它赋值
c = Cat("蘑菇") c.cat_status c.cat_status = 2
报错了
D:\7_Python\Python37\python.exe D:/7_Python/S14/Day6/学习笔记.py 看看蘑菇在干什么 吃饭 Traceback (most recent call last): File "D:/7_Python/S14/Day6/学习笔记.py", line 26, in <module> c.cat_status = 2 AttributeError: can't set attribute Process finished with exit code 1
怎么办
通过@proerty.setter装饰器再装饰一下,此时 需要写一个新方法, 对这个cat_status进行更改
class Cat(object):
def __init__(self,name):
self.name = name
self.status = 1
def checking_status(self):
print("看看%s在干什么" %self.name)
return self.status
@property
def cat_status(self):
self.status = self.checking_status()
if self.status == 0:
print("睡觉")
elif self.status == 1:
print("吃饭")
elif self.status == 2:
print("喝水")
else:
print("不知道")
@cat_status.setter
def cat_status(self,status):
status_dic = {
0 : "睡觉",
1 : "吃饭",
2 : "喝水",
}
print("\033[31;1m准备去 \033[0m",status_dic.get(status))
self.status = status
@cat_status.deleter #删除
def cat_status(self):
print("status got removed...")
c = Cat("蘑菇")
c.cat_status
c.cat_status = 0
c.cat_status
挺有意思
类的特殊成员方法
1. __doc__ 表示类的描述信息
class Cat(object): '''描述猫咪的各种生活习惯''' def func(self): pass print(Cat.__doc__)
2. __call__ 对象后面加括号,触发执行。
class Cat(object): '''描述猫咪的各种生活习惯''' def func(self): pass def __call__(self, *args, **kwargs): print('喵喵') c = Cat() c()
3. __dict__ 查看类或对象中的所有成员
class Cat(object): '''描述猫咪的各种生活习惯''' def __init__(self,name): self.name = name def func(self, *args, **kwargs): print('%s 喵喵'%self.name) c = Cat("蘑菇") c.func() print(Cat.__dict__) print(c.__dict__)
4 __str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Cat(object): '''描述猫咪的各种生活习惯''' def __init__(self,name): self.name = name def func(self, *args, **kwargs): print('%s 喵喵'%self.name) def __str__(self): return '蘑菇是只猫咪' c = Cat("蘑菇") c.func() print(c)
5.__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
6 __new__ \ __metaclass__
反射
# hasattr(obj,func) 判断obj中有没有func # getattr(obj,func) 从obj中获取func # setattr(obj,func1,func/xyz) 在obj中以func1名称设置func或变量 # delattr(obj,func) 在obj中删除func class Cat(object): def __init__(self,name,food): self.name = name self.food = food def eat(self): print("%s在吃%s" %(self.name,self.food)) def play(self): print("%s在玩耍" %self.name) c = Cat("蘑菇","猫粮") #c.eat() user_option = input(">>:").strip() if hasattr(c,user_option): func = getattr(c,user_option) func() else: setattr(c,user_option,play) func = getattr(c,user_option) func(c) print(c.__dict__) # delattr(c,'eat') # c.eat()