Python快速入门学习笔记:第四天

本文深入探讨Python面向对象编程的基础知识,包括类定义、类方法、静态方法、私有化、装饰器及其实现原理。通过实例演示如何在Python中创建类、实例化对象、调用方法和属性,以及如何利用装饰器实现方法调用的属性化。

这个是为准备考研复试,希望做一个textCNN文本情感分析打语言基础的自学笔记,博主本身本科非计算机专业,如果网友们有幸看见本文,博客中内容如有疏漏,不吝赐教。

第6节 类

6.1 类定义

  和之前所学习的面向对象的语言一样,Python也提供类的概念,同样适用关键字class定义一个类,一个类可以拥有一个对象的属性和方法。具体代码示例如下:

class Student:

    age = 18 # 类属性
	# 构造器初始化对象
    def __init__(self, name, score):
        # self必须为第一个参数
        # Python中的self类似于C++中的self指针,Java中的this关键字
        self.name = name
        self.score = score

    def print_score(self):
        # self必须为第一个参数
        print("{0}的分数是:{1}".format(self.name, self.score))

在调用实例方法时,不需要也不能给self传参,由解释器自动传参。在调用时,同样通过类名调用构造函数。如:

s1 = Student("Li Ming", 18)
s1.print_score()

同时,除了可以在类中定义某个类属性,还可以在类的外部临时加入某个属性,例如:对上面的Student类临时加入一个salary属性

s1.salary = 5000
print(s1.salary) # 此类属性为临时加入,仅仅是被实例化后的s1有此属性。

同时也可以使用dir()函数来查看本类的一切方法,使用__dict__来查看对象属性字典,使用isinstance()判断是否为实例化对象:

print(dir(s1))  # dir可获得对象的所有方法
print(s1.__dict__) # 获得对象的属性字典
print(isinstance(s1, Student)) # 判读是否为实例化对象

6.2 类方法与静态方法

  类方法是从属于类对象的方法,通过装饰器@classmethod定义,具体格式如:

class class_name:
		@classmethod
        def obj_name(cls, [ ,list]):
            ... 
           # code_block
            ...

要点在于:

  • @classmethod必须位于方法名上面;
  • 第一个cls必须有
  • 调用类方法的格式:obj_name.method_name(para_list_name)
  • 参数列表无需,也不能给cls传值
  • 类方法中访问实例属性和实例方法会导致错误
  • 子类继承父类时,传入的是子类的方法而不是父类
  • 实例方法操作实例属性,类方法操作类属性
    在这里插入图片描述
    关键点在于,实例方法存在了一个隐藏参数self,类方法存在一个隐藏参数cls,而静态方法两者皆无。。那么我们可以推出一个逻辑:实例方法被实例调用,类方法被类调用,静态方法两者皆可调用。
class mode_class:

    company = 'ByteDance'

    def normalMethod(self, company):
        print(self.company)

    @classmethod
    def classMethod(cls, company):
        print(cls.company)

    @staticmethod
    def staticMethod(company):
        print(company)


my_class = mode_class()
my_class.company = "New"
print(my_class.normalMethod("Normal"))	
# print(mode_class.normalMethod("Class"))     # Error
print(my_class.classMethod("Normal"))
print(mode_class.classMethod("Class"))
print(my_class.staticMethod("Normal")) # 输出方法内部分
print(mode_class.staticMethod("Class"))# 输出方法内部分

最后的输出结果是:

New
None
ByteDance
None
ByteDance
None
Normal
None
Class
None

最后需要注意的是,实例方法和静态方法调用的区别。
总结来讲是:

  • 实例方法随着实例化的属性改变而变,如新定义的new覆盖了原来类中的ByteDance
  • 类方法,使用了类属性的内容不会随着实例属性改变
  • 静态方法不可访问类属性,直接传入新加入方法中的内容。
  • 不想看见报错,就别用类调用实例方法。

6.3 __ del __与__call __

   __del__方法称为析构方法,用于实现对象被销毁时所需要的操作,如:释放占用的资源。Python实现自动的垃圾回收,当对象没有被引用时,由垃圾回收器调用此方法。我们也可以使用del语句从而保证调用了__del__方法。系统也会自动提供__del__方法,一般不需要自定义析构方法。

class Person:
    def __del__(self):
        # 重写一个假的del方法
        print("销毁对象:{0}".format(self))


p1 = Person()
p2 = Person()
del p2
print("程序结束") # 自行调用了del方法,销毁p1

  定义了__call__方法的对象,被称为“可调用对象”,也就是说:有此方法的对象可以被像函数一样调用,其使用方式可以像函数一样。

class SalaryAccount:
    # 工资计算类
    def __call__(self, salary):
        print("Accounting")
        yearSalary =salary*12
        daySalary = salary//22.5
        hourSalary = daySalary//8
        return dict(yearSalary=yearSalary, daySalary=daySalary, hourSalary=hourSalary)


s = SalaryAccount()
print(s(5000))

可以看见,被定义的SalaryAccount类在实例化一个s对象之后,s对象可以像函数一样向其中传参。

6.4 方法重载与动态性

Python中没有方法的重载,新定义的方法会将上一个同名方法覆盖

class Person:
    def say_hi(self):
        print("Hello!")

    def say_hi(self, name): # 将上一个覆盖
        print("{0},hellow!".format(name))


p1 = Person()
# p1.say_hi()  此句error
p1.say_hi("Li")
# 输出:Li,hellow!

可见在Python中的方法并不需要重载,也无法重载。

  但是,python是一个解释性语言,也在动态中执行。类属性一样,类属性可以临时性的新加入进某个实例化的对象中,成为实例化对象的一个新属性。

class Person:

    def say_hi(self):
        print("Hello!")


def new_action(s):
    print("New{0}".format(s))


Person.new_a = new_action # 先加入到类中
p1 = Person()
p1.say_hi()
p1.new_a()

不过与临时加入类属性不同的是,这样动态加入的方法必须要先加入到类中,而不是直接像类属性那样直接声明。另外,函数也是对象,实际上是new_action这个“对象”把地址给了Person类中的new_a。

甚至,可以新定义一个方法来覆盖掉原本类中的方法:

class Person:

    def say_hi(self):
        print("Hello!")


def new_say_hi(s):
    print("Hellow!")


p = Person()
Person.say_hi = new_say_hi # 尝试覆盖原本say_hi
p.say_hi()

但是注意到一个问题:为什么我必须在新定义的方法参数列表中放一个s做参数呢,当我把它去掉时,将会有下面报错:

TypeError: new_say_hi() takes 0 positional arguments but 1 was given

也就是说,解释器不需要我为这个方法提供参数但是提供了一个。Python在类中定义方法的时候,方法会被传当前对象的地址,所以一般在类中定义方法的时候,必须在方法中至少定义一个参数,将其命名为"self"。但是实例方法的第一个参数可以叫任意参数名。

也是就是说:我们完全可以在实例方法中任意定义一个变量来顶替原本需要的self

6.4 私有化

和其他语言不一样的是,Python对于类成员没有严格访问控制,关于私有属性和私有方法有具体如下要求:

  • 通常约定,双下划线开头为私有的,其他为公共的
  • 类内部可访问私有属性和方法
  • 类外部不能直接访问私有属性和方法
class Employee:

    __company = "OK!"

    def __init__(self, name, age):
        self.name = name
        self.__age = age    # 私有化属性

    def __work(self):
        print("private")
        print("年龄:{0}".format(self.__age))  # 一定要加双下划线
        print(Employee.__company)


e = Employee("LI", 18)
print(e.name)
# print(e.age)    # 不可访问
print(e._Employee__age)
# 可访问
print(dir(e))
# e.__work() # 不可访问
e._Employee__work()

如果要完善封装的思想,可以利用像java中的get和set方法。

class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def get_name(self):
        return self.__name

    def set_name(self, name):
        self.__name = name

    def get_age(self):
        return self.__age

    def set_age(self, age):
        self.__age = age


stu = Student("Ada", 18)
print(stu.get_name())
stu.set_age(24)
print(stu.get_age())

6.5 装饰器@property

@property可以把一个方法调用变为属性调用:类方法——>类属性

class Number:

    @property
    def trans_num(self):
        return 10
    
num = Number()
print(num.trans_num)
# print(num.trans_num())  传统的方法调用方式将会报错
print(type(num.trans_num)) 

输出结果为:

10
<class 'int'>

等效于get和set方法的代码可以写成

class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def studentName(self):
        return self.__name

    @studentName.setter  # 方法名.setter
    def studentName(self, name):
        self.__name = name

    @property
    def studentAge(self):
        return self.__age

    @studentAge.setter	# 方法名.setter
    def studentAge(self, age):
        self.__age = age


stu = Student("Ada", 18)
print(stu.studentName)
print(stu.studentAge)

stu.studentName = "Alice"
stu.studentAge = 24

但也有不一样的是,setter修饰的方法不能放在被修饰的方法名前面,比如:

	# 这样做是不允许的
    @studentAge.setter	# 方法名.setter
    def studentAge(self, age):
        self.__age = age
    @property
    def studentAge(self):
        return self.__age

这个问题等以后深入Python学习的时候再继续追究。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值