初识面向对象(核心知识)(2)
类的方法
方法的动态性:Python 是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
例子:对比
class Person:#这是一个Person类
def work(self): # 这是一个Person类的一个方法
print("努力上班!")
p = Person() #正常情况下新建一个p类
p.work() #调用这个类的方法
执行结果:
努力上班!
Python 是动态语言,我们可以动态的新增新的方法或者替换方法。
class Person:#这还是一个Person类
def work(self): # 这还是一个Person类的一个方法
print("努力上班!")
#区别从这里开始
def play_game(self):
print("{0}玩游戏".format(self))
def work2(s):
print("好好工作,努力上班!")
#可以让Person 动态的新增 play_game 方法
Person.play = play_game#把play_game新增到Person里的play方法
Person.work = work2 # 用 work2 替换了 work 方法
p = Person() #还是新建一个p类
p.play()#调用新增的play()的方法
p.work()# 此时调用work()的方法为替换过后的work2方法
新增新的方法或者替换方法就叫做方法的动态性。
1 私有属性(实现封装)
共有属性的例子:
class Employee:
def __init__(self,name,age):
self.name = name
self.age = age
e = Employee("高淇",18)
print(e.name)
print(e.age)
print(dir(e))
执行结果
高淇
18
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
私有属性的实现:
class Employee:
def __init__(self,name,age):
self.__name = name #定义私有属性,“__”
self.__age = age
e = Employee("高淇",18)
#print(e.name) #此时再这样调用会出错
#print(e.age) #此时再这样调用会出错
print(e._Employee__name)
print(e._Employee__age)
print(dir(e))
执行结果:多了_类名__
高淇
18
['_Employee__age', '_Employee__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
2 私有方法
例子:
class Employee:
def __init__(self,name,age):
self.__name = name #定义私有属性,“__”
self.__age = age
def __work(self): # 私有实例方法 通过 dir 可以查到_Employee__work
print("工作!好好工作,好好赚钱,娶个媳妇!")
p1 = Employee("高淇",27)
print(p1._Employee__name)
print(p1._Employee__age) #通过这种方式可以直接访问到私有属性 。通过 dir 可以查到属性:_Employee__age
#print(p1.__age) #直接访问私有属性,报错
#p1.__sleep() #直接访问私有方法,报错
p1._Employee__work()
print(dir(p1)) #查询类的所有属性、方法
执行结果:
高淇
27
工作!好好工作,好好赚钱,娶个媳妇!
['_Employee__age', '_Employee__name', '_Employee__work', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
从打印的 Employee 对象所有属性我们可以看出。私有属性“__age”在实际存储时是按照“_Employee__age”这个属性来存储的。这也就是为什么我们不能直接使用“__age”而可以使用“_Employee__age”的根本原因。
总结:
Python 对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。关于私有属性和私有方法,有如下要点:
- 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)。
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
【注】方法本质上也是属性!只不过是可以通过()执行而已。所以,此处讲的私有属性和公有属性,也同时讲解了私有方法和公有方法的用法。如下测试中,同时也包含了私有方法和公有方法的例子。
3 @property 装饰器
@property 可以将一个方法的调用方式变成“属性调用”。
class Employee:
@property
def salary(self):#这本来是一个方法
return 30000;
emp1 = Employee()
print(emp1.salary) #打印 30000
print(type(emp1.salary)) #打印<class 'int'>
#emp1.salary() #报错:TypeError: 'int' object is not callable
#emp1.salary =1000 #@property 修饰的属性,如果没有加 setter 方法,
# 则为只读属性。此处修改报错:AttributeError: can't setattribute
@property 主要用于帮助我们处理属性的读操作、写操作。对于某一个属性,我们可以直接通过: emp1.salary = 30000
如上的操作读操作、写操作。但是,这种做法不安全。比如,我需要限制薪水必须为 1-10000的数字。这时候,我们就需要通过 getter、setter 方法来处理。
例子:
class Employee:
def __init__(self, name, salary):
self.name = name
self.__salary = salary
@property # 相当于 salary 属性的 getter 方法
def salary(self):
print("月薪为{0},年薪为{1}".format(self.__salary,(12*self.__salary)))
return self.__salary;
@salary.setter
def salary(self, salary): # 相当于 salary 属性的 setter 方法
if (0 <salary <1000000):
self.__salary = salary
else:
print("薪水录入错误!只能在 0-1000000 之间")
emp1 = Employee("高淇",100)
print(emp1.salary)
emp1.salary = -200 #换成0-100000之间
执行结果:
月薪为100,年薪为1200
100
薪水录入错误!只能在 0-1000000 之间
属性和方法命名总结
· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访问这些成员。
· xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)
注:再次强调,方法和属性都遵循上面的规则。
类编码风格
- 类名首字母大写,多个单词之间采用驼峰原则。
- 实例名、模块名采用小写,多个单词之间采用下划线隔开。
- 每个类,应紧跟“文档字符串”,说明这个类的作用。
- 可以用空行组织代码,但不能滥用。在类中,使用一个空行隔开方法;模块中,使用两个空行隔开多个类。