property、classmethod、staticmethod
1.property
把方法伪装成了属性
1 from math import pi 2 class Circle: 3 def __init__(self,r): 4 self.r = r 5 @property #把方法伪装成了属性 6 def perimeter(self): 7 return 2*pi*self.r 8 @property 9 def area(self): 10 return self.r**2*pi 11 12 c1 = Circle(5) 13 print(c1.area) 14 # 圆的面积 #之前的调用方法为c1.area() 15 print(c1.perimeter) 16 # 圆的周长 #之前的调用方法为c1.perimter()
1 #练习 2 #BMI指数(BMI是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 3 # 成年人的BMI数值 4 # 过轻:低于18.5 5 # 正常:18.5~23.9 6 # 过重:24~27 7 # 肥胖:28~32 8 # 非常肥胖:28~32 9 # 体质指数(BMI)=体重(kg)/身高^2(m) 10 # 例如:70kg÷(1.75*1.75)=22.86 11 12 class People: 13 def __init__(self,name,high,weight): 14 self.name = name 15 self.high = high 16 self.weight = weight 17 18 @property 19 def bmi(self): 20 return self.weight/self.high**2 21 22 xiaoli = People("小黎",1.66,47) 23 print(xiaoli.bmi()) #未加@property时,用此调用 24 print(xiaoli.bmi) #加了@property时,用此调用
1 class Goods: 2 def __init__(self): 3 # 原价 4 self.original_price = 100 5 # 折扣 6 self.discount = 0.8 7 8 @property 9 def price(self): 10 # 实际价格 = 原价 * 折扣 11 new_price = self.original_price * self.discount 12 return new_price 13 14 @price.setter #使用了这个可以修改类中的属性 15 def price(self, value): 16 self.original_price = value 17 18 @price.deleter 19 def price(self): 20 del self.original_price 21 print('已删除') 22 obj = Goods() 23 print(obj.price) # 获取商品价格 24 obj.price = 100 # 修改商品原价 25 print(obj.price) 26 del obj.price # 删除商品原价 27 #执行del,会调用deleter装饰的方法 28 29 #执行结果为: 30 # 80.0 31 # 80.0 32 # 已删除
classmethod 类方法
把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
1 class Classmethod_Demo(): 2 role = 'dog' 3 4 @classmethod 5 def func(cls): 6 print(cls.role) 7 8 Classmethod_Demo.func() 9 #输出结果为:dog
1 class Goods: 2 __discount = 0.8 3 def __init__(self,name,price): 4 self.name = name 5 self.__price = price 6 @property 7 def price(self): 8 return self.__price * Goods.__discount 9 @classmethod 10 # 把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象 11 def change_discount(cls,new_discount): # 修改折扣 12 cls.__discount = new_discount 13 apple = Goods('苹果',5) 14 print(apple.price) #--》4.0 15 Goods.change_discount(0.5) # Goods.change_discount(Goods) 16 print(apple.price) #--》2.5 17 # 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
staticmathod 静态的方法
用staticmethod将这个函数变成一个静态方法
1 class Login: 2 def __init__(self,name,password): 3 self.name = name 4 self.pwd = password 5 def login(self):pass 6 7 @staticmethod 8 def get_usr_pwd(): # 静态方法 9 usr = input('用户名 :') 10 pwd = input('密码 :') 11 Login(usr,pwd) 12 13 Login.get_usr_pwd() 14 # 在完全面向对象的程序中, 15 # 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法
# 类方法和静态方法 都是类调用的
# 对象可以调用类方法和静态方法。但是,一般情况下 推荐用类名调用
# 类方法 有一个默认参数 cls 代表这个类 cls
# 静态方法 没有默认的参数 就像函数一样
内置函数isinstance()和issubclass()
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
issubclass(sub, super)检查sub类是否是 super 类的子类
class A:pass class B(A):pass a = A() print(isinstance(a,A)) ->True #检查对象a是否是类A中的对象,是返回True print(issubclass(B,A)) ->True #检查类B是否是类A的子类 print(issubclass(A,B)) ->False
反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。
python中的一切事物都是对象(都可以使用反射)
面向对象中的几个内置函数
——hasattr,setattr,getattr,delattr
1 class Foo: 2 f = '类的静态变量' 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 7 def say_hi(self): 8 print('hi,%s'%self.name) 9 10 obj=Foo('egon',73) 11 12 #检测某个类是否含有某属性 13 print(hasattr(obj,'name')) 14 print(hasattr(obj,'say_hi')) 15 16 #获取某个类中的属性 17 #第一个位置为所属的对象,第二个为变量的字符串形式 18 n=getattr(obj,'name') #等价于obj.name 19 print(n) 20 func=getattr(obj,'say_hi') 21 func() 22 23 print(getattr(obj,'aaaaaaaa','不存在啊')) #报错 24 25 #设置属性 26 setattr(obj,'*名字*',True) 27 setattr(obj,'show_name',lambda self:self.name+'-名字') 28 print(obj.__dict__) 29 print(obj.show_name(obj)) 30 31 #删除属性 32 delattr(obj,'age') 33 delattr(obj,'show_name') 34 # delattr(obj,'show_name111')#不存在,报错 35 36 print(obj.__dict__) 37 38 输出结果为: 39 True 40 True 41 egon 42 hi,egon 43 不存在啊 44 {'name': 'egon', 'age': 73, '*名字*': True, 'show_name': <function <lambda> at 0x000002DBD32D2E18>} 45 egon-名字 46 {'name': 'egon', '*名字*': True}
__str__、__repr__
当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
1 class Car: 2 def __init__(self, newWheelNum, newColor): 3 self.wheelNum = newWheelNum 4 self.color = newColor 5 6 def __str__(self): 7 msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..." 8 return msg 9 10 def move(self): 11 print('车在跑,目标:夏威夷') 12 13 BMW = Car(4, "白色") 14 print(BMW) 15 #输出结果:嘿。。。我的颜色是白色,我有4个轮胎...
1 class B: 2 def __str__(self): 3 return 'str : class B' 4 5 def __repr__(self): 6 return 'repr : class B' 7 8 b = B() 9 print('%s' % b) 10 print('%r' % b) 11 #执行结果为: 12 # str : class B 13 # repr : class B
__del__
创建对象后,python解释器默认调用__init__()方法;
当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法
(在实例化一个对象的时候也会调用__del__方法)
1 class Foo: 2 3 def __del__(self): 4 print('执行我啦') 5 6 f1=Foo() 7 del f1 8 print('------->') 9 10 #输出结果 11 执行我啦 12 -------> 13 #在调用del时自动执行了类的内部__del__方法
__getitem__、__setitem__、__delitem__
1 class Foo: 2 def __init__(self,name): 3 self.name=name 4 5 def __getitem__(self, item): 6 print(self.__dict__[item]) 7 8 def __setitem__(self, key, value): 9 self.__dict__[key]=value 10 def __delitem__(self, key): 11 print('del obj[key]时,我执行') 12 self.__dict__.pop(key) 13 def __delattr__(self, item): 14 print('del obj.key时,我执行') 15 self.__dict__.pop(item) 16 17 f1=Foo('sb') 18 f1['age']=18 19 f1['age1']=19 20 del f1.age1 21 del f1['age'] 22 f1['name']='alex' 23 print(f1.__dict__) 24 25 #执行结果为: 26 # del obj.key时,我执行 27 # del obj[key]时,我执行 28 # {'name': 'alex'}
__new__
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
1 class A(object): 2 def __init__(self): 3 print("这是 init 方法") 4 5 def __new__(cls): 6 print("这是 new 方法") 7 return object.__new__(cls) 8 9 A() 10 #输出结果为: 11 #这是init方法 12 #这是new方法
类在实例化的时候会自动执行__init__方法和__new__方法
1 class A: 2 def __init__(self): 3 self.x = 1 4 print('in init function') 5 def __new__(cls, *args, **kwargs): 6 print('in new function') 7 return object.__new__(A, *args, **kwargs) 8 9 a = A() 10 #实例化时自动会调用__new__方法和__init__方法,先调用__new__方法 11 12 #执行结果为: 13 # in new function 14 # in init function
class Foo(object): def __init__(self): print(111) def __new__(cls, *args, **kwargs): return 'new' obj = Foo() print(obj) # new # 只会输出new,不会打印111
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class Foo: 2 def __init__(self): 3 pass 4 5 def __call__(self, *args, **kwargs): 6 7 print('__call__') 8 9 obj = Foo() # 执行 __init__ 10 obj() # 执行 __call__ 11 12 #执行结果:__call__
__len__
1 class A: 2 def __init__(self): 3 self.a = 1 4 self.b = 2 5 self.c = 1 6 7 def __len__(self): 8 return len(self.__dict__) #返回内中属性的个数 9 a = A() 10 print(len(a)) 11 #执行结果为:3 12 #执行len方法会自动调用类中的__len__方法
__hash__
1 class A: 2 def __init__(self): 3 self.a = 1 4 self.b = 2 5 6 def __hash__(self): 7 return hash(str(self.a)+str(self.b)) 8 a = A() 9 print(hash(a)) 10 #类的外部执行hash()时会调用类中的__hash__方法
__eq__
当判断两个对象的值是否相等时,就会执行类中__eq__方法,且得到的返回值将和在类中定义的__eq__的返回值的真假一致
1 class A: 2 def __init__(self): 3 self.a = 1 4 self.b = 2 5 6 def __eq__(self,obj): 7 if self.a == obj.a and self.b == obj.b: 8 return True 9 a = A() 10 b = A() 11 print(a == b) 12 #True
文章中大部分实例都来自Eva_J老师的文章,原文见博客