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()  # 更改后的类方法

运行结果:
<main.Person object at 0x0000016B7B92D3C8>玩游戏
hello,python
<main.Person object at 0x0000016B7B92D3C8>learn coding to print “hello,python”
在这里插入图片描述

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

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

  1. 通常约定,两个下划线"__"开头的属性是私有的(private),其他为公共的(public)。
  2. 类内部可以访问私有属性(方法)
  3. 类外部不能直接访问私有属性(方法)
  4. 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
    【注】方法本质上也是属性!只不过是可以通过()执行而已。所以,此处讲的私有属性和公有属性,也适用于私有方法和公有方法。
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))  # <class 'int'>,是salary方法返回值的type
# emp1.salary =1000  # 修改报错,@property修饰的属性,在没有加setter方法的情况下,为只读属性。

运行结果:
装饰器,将方法转换成属性调用
30000


装饰器,将方法转换成属性调用
<class ‘int’>

# 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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页