面向对象--内置函数(property\classmethod\staticmethod)
property属性
内置装饰器函数,只在面向对象中使用
作用:将类里的方法,伪装成属性,调用时看起来像是调用属性,而不是方法;
注意:被@property装饰的方法里,不能传参;
# 计算一个圆的面积周长
from math import pi
class Circle:
def __init__(self,r):
self.r = r
def perimeter(self):
return 2*pi*self.r
def area(self):
return self.r**2*pi
ret = Circle(5)
print(ret.area()) # 调用方法需要添加()
print(ret.perimeter())
#将方法伪装成属性,通过@property
# 注意被装饰的对象里的不能添加任何属性
from math import pi
class Circle:
def __init__(self,r):
self.r = r
@property
def perimeter(self): # 不能添加属性
return 2*pi*self.r
@property
def area(self): # 不能添加属性
return self.r**2*pi
ret = Circle(5)
print(ret.area) #伪装成属性,直接调用无需添加()
print(ret.perimeter)
# 典型面向对象的题
# BMI指数(BMI是计算而来,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
'''
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖:高于32
体质指数(BMI) = 体重(kg)/身高^2(m)
EX: 70KG/(1.75*1.75) = 22.86
'''
class People: def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2)
p1=People('egon',75,1.85)
print(p1.bmi)
BMI指数
为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
ps:面向对象的封装有三种方式:【public】 这种其实就是不封装,是对外公开的 【protected】 这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开 【private】 这种封装对谁都不公开
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现
class Foo: def __init__(self,val):
self.__NAME=val #将所有的数据属性都隐藏起来
@property
def name(self):
return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)
@name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError('%s must be str' %value)
self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME
@name.deleter
def name(self):
raise TypeError('Can not delete')
f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
一个静态属性property本质就是实现了get,set,delete三种方法
#注意: setter
class Goods: def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8
@property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self):
del self.original_price
obj = Goods()
obj.price # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
classmethod
类方法:类里面的操作行为,无需依托任何对象,直接可以被类调用
适用:当一个方法的操作涉及静态属性的时候,就应该适用classmethod来装饰这个方法
# 例子,修改静态属性class Goods:
discount = 0.5
def __init__(self,name,price):
self.name = name
self.__price = price
@property
def price(self):
return self.__price * Goods.discount
@classmethod # 把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
def change_discount(cls,new_discount):
cls.discount = new_discount
apple = Goods('Apple',5)
print(apple.price)
Goods.change_discount(0.8)
print(apple.price)
staticmethod
作用:在完全面向对象的过程中,如果一个函数既和对象没有关系,也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法。
# 例子:如登录实现完全面向对象编程# 常规写法
class Login:
def __init__(self,name,pwd):
self.name = name
self.pwd =pwd
def login():
username = input('username:')
password = input('password:')
Login(username,password)
login()
#完全面向对象
class Login:
def __init__(self,name,pwd):
self.name = name
self.pwd =pwd
@staticmethod # 将被装饰方法,转为一般函数,可以传参,也可以不传参,(注意:因为是一般函数,所以无需写self)
def login():
username = input('username:')
password = input('password:')
Login(username,password)
Login.login()
# 类方法和静态方法,都是类调用# 对象可以调用类方法和静态方法吗? 可以调用,一般情况下推荐用类名调用
# 类方法有一个默认参数cls 代表这个类
# 静态方法没有默认参数,就像函数一样,也是可以传参,传的是一般参数和 self和cls 不一样
练一练
class Foo: def func(self):
print('in father')
class Son(Foo):
def func(self):
print('in son')
s = Son()
s.func()
# 请说出上面一段代码的输出并解释原因?
# 实例化Son类# 调用func方法# 因为Son类自身有func方法,所以无需再去Foo类中找,所以直接使用自己的func方法
解答
class A: __role = 'CHINA' @classmethod
def show_role(cls):
print(cls.__role)
@staticmethod
def get_role():
return A.__role
@property
def role(self):
return self.__role
a = A()
print(a.role)
print(a.get_role())
a.show_role()
# __role在类中有哪些身份?
# 以上代码分别输出哪些内容?
# 这三个装饰器分别起了什么作用?有哪些区
class A: __role = 'CHINA' # 定义了一个私有静态属性,只能类内使用 @classmethod # 类方法,无须依托对象,即可通过类名调用被装饰的方法 def show_role(cls):
print(cls.__role)
@classmethod # 类方法,无须依托对象,即可通过类名调用被装饰的方法,修改默认参数
def edit_role(cls,newrole):
cls.__role = newrole
@staticmethod # 静态方法,被装饰的方法 与对象和类无关
def get_role():
return A.__role
@property # 将方法伪装成属性
def role(self):
return self.__role
A.show_role()
A.edit_role('CN')
a = A()
print(a.role)
print(a.get_role())
a.show_role()
解答