类的数据属性
class Student:
school = "AAA"
count = 0
def __init__(self, name, age, gender):
# 给类
Student.count += 1 # 给类本身+1,才可以在实例化时都+1
# self.count+=1 # 这里不能给单独的对象+1,会统计不到所有的实例
self.name = name
self.age = age
self.gender = gender
obj1 = Student("x", "z", 'a')
obj2 = Student('1', '2', '3')
obj3 = Student('k1', 'k2', 'k3')
obj1.count += 1 # 单独给obj1对象多加了个1
# 注意答案不是1,2,3 因为是实例化完了之后在count的
print(obj1.count) # 3
print(obj2.count) # 3
print(obj3.count) # 3
封装
一、隐藏属性怎么用?
隐藏数据属性
class Student:
# 对age属性进行隐藏
def __init__(self, name, age, gender):
self.name = name
self.__age = age
self.gender = gender
# 对外提供访问的接口
def set_age(self, age):
# 可以增加对隐藏属性修改的限制条件
if not isinstance(age, int):
raise TypeError("必须是int类型")
return age
obj = Student('s', 'we', 'w')
res = obj.set_age('23')
print(res)
隐藏函数属性
class ATM:
def __card(self): #插卡
print('插卡')
def __auth(self): #身份认证
print('用户认证')
def __input(self): #输入金额
print('输入取款金额')
def __print_bill(self): #打印小票
print('打印账单')
def __take_money(self): #取钱
print('取款')
def withdraw(self): #取款功能
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
obj=ATM()
obj.withdraw() # 取款功能分了好多小步骤,但是不想让用户知道,但又要用时,可以隐藏
二、property、setter、deleter
案例一
class People:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
@property # bmi=property(bmi)
def bmi(self):
return self.weight / (self.height) ** 2
obj = People('li', 75, 1.85)
# 没有装饰器property时,bmi为功能属性,需要加括号调用
print(obj.bmi())
# 有装饰器时,把功能属性作为数据属性调用,不需要加括号
print(obj.bmi)
案例二
class People:
def __init__(self, name):
# 当前name作为了隐藏属性,需要开放使用接口
self.__name = name
def get_name(self):
"""查看名字"""
return self.__name
def set_name(self, val):
"""修改名字"""
if isinstance(val, str):
self.__name = val
def del_name(self):
"""删除名字"""
print("该属性不可删除")
name = property(get_name, set_name, del_name)
obj = People('AAA')
# 不加装饰器的用法
print(obj.get_name())
obj.set_name('BBB')
print(obj.get_name())
obj.del_name()
print("="*10)
# 加装饰器后的用法
print(obj.name) # 相当于直接调用name里的get_name方法
obj.name = "CCC" # 相当于直接调用name里的set_name方法
print(obj.name)
del obj.name # 相当于直接调用name里的del_name方法
案例三
案例三为案例二的改进写法
- 希望属性不被随意修改:设置隐藏属性
修改该属性的一系列功能接口(功能名字一样) ```python class People: def init(self, name):
# 当前name作为了隐藏属性,需要开放使用接口
self.__name = name
@property #name123=property(name123) def name123(self):
"""查看名字"""
return self.__name
@name123.setter def name123(self, val):
"""修改名字"""
if isinstance(val, str):
self.__name = val
@name123.deleter def name123(self):
"""删除名字"""
print("该属性不可删除")
obj = People(‘AAA’)
加装饰器后的用法
print(obj.name123) # 相当于直接调用name里的get_name方法 obj.name123 = “CCC” # 相当于直接调用name里的set_name方法 print(obj.name123) del obj.name123 # 相当于直接调用name里的del_name方法
调用时写name123方便理解和区分
<a name="IkEKY"></a>
# 继承
<a name="CURd6"></a>
## 继承小案例
```python
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(People):
# 有3个共同的属性,2个特有的属性
def __init__(self, name, age, gender, weight, height):
People.__init__(self, name, age, gender)
# super().__init__(name, age, gender)
self.weight = weight
self.height = height
obj = Student('wy', 18, 'female', 123, 110)
单继承下的属性查找
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1() # 问题:若想使得这里的f1得到的是Foo.f1应该如何修改??
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj = Bar()
obj.f2()
"""
输出结果:
Foo.f2 # 首先因为obj对象的类Bar中没有f2,所以来Bar的父类中查找f2了
Bar.f1 # 因为self表示的对象是obj,是Bar创建的,而且Bar中有f1。
因此是Bar.f1而不是Foo.f1
"""
答案
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
Foo.f1(self) # 答案:直接使用类来调用,注意此时self也要作为参数传入
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj = Bar()
obj.f2()
class Foo:
def __f1(self): #_Foo__f1
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.__f1() # 答案:隐藏属性,只有类内部可以使用,并且名字发生了变形
class Bar(Foo):
def __f1(self): #_Bar__f1
print('Bar.f1')
obj = Bar()
obj.f2()
class Foo:
@classmethod
def f1(cls):
print('Foo.f1')
def f2(self):
print('Foo.f2')
Foo.f1() # 自动传入Foo为cls
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj = Bar()
obj.f2()
@classmethod和@staticmethod
最开始:使用对象和类来调用类方法的区别 ```python class People: def init(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def add(self, x, y):
return x + y
obj = People(‘wy’, 18, ‘famela’)
print(People.add(obj, 1, 2)) # 使用类去访问功能属性 print(obj.add(1, 2)) # 使用实例化的对象去访问功能属性
“””
- 绑定方法的特殊之处在于:谁调用方法就会将谁作为方法的第一个参数
类的功能属性是绑定给对象用的,所以对象调用时不需要自己传入第一个参数self, 但是类自己调用时需要传入self “””
self.name = name
self.age = age
self.gender = gender
@classmethod # add=classmethod(add) 只绑定给类用 def add(cls, x, y):
return x + y
obj = People(‘wy’, 18, ‘famela’) print(People.add(1, 2)) # 使用类去访问功能属性 “”” 给add添加了@classmethod装饰器后,add就变成了类的绑定方法 也就是说,只有类可以调用,并且此时第一个参数cls就是People本身 “””
```python
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
@staticmethod # 作为静态方法在类内定义
def add(x, y): # 即不需要绑定给类也不需要绑定给对象
return x + y
obj = People('wy', 18, 'famela')
# 类和对象都可调用
print(People.add(1, 2)) # 3
print(obj.add(3, 4)) # 7
反射
python是动态语言,而反射(reflection)机制被视为动态语言的关键。
反射机制指的是在程序的运行状态中
对于任意一个类,都可以知道这个类的所有属性和方法;
对于任意一个对象,都能够调用他的任意方法和属性。
这种动态获取程序信息以及动态调用对象的功能称为反射机制
hasattr, getattr, setattr, delattr
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
obj = People('wy', 18, 'famela')
print(dir(obj)) # 打印所有的属性
# 使用字符串去操作属性
print(hasattr(obj, 'name')) # 查看属性是否存在
print(getattr(obj, 'name')) # 查看当前属性值
setattr(obj, 'name', 'new_name') # 修改属性值
print(getattr(obj, 'name')) # 查看修改后的属性值
delattr(obj, 'name') # 删除'name'属性
print(dir(obj)) # 再查看属性已经没有了'name'
str, del
__str__
:会在对象被打印时自动触发,print功能打印的就是它的返回值,另外该方法需要返回字符串类型__del__
:会在对象被删除时自动触发。但是python有自动的垃圾回收机制,因此几乎不用 ```python class People: def init(self, name, age):self.name = name
self.age = age
def str(self):
return '打印对象时自动触发' # 返回类型必须是字符串
obj = People(‘lili’, 18) print(obj) # obj.str
<a name="U1YXN"></a>
# class关键字的机制分析
XXXXXXX
<a name="HJT0J"></a>
# 异常处理
```python
try:
代码块
except 异常信息1 as e:
异常1后输出的内容
except 异常信息2 as e:
异常2后输出的内容
...
else:
以上异常均不是时,输出的内容
finally:
无论代码块有无异常,均会输出的内容
# 多个异常处理可以写在一起
except (异常信息1,异常信息2) as e: