类的数据属性
class Student:school = "AAA"count = 0def __init__(self, name, age, gender):# 给类Student.count += 1 # 给类本身+1,才可以在实例化时都+1# self.count+=1 # 这里不能给单独的对象+1,会统计不到所有的实例self.name = nameself.age = ageself.gender = genderobj1 = 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) # 3print(obj2.count) # 3print(obj3.count) # 3
封装
一、隐藏属性怎么用?
隐藏数据属性
class Student:# 对age属性进行隐藏def __init__(self, name, age, gender):self.name = nameself.__age = ageself.gender = gender# 对外提供访问的接口def set_age(self, age):# 可以增加对隐藏属性修改的限制条件if not isinstance(age, int):raise TypeError("必须是int类型")return ageobj = 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 = nameself.weight = weightself.height = height@property # bmi=property(bmi)def bmi(self):return self.weight / (self.height) ** 2obj = People('li', 75, 1.85)# 没有装饰器property时,bmi为功能属性,需要加括号调用print(obj.bmi())# 有装饰器时,把功能属性作为数据属性调用,不需要加括号print(obj.bmi)
案例二
class People:def __init__(self, name):# 当前name作为了隐藏属性,需要开放使用接口self.__name = namedef get_name(self):"""查看名字"""return self.__namedef set_name(self, val):"""修改名字"""if isinstance(val, str):self.__name = valdef 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>## 继承小案例```pythonclass People:def __init__(self, name, age, gender):self.name = nameself.age = ageself.gender = genderclass 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 = weightself.height = heightobj = 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__f1print('Foo.f1')def f2(self):print('Foo.f2')self.__f1() # 答案:隐藏属性,只有类内部可以使用,并且名字发生了变形class Bar(Foo):def __f1(self): #_Bar__f1print('Bar.f1')obj = Bar()obj.f2()
class Foo:@classmethoddef f1(cls):print('Foo.f1')def f2(self):print('Foo.f2')Foo.f1() # 自动传入Foo为clsclass 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 = nameself.age = ageself.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 “””
python class People: def init(self, name, age, gender):self.name = nameself.age = ageself.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本身 “””
```pythonclass People:def __init__(self, name, age, gender):self.name = nameself.age = ageself.gender = gender@staticmethod # 作为静态方法在类内定义def add(x, y): # 即不需要绑定给类也不需要绑定给对象return x + yobj = People('wy', 18, 'famela')# 类和对象都可调用print(People.add(1, 2)) # 3print(obj.add(3, 4)) # 7
反射
python是动态语言,而反射(reflection)机制被视为动态语言的关键。
反射机制指的是在程序的运行状态中
对于任意一个类,都可以知道这个类的所有属性和方法;
对于任意一个对象,都能够调用他的任意方法和属性。
这种动态获取程序信息以及动态调用对象的功能称为反射机制
hasattr, getattr, setattr, delattr
class People:def __init__(self, name, age, gender):self.name = nameself.age = ageself.gender = genderobj = 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 = nameself.age = age
def str(self):
return '打印对象时自动触发' # 返回类型必须是字符串
obj = People(‘lili’, 18) print(obj) # obj.str
<a name="U1YXN"></a># class关键字的机制分析XXXXXXX<a name="HJT0J"></a># 异常处理```pythontry:代码块except 异常信息1 as e:异常1后输出的内容except 异常信息2 as e:异常2后输出的内容...else:以上异常均不是时,输出的内容finally:无论代码块有无异常,均会输出的内容# 多个异常处理可以写在一起except (异常信息1,异常信息2) as e:
