4.4-类的成员
类的成员
类分为两块区域:
- 第一部分:静态字段;
- 第二部分:方法部分;
每个区域详细划分:
class A:
name = '黑色利穆' # 静态变量(静态字段)
__name = '白色利穆' # 私有静态变量(私有静态字段)
def __init__(self, name, age): # 特殊方法
self.name = name # 对象属性(普通字段)
self.__age = age # 私有对象属性(私有普通字段)
def func1(self): # 普通方法
pass
def __func2(self): # 私有方法
pass
@classmethod # 类方法
def class_func(cls):
'''定义类方法,至少有一个cls参数'''
print('类方法')
@staticmethod # 静态方法
def static_func():
'''定义静态方法,无默认参数'''
print('静态方法')
@property # 属性
def prop(self):
pass
类的私有成员
对于每一个类的成员而言都有两种形式:
- 公有成员,在任何地方都能访问;
- 私有成员,只有在类的内部才能访问;
私有成员和公有成员的访问限制不同:
静态字段(静态属性):
- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问;
- 私有静态字段:仅类内部可以访问;
公有静态属性(字段)
class A:
name = '公有静态字段'
def func(self):
print(A.name)
class B(A):
def show(self):
print(A.name)
print(A.name) # 类访问
obj = A()
obj.func() # 类内部访问
obj_son = B()
obj_son.show() # 派生类中可以访问
私有静态属性(字段)
class A:
__name = '私有静态字段'
def func(self):
print(A.__name)
class B(A):
def show(self):
print(A.__name)
# print(A.__name) # 不可在外部访问
obj = A()
# obj.__name # 不可在外部访问
obj.func() # 类内部可以访问
# obj_son = B()
# obj_son.show() # 不可在派生类中访问
普通字段(对象属性)
- 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问;
- 私有普通字段:仅类内部可以访问;
公有对象属性
class A:
def __init__(self):
self.foo = '公有字段'
def func(self):
print(self.foo) # 类内部访问
class B(A):
def show(self):
print(self.foo) # 派生类中访问
obj = A()
print(obj.foo) # 通过对象访问
obj.func() # 类内部访问
obj_son = B()
obj_son.show() # 派生类中访问
私有对象属性
class A:
def __init__(self):
self.__foo = '私有字段'
def func(self):
print(self.__foo) # 类内部访问
class B(A):
def show(self):
print(self.__foo) # 派生类中访问
obj = A()
# print(obj.__foo) # 通过对象访问 不行
obj.func() # 类内部访问 可以
# obj_son = B()
# obj_son.show() # 派生类中访问 不行
方法
- 公有方法:对象可以访问;类内部可以访问;派生类可以访问;
- 私有方法:仅类内部可以访问;
公有方法
class A:
def __init__(self):
pass
def add(self):
print('in A')
class B(A):
def show(self):
print('in B')
def func(self):
self.show()
obj = B()
obj.show() # 通过对象访问
obj.func() # 类内部访问
obj.add() # 派生类访问
私有方法
class A:
def __init__(self):
pass
def __add(self):
print('in A')
class B(A):
def __show(self):
print('in B')
def func(self):
self.__show()
obj = B()
# obj.__show() # 不能通过对象访问
obj.func() # 类内部可以访问
# obj.__add() # 派生类不可以访问
总结
对于这些私有成员来说,只能在类内部使用,不能在类的外部以及派生类中使用;
ps:私有成员可以通过 对象._类__属性名 方式访问,但是绝对禁止的。
为什么可以通过 对象._类__属性名 访问?因为在类的创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)都会将其保存在内存时自动在前边加上 _类名.
类的其他成员
其他成员:类方法
方法包括:普通方法,静态方法,和类方法。三种方法在内存中都属于类,但是调用方式不同;
实例方法
第一个参数必须是实例对象,该参数名一般为self,通过它来传递实例的属性和方法(也可以传递类的属性和方法);
调用:只能由实例对象调用;
实例方法就是类的实例能够使用的方法;
类方法
使用装饰器@classmethod,第一个参数必须是当前类对象,该参数名一般为cls,通过它来传递类的属性和方法(不能传递实例的属性和方法);
调用:实例对象和类的对象都可以调用;
'''
需求:现在有一个班级类和学生类;
执行班级人数增加的操作,或得班级的总人数;
学生类继承班级类,每实例化一个学生,班级总人数增加;
最后,定义一写学生,或得班级中的总人数;
'''
class Stu:
__num = 0
def __init__(self, name, age):
self.name = name
self.age = age
Stu.addNum()
@classmethod
def addNum(cls):
cls.__num += 1
@classmethod
def getNum(cls):
return cls.__num
a = Stu('黑色利穆', 25)
b = Stu('色利穆', 26)
c = Stu('利穆', 27)
d = Stu('穆', 28)
print(Stu.getNum())
静态方法
使用装饰器@staticmethod,参数随意,没有self和cls参数,但是方法体重不能使用类或实例的任何属性和方法;
调用:实例对象和类对象都可以调用;
静态方法是类中的函数,不需要实例。静态方法主要用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的,单独的函数,仅仅托管于某个类的名称空间中,方便使用和维护。
# 定义一个关于时间的类,其中有一个获取当前时间的函数
import time
class TimeTest():
def __init__(self, hour, minute, second):
self.hour = hour
self.minute = minute
self.second = second
def test(self):
return f'{self.hour}时{self.minute}分{self.second}秒'
@staticmethod
def showTime():
return time.strftime('%H:%M:%S', time.localtime())
print(TimeTest.showTime())
t = TimeTest(10,10,10)
print(t.test())
如上,使用了静态方法(函数),方法体中并没有使用(也不能使用)类或实例的属性(方法)。若要或得当前时间的字符串时,并不一定需要实例化对象,此时对于静态方法而言,所在类更像是一种名称空间;
属性
将方法伪装成属性
property是一种特殊的属性,访问它时会执行一段(函数)然后返回值
'''
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('黑色利穆', 78, 1.72)
print(p1.bmi)
使用property的原因:
将一个类的函数定义成特性后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的。这种特性的使用方式遵循了统一访问的原则;
# 根据属性的访问特点,分别将三个方法定义为对同一个属性的:获取,修改,删除
class Foo:
@property
def AAA(self):
print('get')
@AAA.setter
def AAA(self, value):
print('set')
@AAA.deleter
def AAA(self):
print('del')
# 只有在属性AAA定义property后,才能定义AAA.setter, AAA.deleter
f = Foo()
f.AAA # get
f.AAA = 'bbb' # set
del f.AAA # del
或者
# 根据属性的访问特点,分别将三个方法定义为对同一个属性的:获取,修改,删除
class Foo:
def get_AAA(self):
print('get')
def set_AAA(self, value):
print('set')
def delete_AAA(self):
print('del')
AAA = property(get_AAA, set_AAA, delete_AAA) # 内置property三个参数与get,set,delete一一对应
# 只有在属性AAA定义property后,才能定义AAA.setter, AAA.deleter
f = Foo()
f.AAA # get
f.AAA = 'bbb' # set
del f.AAA # del
练习
class Googs():
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 = Googs()
print(obj.price) # 获取商品价格
obj.price = 200 # 修改商品价格
print(obj.price) # 获取修改后价格的折扣价格
del obj.price # 删除商品价格
双下方法
特殊方法,由解释器提供,由双下划线加方法名加双下划线 的具有特殊意义的方法,双下方法主要是python源码程序员使用;开发中尽量不要使用双下方法
isinstace 与 issubclass
# isinstance(a,b) 判断a是否是b类(或b类的派生类)实例化的对象
class A:
pass
class B(A):
pass
obj = B()
print(isinstance(obj, B)) # True
print(isinstance(obj, A)) # True
# issubclass(a, b) 判断a类是否是b类(或b的派生类)的派生类
class A:
pass
class B(A):
pass
class C(B):
pass
print(issubclass(B, A)) # True
print(issubclass(C, A)) # True
思考:那么list,str,tuple,dict这些类与Iterble类的关系?
from collections import Iterable
print(isinstance([1,2,3], list)) # True
print(isinstance([1,2,3], Iterable)) # True
print(issubclass(list, Iterable)) # True
# 如上,这些可迭代的数据类型,list,str,tuple,dict等,都是Iterable的子类
元类type
按照python的一切皆对象理论,类也是一个对象,那么类这个对象是如何实例化来的呢?
print(type('abc'))
print(type(True))
print(type(100))
print(type([1, 2, 3]))
print(type({'name': '黑色利穆'}))
print(type((1,2,3)))
print(type(object))
class A:
pass
print(isinstance(object, type))
print(isinstance(A, type))
type元类是获取该对象从属于的类,而type类比较特殊;python原则:一切皆对象,其实类也可以理解为对象,而type元类又称作构建类,python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造的;
而type类与object类之间的关系比较特殊:object是type类的实例,而type类是object类的子类。