Python进阶
面向对象编程
面向对象编程——Object Oriented Programming,简称 OOP,是一种程序设计思想。OOP 把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
在 Python 中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。
面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。Class 是一种抽象概念,比如我们定义的 Class——Student,是 指学生这个概念,而实例(Instance)则是一个个具体的 Student,比如,张三和李四是两个具体的 Student。
所以,面向对象的设计思想是抽象出 Class,根据 Class 创建 Instance。
面向对象的抽象程度又比函数要高,因为一个 Class 既包含数据,又包含操作数据的方法。
创建类
类的特殊方法
Python 使用 __ 开头的名字来定义特殊的方法和属性,它们有:
__init__()
__repr__()
__str__()
__call__()
__iter__()
__add__()
__sub__()
__mul__()
__rmul__()
__class__
__name__
构造方法 __init__()
在产生对象之后,我们可以向对象中添加属性。 事实上,还可以通过构造方法,在构造对象的时候直接添加属性:
class Clothes(object):
"""
init_demo
"""
def __init__(self, color="green"):
self.color = color
my_clothes = Clothes()
my_clothes.color
传入有参数的值:
your_clothes = Clothes('orange')
your_clothes.color
表示方法 __repr__() 和 __str__()
:
class Clothes(object):
"""
repr and str demo
"""
def __init__(self, color="green"):
self.color = color
def __str__(self):
"This is a string to print."
return ("a {} clothes".format(self.color))
def __repr__(self):
"This string recreates the object."
return ("{}(color='{}')".format(self.__class__.__name__, self.color))
__str__()
是使用 print 函数显示的结果,类似 java 中的 toString:
my_clothes = Clothes()
print(my_clothes)
__repr__()
返回的是不使用 print 方法的结果:
my_clothes
print(my_clothes.__class__, my_clothes.__class__.__name__, my_clothes.color)
my_clothes.__class__, my_clothes.__class__.__name__, my_clothes.color
类的属性
只读属性:
class Clothes(object):
def __init__(self, price):
self.price = price
# 这样 discount_price 就变成属性了
@property
def discount_price(self):
return self.price * 0.8
这里 discount_price 就是一个只读不写的属性了(注意是属性不是方法), 而 price 是可读写的属性:
my_clothes = Clothes(100)
print(my_clothes.discount_price) # 80.0
可以修改 price 属性来改变 discount_price:
my_clothes.price = 200
print(my_clothes.discount_price) # 160.0
my_clothes.discount_price()会报错,因为 my_clothes.discount_price 是属性,不是方法;
my_clothes.discount_price=100 也会报错,因为只读。
对于 @property 生成的只读属性,我们可以使用相应的 @attr.setter 修饰符来使得这个属性变成可写的:
class Clothes(object):
def __init__(self, price):
self.price = price
# 这样就变成属性了
@property
def discount_price(self):
return self.price * 0.8
@discount_price.setter
def discount_price(self, new_price):
self.price = new_price * 1.25
测试一下:
my_clothes = Clothes(100)
print(my_clothes.discount_price)
my_clothes.price = 200
print(my_clothes.discount_price)
修改 discount_price 属性:
my_clothes.discount_price = 180
print(my_clothes.price)
print(my_clothes.discount_price)
一个等价的替代如下,用方法:
class Clothes(object):
def __init__(self, price):
self.price = price
def get_discount_price(self):
return self.price * 0.8
def set_discount_price(self, new_price):
self.price = new_price * 1.25
discount_price = property(get_discount_price, set_discount_price)
my_clothes = Clothes(100)
print(my_clothes.discount_price)
my_clothes.price = 200
print(my_clothes.discount_price)
my_clothes.discount_price = 180
print(my_clothes.price)
print(my_clothes.discount_price)
继承
类定义的基本形式:
class ClassName(ParentClass):
"""class docstring"""
def method(self):
return
里面的 ParentClass 就是用来继承的。
class Clothes(object):
def __init__(self, color="green"):
self.color = color
def out_print(self):
return self.__class__.__name__, self.color
my_clothes = Clothes()
my_clothes.color
my_clothes.out_print()
定义一个子类,继承父类的所有方法:
class NikeClothes(Clothes):
def change_color(self):
if self.color == "green":
self.color = "red"
继承父类的所有方法:
your_clothes = NikeClothes()
your_clothes.color
your_clothes.out_print()
但有自己的方法:
your_clothes.change_color()
your_clothes.color
如果想对父类的方法进行修改,只需要在子类中重定义这个类即可:
class AdidasClothes(Clothes):
def change_color(self):
if self.color == "green":
self.color = "black"
def out_print(self):
self.change_color()
return self.__class__.__name__, self.color
him_clothes = AdidasClothes()
print(him_clothes.color)
him_clothes.change_color()
print(him_clothes.color)
print(him_clothes.out_print())
super() 函数
super(CurrentClassName, instance)
返回该类实例对应的父类对象。
刚才 AdidasClothes 可以改写为:
class NewAdidasClothes(Clothes):
def change_color(self):
if self.color == "green":
self.color = "black"
def out_print(self):
self.change_color()
print(super(NewAdidasClothes, self).out_print())
her_clothes = NewAdidasClothes()
print(her_clothes.color)
her_clothes.out_print()
new() 方法
new()用来创建一个实例,它至少有一个参数 cls,代表当前类。默认情况下new()会创建当前类的实例,该方法也可以被重载,重载后也可以创建其他类的实例。
class Fun(object):
def __init__(self, fun):
self.fun = fun
def __new__(cls, *args, **kwargs):
return object.__new__(Fun)
if __name__ == '__main__':
f = Fun.__new__(Fun)
print(type(f))
new()方法只是创建实例,此时拿到的实例并不能正常使用。一个实例需要被init()方法初始化后才可以被正常使用。也就是说,正常场景下,我们生成一个类的实例,Python 先调用该类的new()**方法创建一个实例,然后再调用init**()方法初始化该实例。**new()**方法存在于 object 方法中,通常情况下不需要被重载。
可以使用new方法创建出其它类的实例。在这种场景下,new方法创建后会调用对应类的init方法完成初始化:
class Fun(object):
def __init__(self, fun):
self.fun = fun
def __new__(cls, *args, **kwargs):
return Demo(*args, **kwargs)
class Demo(object):
def __init__(self, d):
self.demo = d
if __name__ == '__main__':
f = Fun(1)
print("type f:", type(f))
print("f.demo:", f.demo)
可以看出,f 不是 Fun 类的一个实例,而是 Demo 类的一个实例,拥有 Demo 类的字段。因为 Fun 类的new方法创建的是一个 Demo 类实例,而非 Fun 类本身。因此 Fun.new方法在 return 后调用了 Demo.init方法,以完成该实例的初始化。
接口
接口的调用:
class Clothes(object):
def __init__(self, color="green"):
self.color = color
def out(self):
print("father.")
class NikeClothes(Clothes):
def out(self):
self.color = "brown"
super(NikeClothes, self).out()
class AdidasClothes(object):
def out(self):
print("adidas.")
因为三个类都实现了 out() 方法,因此可以这样使用:
objects = [Clothes(), NikeClothes(), AdidasClothes()]
for obj in objects:
obj.out()
类方法
类方法包括以下几种:
- special 方法和属性,即以 __ 开头和结尾的方法和属性
- 私有方法和属性,以 _ 开头,不过不是真正私有,而是可以调用的, 但是不会被代码自动完成所记录(即 Tab 键之后不会显示)
- 共有的方法和属性
以 __
开头不以 __
结尾的属性是更加特殊的方法,调用方式也不同:
class MyDemoClass(object):
def __init__(self):
print("special.")
def _get_name(self):
print("_get_name is private method.")
def get_value(self):
print("get_value is public method.")
def __get_type(self):
print("__get_type is really special method.")
demo = MyDemoClass()
demo.get_value()
demo._get_name()
demo._MyDemoClass__get_type()
文件
写文件
我们使用 open 函数的写入模式来写文件:
f = open('test.txt', 'w')
f.write('hello world.')
f.close()
print(open('test.txt').read())
使用 w 模式时,如果文件不存在会被创建
除了写入模式,还有追加模式 a
读写模式 w+
f = open('test.txt', 'w+')
f.write('hello world. morning.')
f.seek(3)
print(f.read()) # hello world.
f.close()
读文件
使用 open 函数 来读文件,使用文件名的字符串作为输入参数:
默认打开文件是 ‘r’ 读模 式
f = open("test.txt")
# 默认以读的方式打开文件,如果文件不存在会报错。
# 可以使用 read 方法来读入文件中的所有内容:
text = f.read()
print(text)
按照行读入内容,readlines 方法返回一个列表,每个元素代表文件中每一行的内容:
f = open("test.txt")
lines = f.readlines()
print(lines)
f.close()
# 事实上,我们可以将 f 放在一个循环中,得到它每一行的内容:
f = open('test.txt')
for line in f:
print(line)
f.close()