1. 实例方法—— 方法内部需要访问实例属性
    实例方法 内部可以使用 类名. 访问类属性
  2. 类方法 —— 方法内部 只 需要访问 类属性
  3. 静态方法 —— 方法内部,不需要访问 实例属性 和 类属性
    提问
    如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?

    细分类的组成成员

    类主要有两部分组成
  • 静态字段(变量)部分
  • 方法部分

    1. class A:
    2. # 第一部分:静态字段(静态变量)部分
    3. name = '陈松'
    4. # 第二部分:方法部分
    5. def __init__(self):
    6. pass
    7. def func(self):
    8. pass

    每个区域的详细划分

    1. class A:
    2. name = 'zhangsan' # 静态变量
    3. __telphone = '132xxxxxxx' # 私有静态变量
    4. def __init__(self, where, status): # 特殊方法
    5. self.where = where # 对象属性
    6. self.__status = status # 私有对象属性
    7. def func(self): # 普通方法
    8. pass
    9. def __func(self): # 私有方法
    10. pass
    11. @classmethod
    12. def class_func(cls): # 类方法
    13. # 定义类方法,至少要有一个cls参数
    14. print('类方法')
    15. pass
    16. @staticmethod
    17. def static_func(): # 静态方法
    18. # 静态方法没有默认参数
    19. print('静态方法')
    20. pass
    21. @property
    22. def prop(self): # 方法当属性用
    23. pass

    类的私有成员

    对每一个类的成员有两种形式:

  • 公有成员:在任何地方都可以访问

  • 私有成员:只有在类的内部才可以访问

    私有成员和公有成员的访问限制不同

    静态字段(静态属性)

  • 公有静态字段:类可以访问;类的内部可以访问;派生类中可以访问

  • 私有静态字段:仅类的内部可以访问

公有静态字段访问实例

  1. class C:
  2. name = "公有静态字段"
  3. def func(self):
  4. print(C.name)
  5. class D(C):
  6. def show(self):
  7. print(C.name)
  8. # 类访问
  9. print(C.name)
  10. # 类内部访问
  11. obj = C()
  12. obj.func()
  13. # 派生类中访问
  14. obj_son = D()
  15. obj_son.show()
  16. # 运行结果
  17. 公有静态字段
  18. 公有静态字段
  19. 公有静态字段

私有静态字段访问实例(只能在类内部访问)

  1. class C:
  2. __name = "私有静态字段"
  3. def func(self):
  4. print(C.__name)
  5. class D(C):
  6. def show(self):
  7. print(C.__name)
  8. obj = C()
  9. obj.func()
  10. # 运行结果
  11. 私有静态字段

普通字段(对象属性)

  • 公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
  • 私有普通字段:仅类内部可以访问;

公有普通字段实例

  1. class C:
  2. def __init__(self):
  3. self.foo = "公有字段"
  4. def func(self):
  5. print(self.foo) # 类内部访问
  6. class D(C):
  7. def show(self):
  8. print(self.foo) # 派生类中访问
  9. obj = C()
  10. print(obj.foo) # 通过对象访问
  11. obj.func() # 类内部访问
  12. obj_son = D();
  13. obj_son.show() # 派生类中访问
  14. # 运行结果
  15. 公有字段
  16. 公有字段
  17. 公有字段

私有普通字段实例(只能类内部访问)

  1. class C:
  2. def __init__(self):
  3. self.__foo = "私有字段"
  4. def func(self):
  5. print self.foo # 类内部访问
  6. class D(C):
  7. def show(self):
  8. print self.foo # 派生类中访问
  9. obj = C()
  10. print(obj.__foo) # 通过对象访问 ==> 错误
  11. obj.func() # 类内部访问 ==> 正确
  12. obj_son = D();
  13. obj_son.show() # 派生类中访问 ==> 错误

方法

  • 公有方法:对象可以访问;类内部可以访问;派生类中可以访问
  • 私有方法:仅类内部可以访问;

