类,也许是从计算机的角度去结构这个世界的唯一方式。本文是一篇入门级别的文章,是有关于Python类的基础语法特性。主要内容有:类的方法(即C/C++中的函数),类的属性(即成员变量)。
写在前面:
本文是一篇学习笔记、有一定的总结性的文章,可能只适合有相关基础的人作为复习和查漏补缺。也许不适合新手!
类的定义
以Student类为例,在Python中,定义类是通过class关键字:
class Student(object):
pass
解释:
- class后面紧接着是类名,即Student,
- 类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,
- 通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
类方法
类方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
三种类的方法
- 普通方法:由
对象
调用;至少一个self
参数;执行普通方法时,自动将调用该方法的对象
赋值给self
; - 类方法:由
类
调用; 至少一个cls
参数;执行类方法时,自动将调用该方法的类复制给cls; - 静态方法:由
类
调用;无默认参数;
三种类方法的调用:
class Foo:
def __init__(self, name):
self.name = name
def ord_func(self): # 定义普通方法,至少有一个self参数
print('普通方法')
@classmethod # 定义类方法,至少有一个cls参数
def class_func(cls):
print('类方法')
@staticmethod # 定义静态方法 ,无默认参数
def static_func():
print('静态方法')
# 调用普通方法
f = Foo()
f.ord_func()
# 调用类方法
Foo.class_func()
# 调用静态方法
Foo.static_func()
三种方法的区别:
- 相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
- 不同点:方法调用者不同、调用方法时自动传入的参数不同。
特殊的内置方法
__init__
构造函数,在生成对象时调用__del__
析构函数,释放对象时使用__str__
显示该类的实例的信息,类似于Java中Object类的toString方法- …
为了不喧宾夺主,这里这是简单介绍一下内置方法,更加详细的内置方法,后文将更加详细地介绍!
init内置方法
__init__()
:
- 类似于Java中的带参构造方法,特殊方法“init”前后分别有两个下划线!!!
- 第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
- self类似于Java中的this指针;
class Student(object): # 定义类
def __init__(self, name, score): # 定义构造方法
self.name = name
self.score = score
del内置方法
__del__()
:
理解del内置方法:
- 与 init() 方法对应的是
__del__
() 方法,__init__
() 方法用于初始化 Python 对象, - 而
__del__
() 则用于销毁 Python 对象, - 即在任何 Python 对象将要被系统回收之时,系统都会自动调用该对象的
__del__
() 方法。
当程序不再需要一个 Python 对象时,系统必须把该对象所占用的内存空间释放出来,这个过程被称为垃圾回收(GC,Garbage Collector),Python 会自动回收所有对象所占用的内存空间,因此开发者无须关心对象垃圾回收的过程。
**注意:**对一个变量执行 del 操作,该变量所引用的对象就会被回收,只有当对象的引用计数变成 0 时,该对象才会被回收。因此,如果一个对象有多个变量引用它,那么 del 其中一个变量是不会回收该对象的。
class Item:
def __init__(self, name, price):
self.name = name
self.price = price
def __del__ (self): # 定义析构函数
print('del删除对象')
im = Item('鼠标', 29.8) # 创建一个Item对象,将之赋给im变量
x = im # 打印im所引用的Item对象
del im
print('--这是最后一句Python语句--') # 只有执行最后一句,该类的对象不再被使用,才del
'''输出:
--这是最后一句Python语句--
del删除对象
'''
str内置方法
__str__()
:
类似于Java中的“toString”方法;用于输出本类的信息;
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
print(Student('Michael')) # 输出:Student object (name: Michael)
# 如果不定义"__str__",输出:<__main__.Student object at 0x109afb190>
类属性
属性的定义有两种方式:
- 装饰器,即:在方法上应用装饰器
- 静态字段,即:在类中定义值为property对象的静态字段
在哪里定义类属性:
1、直接在类中定义属性
class UserInfo(object):
name = '两点水'
2、在构造函数中定义属性
class UserInfo(object):
def __init__(self, name):
self.name = name
类变量的定义方式:
xx
:公有变量_xx
:单前置下划线,受保护的属性或方法(相当于protected),类对象和子类可以访问,from somemodule import *禁止导入__xx
:双前置下划线,私有化属性或方法(相当于private),无法在外部直接访问(名字重整所以访问不到),访问这种变量只能通过getter和setter函数来实现。__xx__
:双前后下划线,系统定义名字(不要自己发明这样的名字)xx_
:单后置下划线,用于避免与Python关键词的冲突
静态变量
有两种方式:
- 普通方式
- property方式
普通静态变量
class Province:
country = '中国' # 类的静态变量,类似于Java中的static
def __init__(self, name):
self.name = name # 普通(对象)的属性
obj = Province('河北省') # 直接访问普通属性
print(obj.name)
print(Province.country) # 直接访问静态变量
• 静态变量在内存中只保存一份
• 普通变量在每个对象中都要保存一份
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段
property的静态变量
快速理解property方法:
class Foo:
def get_bar(self):
return 'constant info'
BAR = property(get_bar) # 创建常量"BAR",把get_bar方法的返回值赋值给它;
obj = Foo()
reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
print(reuslt)
property的构造方法中有个四个参数:
- 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
- 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
- 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
- 第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息
class Foo:
def get_bar(self):
return 'wupeiqi'
def set_bar(self, value): # *必须两个参数
return
return 'set value' + value
def del_bar(self):
return 'wupeiqi'
BAR = property(get_bar, set_bar, del_bar, 'description...') # 定义一个BAR常量
obj = Foo()
obj.BAR # 自动调用第一个参数中定义的方法:get_bar
obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入
del Foo.BAR # 自动调用第三个参数中定义的方法:del_bar方法
obj.BAE.__doc__ # 自动获取第四个参数中设置的值:description...
操作静态字段
- 由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
class Goods(object):
def __init__(self):
self.original_price = 100 # 原价
self.discount = 0.8 # 折扣
def get_price(self):
new_price = self.original_price * self.discount # 实际价格 = 原价 * 折扣
return new_price
def set_price(self, value):
self.original_price = value
def del_price(self, value):
del self.original_price
PRICE = property(get_price, set_price, del_price, '价格属性描述...')
obj = Goods()
obj.PRICE # 获取商品价格
print('现在商品的价格是:',obj.PRICE)
obj.PRICE = 200 # 修改商品原价
print('修改后商品的价格是:',obj.PRICE)
#del obj.PRICE # 删除商品原价
装饰器
如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。即,通过“@property”装饰器,将一个方法变成一个变量或常量。
装饰器的类变量
class Goods:
@property
def price(self):
return 'hahha'
obj = Goods()
result = obj.price # 完全把price()方法,搞成了一个变量;如果result = obj.price() 错误!
print(result) # 输出:hahha
# print(obj.price()) # 报错:TypeError: 'str' object is not callable
属性的定义和调用要注意一下几点:
• 定义时,在普通方法的基础上添加 @property 装饰器;
• 定义时,属性仅有一个self参数
• 调用时,无需括号,即被@property装饰的方法不再是一个方法,而是一个类属性(类变量);
注意: 属性存在意义是:访问属性时可以制造出和访问字段(类变量)完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
装饰器与经典类、新式类
经典类(类名后的括号里没继承“object”):
# ############### 定义 ###############
class Goods:
@property
def price(self):
return "wupeiqi"
# ############### 调用 ###############
obj = Goods()
result = obj.price # 使得price方法变成一个变量,并获取方法的返回值
print(result)
新式类(类名后的括号里有“object”):具有三种@property装饰器
# ############### 定义 ###############
# 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
class Goods(object):
@property
def price(self):
print('@property')
@price.setter
def price(self, value):
print('@price.setter')
@price.deleter
def price(self):
print('@price.deleter')
# ############### 调用 ###############
obj = Goods()
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
核心点:
- 经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
- 新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
新式类的三个装饰
class Goods(object):
def __init__(self):
self.original_price = 100 # 原价
self.discount = 0.8 # 折扣
@property
def price(self):
new_price = self.original_price * self.discount # 实际价格 = 原价 * 折扣
return new_price
@price.setter
def price(self, value):
self.original_price = value
@price.deleter
def price(self):
del self.original_price
obj = Goods()
obj.price # 获取商品价格
print('原商品价格:',obj.price) # 输出:原商品价格: 80.0
obj.price = 200 # 修改商品原价
print('修改后商品价格:',obj.price) # 输出:修改后商品价格: 160.0
del obj.price # 删除商品原价
内置变量:name
在有些Python文件中,在最后一行常见这样的代码:
这到底是什么意思呢?
-
__name__
是一个变量。前后加了双下划线是因为这是系统定义的名字。普通变量不要使用此方式命名变量。 -
Python有很多模块,而这些模块是可以独立运行的!这点不像C++和C的头文件。
-
import的时候是要执行所import的模块的。
-
__name__
就是标识模块的名字的一个系统变量。这里分两种情况:假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__
,通过if判断这样就可以执行“__mian__
:”后面的主函数内容;假如此模块是被import的,则此模块名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__
:”后面的内容。
通过上面方式,python就可以分清楚哪些是主函数,进入主函数执行;并且可以调用其他模块的各个函数等等。
- 如果模块是被导入,
__name__
的值为模块名字 - 如果模块是被直接执行,
__name__
的值为’__main__
’