1、封装
类中的私有化:属性的私有化和方法的私有化
会用到私有的这个概念de场景
1.隐藏起一个属性 不想让类的外部调用
2.我想保护这个属性,不想让属性随意被改变
3.我想保护这个属性,不被子类继承
1 class Room: 2 """房间类""" 3 4 def __init__(self, name, length, width, height): 5 self.__name = name 6 self.__length = length 7 self.__width = width 8 self.__height = height 9 10 def get_name(self): 11 return self.__name 12 13 def set_name(self, new_name): 14 if type(new_name) is str and new_name.isdigit() == False: # 新名称是字符串且不能是数字 15 self.__name = new_name 16 17 def area(self): 18 return self.__length * self.__width 19 20 def volume(self): 21 return self.__length * self.__width * self.__height 22 23 24 room = Room('标准间', 3.6, 3.0, 3.2) 25 26 print(room.get_name()) 27 room.set_name('豪华间') 28 print(room.get_name()) 29 30 print(room.area()) 31 print(room.volume()) 32 33 34 # 子类无法继承父类中的私有属性和私有方法 35 36 37 class Foo: 38 __key = '123' # _Foo__key 39 40 41 class Son(Foo): 42 print(Foo.__key) # _Son__key 43 44 45 son = Son() 46 # son.__key # AttributeError: type object 'Foo' has no attribute '_Son__key'
2、属性方法
@property语法糖的使用场景
如果方法不得不使用名词,而规矩是名词是属性,动词是方法。而使用名词是将运算后的值给它。
1 class Room: 2 """房间类""" 3 4 def __init__(self, name, length, width, height): 5 self.__name = name 6 self.__length = length 7 self.__width = width 8 self.__height = height 9 10 def get_name(self): 11 return self.__name 12 13 def set_name(self, new_name): 14 if type(new_name) is str and new_name.isdigit() == False: # 新名称是字符串且不能是数字 15 self.__name = new_name 16 17 @property 18 def area(self): # 名词一般是属性,动词才是方法,为了解决有了属性语法糖 19 return self.__length * self.__width 20 21 @property 22 def volume(self): 23 return self.__length * self.__width * self.__height 24 25 26 room = Room('标准间', 3.6, 3.0, 3.2) 27 print(room.volume) # 有了@property可以像调用属性一样调用方法 28 print(room.area)
属性的 查看 修改 删除
1 class Person: 2 def __init__(self, name): 3 self.__name = name 4 5 @property 6 def name(self): 7 return self.__name 8 9 @name.setter # 修改 10 def name(self, new_name): 11 self.__name = new_name 12 13 @name.deleter # 删除 14 def name(self): 15 del self.__name 16 17 18 tom = Person('Tom') 19 print(tom.name) 20 tom.name = 'Jone' 21 print(tom.name) 22 del tom.name # 删除 有了@name.deleter才有效果 23 # print(tom.name) # AttributeError: 'Person' object has no attribute '_Person__name'
3、静态方法和类方法
method 方法
staticmathod 静态的方法 ***
classmethod 类方法 ****
类的操作行为
1)staticmethod 静态的方法
1 class Login: 2 def __init__(self, name, pwd): 3 self.name = name 4 self.__password = pwd 5 6 def login(self):pass 7 8 @staticmethod # 该语法糖是声明该方法为静态方法 9 def get_usr_pwd(): 10 usr = input('请输入登录名:》》》').strip() 11 pwd = input('请输入密码:》》》').strip() 12 Login(usr, pwd) 13 14 15 Login.get_usr_pwd()
静态方法的应用场景:在完全面向对象的程序中,如果一个函数,既跟对象没有关系,
也跟类没有关系 那么就用staticmethod将这个函数变成一个静态方法
2)classmethod 类方法
1 class Goods: 2 """商品类""" 3 discount_rate = 0.5 4 5 def __init__(self, name, price): 6 self.name = name 7 self.__price = price 8 9 @property 10 def price(self): 11 return self.__price * Goods.discount_rate 12 13 @classmethod # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象 14 def change_discount_rate(cls, new_rate): 15 cls.discount_rate = new_rate 16 17 18 apple = Goods('apple', 9.8) 19 print(apple.price) 20 # apple.change_discount_rate(0.75) 如此调用合理,商品的折扣率是类的事,不应该由实例来控制! 21 Goods.change_discount_rate(0.8) 22 print(apple.price)
类方法的应用场景:
当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
3)、小结
类方法和静态方法 都是类调用的
对象可以调用类方法和静态方法么? 可以 一般情况下 推荐用类名调用
类方法 有一个默认参数 cls 代表这个类 cls
静态方法 没有默认的参数 就象函数一样
4、反射
(1)、简介
有此使用场景,知道一个类中的方法名的字符串形式,如何调用该方法?
通过反射
对象名 获取对象属性 和 普通方法
类名 获取静态属性 和类方法 和 静态方法
普通方法 self
静态方法 @staticmethod
类方法 @classmethod
属性方法 @property
(2)、反射的使用场景
1 class Dog: 2 fur = 'golden' 3 def __init__(self, name, kind): 4 self.name = name 5 self.kind = kind 6 7 def bite(self): 8 print(self.name + "is biting!") 9 10 def walk(self): 11 print(self.name + "is walking!"
1)反射对象
1 dog = Dog('duck','harsci') 2 3 # 1)、反射对象的属性 4 if hasattr(dog, 'fur'): 5 print(getattr(dog, 'fur')) 6 7 # 2)、反射对象的方法 8 if hasattr(dog, 'bite'): 9 getattr(dog, 'bite')()
2)反射类
1 class A: 2 year = 2020 3 @classmethod 4 def get_year(cls): 5 print(cls.year) 6 # 1)获得类的属性 7 A.year 8 if hasattr(A, 'year'): 9 print(getattr(A, 'year')) 10 # 2)获得类的方法 11 if hasattr(A, 'get_year'): 12 getattr(A, 'get_year')() # 如果不加classmethod装饰器,会报错get_year() missing 1 required positional argument: 'self'
3)反射导入的模块
1 import time 2 3 t = '' 4 if hasattr(time, 'time'): 5 t = getattr(time, 'time')() # 得到当前的时间的时间戳 6 print(t) 7 8 t = time.localtime(t) # 将时间戳转化为结构时间 9 10 if hasattr(time, 'asctime'): 11 print(getattr(time, 'asctime')(t)) # asctime必须传结构时间
4)反射自身(坐在的模块)
1 import sys 2 # 查看系统中所有模块 3 print(sys.modules) 4 # 找到本模块对应的key 5 # '__main__': < module'__main__'from' D:/python_bases/day27/2_反射进阶.py' > 6 7 # 1)、获得本模块的属性 8 print(getattr(sys.modules["__main__"], 'dog').fur) 9 10 def get_year(): 11 print(time.asctime(time.localtime(time.time()))) 12 # 2)、获得本模块的方法 13 getattr(sys.modules['__main__'], 'get_year')() 14 15 # 如果别的模块引入该模块,会无法执行,因为写死了'__main__',要改为变量 16 __main__ = '__main__'
(3)、反射的剩余方法:
1 method_str = ['bite', 'walk'] 2 3 dog = Dog('金毛', '狮子狗') 4 5 if hasattr(Dog, 'bite'): # 内置函数一 6 bite = getattr(Dog, method_str[0]) # 内置函数二 7 8 bite(dog) 9 setattr(Dog, 'price', 999) # 内置函数三 10 print(dog.price) 11 12 delattr(Dog, 'price') # 内置函数四