Python 面向对象编程(进阶 I)

时间:2023-02-15 16:11:33

类的成员可以分为三大类:字段、方法和属性

所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份

 Python 面向对象编程(进阶 I)

 

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同

  • 普通字段属于对象
  • 静态字段属于

应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

 举个例子,模拟CS游戏场景:

class createRole(object):
ac
=None # 类属性/变量, 静态字段
Num=0
def __init__(self,name,role,weapon,lifeValue):
self.Name=name # self.Name 成员属性/变量
self.Role=role
self.Weapon
=weapon
self.LifeValue
=lifeValue
createRole.Num
+=1

def buyWeapon(self,weapon): #类的方法(普通方法)
print('%s is buying [%s]' %(self.Name,weapon))
self.Weapon
=weapon

p1
=createRole('P1','Police','B10',100)
t1=createRole('T1','Terrorist','B11',100)
p2
=createRole('P1','Police','B12',100)
t2
=createRole('T2','Terrorist','B13',100)

p1.ac
='China-made'
t1.ac
='Japan-made'

createRole.ac
='US-made'
createRole.Weapon
='XD' #创建了一个类中的变量Weapon,并赋值,和实例化后的Weapon变量不同
p1.buyWeapon('AK47') #createRole.buy_weapon(p1,'AK47')
t1.buyWeapon('B51') #和ac一样,buyWeapon并没有在每个类的实例化对象中都创建一遍,所有的实例化对象都共用类中的buyWeapon

print('P1:', p1.Weapon, p1.ac, id(p1.ac))
print('T1:', t1.Weapon, t1.ac, id(t1.ac))
print('P2:', p2.Weapon, p2.ac, id(p2.ac))
print('T2:', t2.Weapon, t2.ac, id(t2.ac))
print(createRole.ac,createRole.Num,id(createRole.ac))

执行结果:
P1 is buying [AK47]
T1 is buying [B51]
P1: AK47 China-made 139965298329840
T1: B51 Japan-made 139965298329904
P2: B12 US-made 139965298317328
T2: B13 US-made 139965298317328
US-made 4 139965298317328
# 可以看到p1.ac,p2.ac语句创建了一个实例变量ac,和类中的ac变量不同

 

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:至少一个self参数,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量。
  • 静态方法:静态方法不可以访问实例变量或类变量,由调用;通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法
  • 类方法:类方法只能访问类变量,不能访问实例变量,由调用;类方法通过@classmethod装饰器实现

静态方法

  修改上个例子加上装饰器如下
  @staticmethod
def buyWeapon(self,weapon): #类的方法(静态方法) print('%s is buying [%s]' %(self.Name,weapon))
self.Weapon
=weapon

再次执行,结果如下:
TypeError: buyWeapon() missing 1 required positional argument: 'weapon'

分析:当 buyWeapon 变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
有两种解决办法:
1、调用时主动传递实例本身给 buyWeapon 方法
p1.buyWeapon(p1,'AK47')
t1.buyWeapon(t1,'B51')
2、在buyWeapon方法中去掉self参数,但这也意味着,在buyWeapon中不能通过self.调用实例中的其它变量了

类方法

  修改上个例子加上装饰器如下
  @classmethod
def buyWeapon(self,weapon): #类的方法(类方法)
print('%s is buying [%s]' %(self.Name,weapon))
self.Weapon
=weapon
再次执行,结果如下:
AttributeError: type object 'createRole' has no attribute 'Name'

分析:name是个实例变量,类方法是不能访问实例变量的,只能访问类变量
  @staticmethod
def buyWeapon(self,weapon): #类的方法(类方法) print(self.ac,weapon)
self.Weapon=weapon

再次执行,结果如下:

US-made AK47
US-made B51
P1: B10 China-made 139988741179632
T1: B11 Japan-made 139988741179696
P2: B12 US-made 139988741167120
T2: B13 US-made 139988741167120
US-made 4 139988741167120

对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。方法调用者不同、调用方法时自动传入的参数不同。

 

属性

 

属性的作用就是把一个方法变成一个静态属性,其实是普通方法的变种

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段

 

装饰器方式:在类的普通方法上应用@property装饰器


class
Foo: def func(self):
pass

# 定义属性,属性仅有一个self参数
@property
def prop(self):
pass

foo_obj
= Foo()
foo_obj.func()
#调用方法
foo_obj.prop #调用属性

把一个方法变成静态属性有什么用呢?Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。

比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步 :

1. 连接航空公司API查询

2. 对查询结果进行解析 

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以。

Python 面向对象编程(进阶 I)Python 面向对象编程(进阶 I)
class Flight(object):
def __init__(self,name):
self.flight_name
= name


def checking_status(self):
print("checking flight %s status " % self.flight_name)
return 1

@property
def flight_status(self):
status
= self.checking_status()
if status == 0 :
print("flight got canceled...")
elif status == 1 :
print("flight is arrived...")
elif status == 2:
print("flight has departured already...")
else:
print("cannot confirm the flight status...,please check later")


f
= Flight("CA980")
f.flight_status
Flight

 

经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
新式类(继承object类)中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

Python 面向对象编程(进阶 I)Python 面向对象编程(进阶 I)
class Goods(object):

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()
print(obj.price) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price) # 获取商品价格
del obj.price # 删除商品原价
print(obj.price) # 获取商品价格

执行结果:
80.0
160.0
AttributeError:
'Goods' object has no attribute 'original_price'
View Code

 

静态字段方式,创建值为property对象的静态字段。当使用静态字段的方式创建属性时,经典类和新式类无区别

property的构造方法中有个四个参数

  • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
  • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
  • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
  • 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
Python 面向对象编程(进阶 I)Python 面向对象编程(进阶 I)
class Goods(object):

def __init__(self):
self.original_price
= 100 # 原价
self.discount = 0.8 # 折扣

def get_price(self):
new_price
= self.original_price * self.discount # 实际价格 = 原价 * 折扣
return new_price

def set_price(self, value):
self.original_price
= value

def del_price(self):
del self.original_price

#PRICE = property(get_price, set_price, del_price, '价格属性描述...')
PRICE = property(get_price, set_price, del_price, '123')

obj
= Goods()
print(obj.PRICE) # 获取商品价格
obj.PRICE = 200 # 修改商品原价
print(obj.PRICE) # 获取商品价格
print(obj.PRICE.__doc__)
del obj.PRICE # 删除商品原价
print(obj.PRICE) # 获取商品价格

不知道这里为什么获取不到doc
View Code

Python WEB框架 Django 的视图中 request.POST 就是使用的静态字段的方式创建的属性