python收徒_python学习笔记_第14天(面向对象初级)

__del__方法(析构函数)和垃圾回收机制

__del__方法称为“析构方法”,用于实现对象被销毁时所需的操作。系统会自动提供__del__方法,一般不需要自定义析构方法。

Python 中当对象被变量调用时引用计数+1,当对象没有被引用时引用计数为0,由垃圾回收器自动调用__del__方法。也可以通过del 语句删除对象,从而保证调用__del__方法。

__call__方法和可调用对象

定义了__call__方法的对象,称为“可调用对象”,即该对象可以像函数一样被调用。函数通过函数名()调用函数,可调用对象和函数一样也是对象,可调用对象()可调用__call__方法,即该对象可以像函数一样被调用。

class SalaryAccount:

'''工资计算类'''

def __call__(self, salary):

yearSalary = salary * 12

daySalary = salary // 22.5

hourSalary = daySalary // 8

return dict(monthSalary=salary, yearSalary=yearSalary, daySalary=daySalary, hourSalary=hourSalary)

s = SalaryAccount()

print(s(5000)) # 可以像调用函数一样调用对象的__call__方法

方法没有重载

在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可。方法签名包含3个部分:方法名、参数数量、参数类型。

但Python 中,方法的的参数没有声明类型(调用时确定参数的类型),参数的数量也可以由可变参数控制。因此,Python 中是没有方法的重载。如果在类结构体中定义了多个重名的方法,只有最后一个方法会生效,前面的同名方法将被覆盖。

总结:不要使用重名的方法!Python 中方法没有重载。

class Person:

def say_hi(self):

print("hello")

def say_hi(self, name):

print("{0},hello".format(name))

p1 = Person()

# p1.say_hi() # 同名方法前者被覆盖,不带参时报错

p1.say_hi("python")

方法的动态性

Python 是动态语言,可以动态的为类添加新的方法,或者动态的修改类的已有的方法

# 定义Preson类

class Person:

def learning(self):

print("hello,python")

# 与类无关的函数

def play_game(one):

print("{0}玩游戏".format(one))

def learn(one):

print('{0}learn coding to print "hello,python"'.format(one))

p = Person() # 新建实例对象

Person.play = play_game # 动态语言,引用外部函数对类添加新的方法

p.play() # 内部调用原理,Person.play(p)传入的参数为实例对象

p.learning() # 未更改前的类方法

Person.learning = learn # 动态语言,用外部函数更改类的方法

p.learning() # 更改后的类方法

运行结果:

玩游戏

hello,python

learn coding to print “hello,python”

f8e51bc00138f1afc824907dc39862e0.png

私有属性和私有方法(实现对外封装)

Python 对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。关于私有属性和私有方法,有如下要点:

通常约定,两个下划线开头的属性是私有的(private),其他为公共的(public)。

类内部可以访问私有属性(方法)

类外部不能直接访问私有属性(方法)

类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)

【注】方法本质上也是属性!只不过是可以通过()执行而已。所以,此处讲的私有属性和公有属性,也适用于私有方法和公有方法。

class Students:

__subject = "python" # 私有类属性通过dir,可以查到存储格式为_Students__subject

def __init__(self, name, age):

self.name = name

self.__age = age # 私有实例属性

def say_subject(self):

print("我的正在学习:", Students.__subject) # 类内部可以直接访问私有属性

print(self.name, "的年龄是:", self.__age)

self.__work() # 类内部可以直接访问私有方法

def __work(self): # 私有实例方法通过dir,可以查到_Employee__work

print("终身学习,财务自由!")

p1 = Students("张三", 25)

print(p1.name) # 公共属性可直接调用

print(dir(p1)) # dir(obj)可以获得对象的所有属性、方法;obj.__dict__ 自定义对象字典展示

print('*' * 40)

p1.say_subject()

print('*' * 40)

print(p1._Students__age) # 通过这种方式可以直接访问到私有属性。通过dir可以查到属性:_Students__age

p1._Students__work() # 通过这种方式可以直接访问到私有方法。通过dir可以查到方法性:_Students__work

print(Students._Students__subject) # 调用类属性格式相似,类属性属于类,不属于实例

# print(p1.__age) #直接访问私有属性,报错

# p1.__work() #直接访问私有方法,报错

运行结果:

张三

[’_Students__age’, ‘_Students__subject’, ‘_Students__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’, ‘name’, ‘say_subject’]

我的正在学习: python

张三 的年龄是: 25

终身学习,财务自由!

25

终身学习,财务自由!

python

【总结】:

属性和方法命名总结:方法和属性都遵循以下规则。

· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访问这些成员。

· __xxx__:系统定义的特殊成员

· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但在类外部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)

@property 装饰器

@property 可以将一个方法的调用方式变成“属性调用”。

class Employee:

@property

def salary(self):

print("装饰器,将方法转换成属性调用")

return 30000

emp1 = Employee()

print(emp1.salary) # 在方法前添加装饰器@property,在外部调用方法时用属性方法调用,方法名后不用跟()

print('*'*40)

print(type(emp1.salary)) # ,是salary方法返回值的type

# emp1.salary =1000 # 修改报错,@property修饰的属性,在没有加setter方法的情况下,为只读属性。

运行结果:

装饰器,将方法转换成属性调用

30000

装饰器,将方法转换成属性调用

# get与set的使用

class Employee:

def __init__(self, name, salary):

self.__name = name

self.__salary = salary # 避免外部可直接对类属性读取和赋值,私有化类属性

def get_salary(self):

print("月薪为{0},年薪为{1}".format(self.__salary, (12 * self.__salary))) # 类内部可直接调用类私有属性

return self.__salary

def set_salary(self, salary): # 条件判断,避免用户端输入错误值

if (0 < salary < 50000):

self.__salary = salary

print("已成功写入")

else:

print("薪水录入错误!只能在0-50000 之间")

emp1 = Employee("张三", 5000)

print(emp1.get_salary()) # 读取

emp1.set_salary(-3000) # 写入

print(emp1.get_salary()) # 确认是否写入,写入错误时不更改属性值

运行结果:

月薪为5000,年薪为60000

5000

薪水录入错误!只能在0-50000 之间

月薪为5000,年薪为60000

5000

对于某一个公共属性,可以直接通过:类.属性 = 值,来读操作/写操作。@property 主要用于处理属性的读操作,相当于get方法;@属性.setter主要用于处理属性的写操作,相当于set方法。

class Employee:

def __init__(self, name, salary):

self.__name = name

self.__salary = salary # 避免外部可直接对类属性读取和赋值,私有化类属性

# 避免客户端对类属性输入错误值,使用 @property读取, @属性.setter 可带条件写入

@property # 相当于salary属性的getter方法

def salary(self):

print("月薪为{0},年薪为{1}".format(self.__salary, (12 * self.__salary))) # 类内部可直接调用类私有属性

return self.__salary

@salary.setter # 相当于salary属性的setter方法

def salary(self, salary): # 条件判断,避免用户端输入错误值

if (0 < salary < 50000):

self.__salary = salary

print("已成功写入")

else:

print("薪水录入错误!只能在0-50000 之间")

emp1 = Employee("李四", 6000)

print(emp1.salary) # 读取时调用,@property下方法,不用带()。

emp1.salary = 20000 # 写入时调用,@salary.setter下方法,不用带()。

print(emp1.salary) # 确认是否写入

运行结果:

月薪为6000,年薪为72000

6000

已成功写入

月薪为20000,年薪为240000

20000

未经允许不得转载:作者:1544-陈同学,

转载或复制请以 超链接形式 并注明出处 拜师资源博客。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值