这个是为准备考研复试,希望做一个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学习的时候再继续追究。
本文深入探讨Python面向对象编程的基础知识,包括类定义、类方法、静态方法、私有化、装饰器及其实现原理。通过实例演示如何在Python中创建类、实例化对象、调用方法和属性,以及如何利用装饰器实现方法调用的属性化。
7002

被折叠的 条评论
为什么被折叠?