公有方法实例

  1. class C:
  2. def __init__(self):
  3. pass
  4. def add(self):
  5. print('in C')
  6. class D(C):
  7. def show(self):
  8. print('in D')
  9. def func(self):
  10. self.show()
  11. obj = D()
  12. obj.show() # 通过对象访问
  13. obj.func() # 类内部访问
  14. obj.add() # 派生类中访问

私有对象实例

  1. class C:
  2. def __init__(self):
  3. pass
  4. def __add(self):
  5. print('in C')
  6. class D(C):
  7. def __show(self):
  8. print('in D')
  9. def func(self):
  10. self.__show()
  11. obj = D()
  12. obj.__show() # 通过不能对象访问
  13. obj.func() # 类内部可以访问
  14. obj.__add() # 派生类中不能访问

总结

私有成员的访问只能在类内部(通过使用类内的公有方法如前几例中的func),不能在类外部或派生类中访问。

ps:非要访问私有成员的话,可以通过 对象.类_属性名(如obj._C__name),但是绝对不允许!!!
这是因为私有成员不能被直接访问的本质就是保存在内存时在前面自动加上 _类名,这样直接调用原来的私有成员名自然访问不到东西了。

  1. class C:
  2. def __init__(self):
  3. self.__foo = "私有字段"
  4. def func(self):
  5. print
  6. self.foo # 类内部访问
  7. class D(C):
  8. def show(self):
  9. print
  10. self.foo # 派生类中访问
  11. obj = C()
  12. print(obj.__dir__())
  13. print(obj._C__foo)
  14. # 运行结果
  15. ['_C__foo', '__module__', '__init__', 'func', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
  16. 私有字段

类的其他成员(方法)

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

实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传
类的属性和方法);

调用:只能由实例对象调用。

类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传
递类的属性和方法(不能传实例的属性和方法);

调用:实例对象和类对象都可以调用。

静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例
的任何属性和方法;

调用:实例对象和类对象都可以调用。

双下方法
定义:双下方法是特殊方法,他是解释器提供的 由双下划线方法名双下划线 方法名的具有特殊意
义的方法,双下方法主要是python源码程序员使用的,

我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。
调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方
法,例如:init

类方法

使用装饰器@classmethod。
原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身
作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方
法。

如下场景:

  • 假设我有一个学生类和一个班级类,想要实现的功能为:
    • 执行班级人数增加的操作、获得班级的总人数;
    • 学生类继承自班级类,每实例化一个学生,班级人数都能增加;
    • 最后,我想定义一些学生,获得班级中的总人数。

思考:这个场景使用类方法比较合适,为什么?因为我要实例化学生类,班级类的需要的功能是增加人数和获得班级总人数,实例化一个班级类是不必要的,然而从学生这一个实例获取班级总人数逻辑上也不合理。

  1. class Student:
  2. __num = 0
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. Student.addNum()
  7. @classmethod
  8. def addNum(cls):
  9. cls.__num += 1
  10. @classmethod
  11. def getNum(cls):
  12. return cls.__num
  13. Student('陈松', 18)
  14. Student('阿松', 36)
  15. Student('松松', 73)
  16. print(Student.getNum())
  17. # 运行结果
  18. 3

静态方法

使用装饰器@staticmethod。

静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和
类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方
法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。

譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。

  1. import time
  2. class TimeTest(object):
  3. def __init__(self, hour, minute, second):
  4. self.hour = hour
  5. self.minute = minute
  6. self.second = second
  7. @staticmethod
  8. def showTime():
  9. return time.strftime("%H:%M:%S", time.localtime())
  10. print(TimeTest.showTime())
  11. t = TimeTest(2, 10, 10)
  12. nowTime = t.showTime()
  13. print(nowTime)
  14. # 运行结果
  15. 22:45:56
  16. 22:45:56

方法综合案例

需求

  1. 设计一个 Game 类
  2. 属性:

定义一个 类属性 top_score 记录游戏的 历史最高分
定义一个 实例属性 player_name 记录 当前游戏的玩家姓名

  1. 方法:

静态方法 show_help 显示游戏帮助信息
类方法 show_top_score 显示历史最高分
实例方法 start_game 开始当前玩家的游戏

  1. 主程序步骤

1) 查看帮助信息
2) 查看历史最高分
3) 创建游戏对象,开始游戏
![7US)N0OQNGLGYUB{A(N0(R.png

案例小结

  1. 实例方法—— 方法内部需要访问实例属性

实例方法 内部可以使用 类名. 访问类属性

  1. 类方法 —— 方法内部 需要访问 类属性
  2. 静态方法 —— 方法内部,不需要访问 实例属性类属性

提问
如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?
答案
应该定义为实例方法,实例方法可以使用 类名. 访问类属性。

  1. class Game(object):
  2. top_score = 0
  3. @staticmethod
  4. def show_help():
  5. print("显示游戏帮助信息")
  6. pass
  7. @classmethod
  8. def show_top_score(cls):
  9. print("游戏历史最高分是:%s" % cls.top_score)
  10. def __init__(self, player_name):
  11. self.player_name = player_name
  12. def strat_game(self):
  13. print("%s开始游戏" % self.player_name)
  14. # 使用类名修改历史最高分
  15. Game.top_score = 999
  16. pass
  17. def main():
  18. # 查看游戏帮助
  19. Game.show_help()
  20. # 查看历史最高分
  21. Game.show_top_score()
  22. # 创建游戏对象,开始游戏
  23. game = Game("小明")
  24. game.strat_game()
  25. # 游戏结束,查看游戏最高分
  26. Game.show_top_score()
  27. if __name__ == '__main__':
  28. main()
  29. # 运行结果
  30. 显示游戏帮助信息
  31. 游戏历史最高分是:0
  32. 小明开始游戏
  33. 游戏历史最高分是:999

属性

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

  1. class People:
  2. def __init__(self,name,weight,height):
  3. self.name=name
  4. self.weight=weight
  5. self.height=height
  6. @property
  7. def bmi(self):
  8. return self.weight / (self.height**2)
  9. p1=People('陈松',75,1.85)
  10. print(p1.bmi)

相当于把一个方法封装成属性使用。

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

  1. class Foo:
  2. @property
  3. def AAA(self):
  4. print('get的时候运行我啊')
  5. @AAA.setter
  6. def AAA(self,value):
  7. print('set的时候运行我啊')
  8. @AAA.deleter
  9. def AAA(self):
  10. print('delete的时候运行我啊')
  11. # 只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
  12. f1=Foo()
  13. f1.AAA
  14. f1.AAA='aaa'
  15. del f1.AAA
  16. #运行结果
  17. get的时候运行我啊
  18. set的时候运行我啊
  19. delete的时候运行我啊

  1. class Foo:
  2. def get_AAA(self):
  3. print('get的时候运行我啊')
  4. def set_AAA(self,value):
  5. print('set的时候运行我啊')
  6. def delete_AAA(self):
  7. print('delete的时候运行我啊')
  8. AAA=property(get_AAA,set_AAA,delete_AAA)
  9. # 内置property三个参数与get,set,delete一一对应
  10. f1=Foo()
  11. f1.AAA
  12. f1.AAA='aaa'
  13. del f1.AAA

isinstace 与 issubclass

isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象

  1. class A:
  2. pass
  3. class B(A):
  4. pass
  5. obj = B()
  6. print(isinstance(obj,B))
  7. print(isinstance(obj,A))
  8. # 运行结果
  9. True
  10. True

issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类

  1. class A:
  2. pass
  3. class B(A):
  4. pass
  5. class C(B):
  6. pass
  7. print(issubclass(B,A))
  8. print(issubclass(C,A))
  9. # 运行结果
  10. True
  11. True