单继承init和多继承init
单继承init
以下两种写法基本无差别:
- super().init(name)
- Parent.init(self, name),其中Parent是父类名
```python
class Parent:
def init(self, name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son(Parent): def init(self, name, age): print(‘Son的init开始被调用’)
# Parent.__init__(self, name)
super().__init__(name)
self.age = age
print('Son的init结束被调用')
if name == ‘main‘: son = Son(‘Alan’, 28) print(son.name)
‘’’ 输出: Son的init开始被调用 parent的init开始被调用 parent的init结束被调用 Son的init结束被调用 Alan ‘’’
<a name="ZZxhU"></a>
### 多继承__init__
- super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致父类的方法执行多次,所以应尽量避免使用类名的方法调用
- 多继承时,使用super方法对父类传参数,必须把参数全部传递,否则会报错
- 多继承时,使用类名.__init__方法,要把每个父类全部写一遍。而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何使用super方法需要全部传参的一个原因
```python
class Parent:
def __init__(self, name, *args, **kwargs):
# 为避免多继承报错,使用不定长参数接受参数
print('parent的init开始被调用')
self.name = name # 初始化name属性
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs):
print('Son1的init开始被调用')
self.age = age # 初始化age属性
super().__init__(name, *args, **kwargs)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs):
print('Son2的init开始被调用')
self.gender = gender # 初始化gender属性
super().__init__(name, *args, **kwargs)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
super().__init__(name, age, gender)
print('Grandson的init结束被调用')
if __name__ == '__main__':
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
'''
输出:
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
'''
class Parent(object):
def __init__(self, name):
print('parent的init开始被调用')
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
print('Son1的init开始被调用')
self.age = age
Parent.__init__(self, name)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender):
print('Son2的init开始被调用')
self.gender = gender
Parent.__init__(self, name)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
print('Grandson的init开始被调用')
Son1.__init__(self, name, age)
Son2.__init__(self, name, gender)
print('Grandson的init结束被调用')
if __name__ == '__main__':
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
'''
输出:
Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
'''
两道例题
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x) # 1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x) # 3 2 3
解释:
- 在Python中,如果一个变量的名字在当前类中没有找到,将搜索父类直到变量名被找到,如果都没有找到,则报AttributeError异常
- 如果它的某个子类重写了该值,该值仅仅在当前子类中被改变,不会影响父类 ```python class Parent(object): x = 1
class Child1(Parent): pass
class Child2(Parent): pass
c1 = Child1() c2 = Child2() p = Parent() print(c1.x, c2.x, p.x) # 1 1 1 c1.x = 2 print(c1.x, c2.x, p.x) # 2 1 1 p.x = 3 print(c1.x, c2.x, p.x) # 2 1 3
解释:各实例的变量之间没有关系
<a name="YRpQA"></a>
## property属性
- property属性是一种用起来像是使用实例属性一样的特殊属性,可以对应于某个方法
- 作用:property属性内部进行一系列的逻辑计算,最终将计算结果返回
- property属性的两种方式
- 装饰器:在方法上应用装饰器
- 类属性:在类中定义值为property对象的类属性
<a name="APW1m"></a>
### 装饰器方式
- 定义时,在实例方法的基础上添加@property装饰器,并且仅有一个self参数。调用时,无需括号
- 属性有三种访问方式,分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法,可以分别将这三个方法定义为对同一个属性的获取、修改、删除
- 简单举例
![image.png](https://cdn.nlark.com/yuque/0/2022/png/12692524/1655987549882-3cd1c9d2-30cf-4c20-8ae4-663c2bb0ead1.png#clientId=u0fe7b0c8-3b9a-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=147&id=axJU2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=221&originWidth=194&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7008&status=done&style=none&taskId=u9ce5aff1-2c6a-4b27-abd8-d6fe953f19a&title=&width=129.33333333333334)
```python
class Goods:
def __init__(self):
self.original_price = 100
@property
def price(self):
print('@property')
return self.original_price
@price.setter
def price(self, value):
print('@price.setter')
self.original_price = value
@price.deleter
def price(self):
print('@price.deleter')
del self.original_price
if __name__ == '__main__':
gas = Goods()
print(gas.price)
gas.price = 200
print(gas.price)
del gas.price
# print(gas.price) # 会报错
'''
输出:
@property
100
@price.setter
@property
200
@price.deleter
'''
类属性方式
- property方法中有四个参数
- 第一个参数是方法名,调用 对象.属性 时自动触发执行该方法
- 第二个参数是方法名,调用 对象.属性 = xxx 时自动触发执行该方法
- 第三个参数是方法名,调用 del 对象.属性 时自动触发执行该方法
- 第四个参数是字符串,是该属性的描述信息,调用 对象.属性.doc时返回该字符串
- 简单举例
class Goods:
def __init__(self):
self.original_price = 100
def get_price(self):
print('@property')
return self.original_price
def set_price(self, value):
print('@price.setter')
self.original_price = value
def del_price(self):
print('@price.deleter')
del self.original_price
price = property(get_price, set_price, del_price, '价格属性描述')
if __name__ == '__main__':
gas = Goods()
print(gas.price)
gas.price = 200
print(gas.price)
print(Goods.price.__doc__)
del gas.price
'''
输出:
@property
100
@price.setter
@property
200
价格属性描述
@price.deleter
'''
应用:为私有属性添加getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0
def get_monet(self):
return self.__money
def set_money(self, value):
if isinstance(value, int):
self.__money = value
else:
print('error: 不是整型数字')
class Money(object):
def __init__(self):
self.__money = 0
@property
def money(self):
return self.__money
@money.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print('error: 不是整型数字')
m = Money()
print(m.money)
m.money = 100
print(m.money)
class Money(object):
def __init__(self):
self.__money = 0
def get_money(self):
return self.__money
def set_money(self, value):
if isinstance(value, int):
self.__money = value
else:
print('error: 不是整型数字')
money = property(get_money, set_money)
m = Money()
print(m.money)
m.money = 100
print(m.money)
魔法属性
- doc:显示类或方法的描述信息
- module:显示当前操作的对象在哪个模块
- class:显示当前操作的对象属于哪个类
- dict:显示类或对象中的所有属性
- init:初始化方法,动过类创建对象时,自动触发执行
- del:当对象在内存中被释放时,自动触发执行,一般无须定义
- call:对象后面加括号时,自动触发执行
- 当 对象 = 类名() 时,自动触发执行init方法
- 当 对象名() 或者 类名()() 时,自动触发执行call方法
str:如果一个类中定义了str方法,那么在打印对象时,默认输出该方法的返回值
with语句
基本介绍
with语句用于异常处理,封装了try…except…finally编码范式,提高了易用性
- with语句使代码更清晰、更具易读性,它简化了文件流等公共资源的管理
- 举例
实现上下文管理器
- with语句的实现建立在上下文管理器之上,上下文管理器是一个实现enter和exit方法的类,任何实现了这两个方法的对象都可以称为上下文管理器,上下文管理器可以使用with语句
with语句的执行细节:首先调用enter方法,然后执行with语句中的代码,最后调用exit方法 ```python class MyOpen: def init(self, file_name, open_mode):
self.file_name = file_name self.open_mode = open_mode
def enter(self):
self.f = open(self.file_name, self.open_mode, encoding='utf8') return self.f
def exit(self, exc_type, exc_val, exc_tb):
print('I will exit') self.f.close()
with MyOpen(‘outpout.txt’, ‘w’) as f: f.write(‘坚持练习,就是捷径’)
<a name="fEfCA"></a>
### 实现上下文管理器的简便方式
Python提供了一个contextmanager的装饰器,进一步简化了上下文管理器的实现。通过yield将函数分割成两部分,yield之前的语句在__enter__方法中执行,yield之后的语句在__exit__方法中执行,紧跟在yield后面的值是函数的返回值
```python
from contextlib import contextmanager
@contextmanager
def my_open(file_name, open_mode):
file = open(file_name, open_mode, encoding='utf8')
yield file
print('I will exit')
file.close()
with my_open('output.txt', 'w') as f:
f.write('坚持练习,就是捷径')