类的数据属性

  1. class Student:
  2. school = "AAA"
  3. count = 0
  4. def __init__(self, name, age, gender):
  5. # 给类
  6. Student.count += 1 # 给类本身+1,才可以在实例化时都+1
  7. # self.count+=1 # 这里不能给单独的对象+1,会统计不到所有的实例
  8. self.name = name
  9. self.age = age
  10. self.gender = gender
  11. obj1 = Student("x", "z", 'a')
  12. obj2 = Student('1', '2', '3')
  13. obj3 = Student('k1', 'k2', 'k3')
  14. obj1.count += 1 # 单独给obj1对象多加了个1
  15. # 注意答案不是1,2,3 因为是实例化完了之后在count的
  16. print(obj1.count) # 3
  17. print(obj2.count) # 3
  18. print(obj3.count) # 3

封装

一、隐藏属性怎么用?

隐藏数据属性

  1. class Student:
  2. # 对age属性进行隐藏
  3. def __init__(self, name, age, gender):
  4. self.name = name
  5. self.__age = age
  6. self.gender = gender
  7. # 对外提供访问的接口
  8. def set_age(self, age):
  9. # 可以增加对隐藏属性修改的限制条件
  10. if not isinstance(age, int):
  11. raise TypeError("必须是int类型")
  12. return age
  13. obj = Student('s', 'we', 'w')
  14. res = obj.set_age('23')
  15. print(res)

隐藏函数属性

  1. class ATM:
  2. def __card(self): #插卡
  3. print('插卡')
  4. def __auth(self): #身份认证
  5. print('用户认证')
  6. def __input(self): #输入金额
  7. print('输入取款金额')
  8. def __print_bill(self): #打印小票
  9. print('打印账单')
  10. def __take_money(self): #取钱
  11. print('取款')
  12. def withdraw(self): #取款功能
  13. self.__card()
  14. self.__auth()
  15. self.__input()
  16. self.__print_bill()
  17. self.__take_money()
  18. obj=ATM()
  19. obj.withdraw() # 取款功能分了好多小步骤,但是不想让用户知道,但又要用时,可以隐藏

二、property、setter、deleter

案例一

  1. class People:
  2. def __init__(self, name, weight, height):
  3. self.name = name
  4. self.weight = weight
  5. self.height = height
  6. @property # bmi=property(bmi)
  7. def bmi(self):
  8. return self.weight / (self.height) ** 2
  9. obj = People('li', 75, 1.85)
  10. # 没有装饰器property时,bmi为功能属性,需要加括号调用
  11. print(obj.bmi())
  12. # 有装饰器时,把功能属性作为数据属性调用,不需要加括号
  13. print(obj.bmi)

案例二

  1. class People:
  2. def __init__(self, name):
  3. # 当前name作为了隐藏属性,需要开放使用接口
  4. self.__name = name
  5. def get_name(self):
  6. """查看名字"""
  7. return self.__name
  8. def set_name(self, val):
  9. """修改名字"""
  10. if isinstance(val, str):
  11. self.__name = val
  12. def del_name(self):
  13. """删除名字"""
  14. print("该属性不可删除")
  15. name = property(get_name, set_name, del_name)
  16. obj = People('AAA')
  17. # 不加装饰器的用法
  18. print(obj.get_name())
  19. obj.set_name('BBB')
  20. print(obj.get_name())
  21. obj.del_name()
  22. print("="*10)
  23. # 加装饰器后的用法
  24. print(obj.name) # 相当于直接调用name里的get_name方法
  25. obj.name = "CCC" # 相当于直接调用name里的set_name方法
  26. print(obj.name)
  27. del obj.name # 相当于直接调用name里的del_name方法

案例三

案例三为案例二的改进写法

  • 希望属性不被随意修改:设置隐藏属性
  • 修改该属性的一系列功能接口(功能名字一样) ```python class People: def init(self, name):

    1. # 当前name作为了隐藏属性,需要开放使用接口
    2. self.__name = name

    @property #name123=property(name123) def name123(self):

    1. """查看名字"""
    2. return self.__name

    @name123.setter def name123(self, val):

    1. """修改名字"""
    2. if isinstance(val, str):
    3. self.__name = val

    @name123.deleter def name123(self):

    1. """删除名字"""
    2. 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方便理解和区分

  1. <a name="IkEKY"></a>
  2. # 继承
  3. <a name="CURd6"></a>
  4. ## 继承小案例
  5. ```python
  6. class People:
  7. def __init__(self, name, age, gender):
  8. self.name = name
  9. self.age = age
  10. self.gender = gender
  11. class Student(People):
  12. # 有3个共同的属性,2个特有的属性
  13. def __init__(self, name, age, gender, weight, height):
  14. People.__init__(self, name, age, gender)
  15. # super().__init__(name, age, gender)
  16. self.weight = weight
  17. self.height = height
  18. obj = Student('wy', 18, 'female', 123, 110)

单继承下的属性查找

  1. class Foo:
  2. def f1(self):
  3. print('Foo.f1')
  4. def f2(self):
  5. print('Foo.f2')
  6. self.f1() # 问题:若想使得这里的f1得到的是Foo.f1应该如何修改??
  7. class Bar(Foo):
  8. def f1(self):
  9. print('Bar.f1')
  10. obj = Bar()
  11. obj.f2()
  12. """
  13. 输出结果:
  14. Foo.f2 # 首先因为obj对象的类Bar中没有f2,所以来Bar的父类中查找f2了
  15. Bar.f1 # 因为self表示的对象是obj,是Bar创建的,而且Bar中有f1。
  16. 因此是Bar.f1而不是Foo.f1
  17. """

答案

  1. class Foo:
  2. def f1(self):
  3. print('Foo.f1')
  4. def f2(self):
  5. print('Foo.f2')
  6. Foo.f1(self) # 答案:直接使用类来调用,注意此时self也要作为参数传入
  7. class Bar(Foo):
  8. def f1(self):
  9. print('Bar.f1')
  10. obj = Bar()
  11. obj.f2()
  1. class Foo:
  2. def __f1(self): #_Foo__f1
  3. print('Foo.f1')
  4. def f2(self):
  5. print('Foo.f2')
  6. self.__f1() # 答案:隐藏属性,只有类内部可以使用,并且名字发生了变形
  7. class Bar(Foo):
  8. def __f1(self): #_Bar__f1
  9. print('Bar.f1')
  10. obj = Bar()
  11. obj.f2()
  1. class Foo:
  2. @classmethod
  3. def f1(cls):
  4. print('Foo.f1')
  5. def f2(self):
  6. print('Foo.f2')
  7. Foo.f1() # 自动传入Foo为cls
  8. class Bar(Foo):
  9. def f1(self):
  10. print('Bar.f1')
  11. obj = Bar()
  12. obj.f2()

@classmethod和@staticmethod

  • 最开始:使用对象和类来调用类方法的区别 ```python class People: def init(self, name, age, gender):

    1. self.name = name
    2. self.age = age
    3. self.gender = gender

    def add(self, x, y):

    1. 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):

    1. self.name = name
    2. self.age = age
    3. self.gender = gender

    @classmethod # add=classmethod(add) 只绑定给类用 def add(cls, x, y):

    1. return x + y

obj = People(‘wy’, 18, ‘famela’) print(People.add(1, 2)) # 使用类去访问功能属性 “”” 给add添加了@classmethod装饰器后,add就变成了类的绑定方法 也就是说,只有类可以调用,并且此时第一个参数cls就是People本身 “””

  1. ```python
  2. class People:
  3. def __init__(self, name, age, gender):
  4. self.name = name
  5. self.age = age
  6. self.gender = gender
  7. @staticmethod # 作为静态方法在类内定义
  8. def add(x, y): # 即不需要绑定给类也不需要绑定给对象
  9. return x + y
  10. obj = People('wy', 18, 'famela')
  11. # 类和对象都可调用
  12. print(People.add(1, 2)) # 3
  13. print(obj.add(3, 4)) # 7

反射

python是动态语言,而反射(reflection)机制被视为动态语言的关键。
反射机制指的是在程序的运行状态中
对于任意一个类,都可以知道这个类的所有属性和方法;
对于任意一个对象,都能够调用他的任意方法和属性。
这种动态获取程序信息以及动态调用对象的功能称为反射机制

hasattr, getattr, setattr, delattr

  1. class People:
  2. def __init__(self, name, age, gender):
  3. self.name = name
  4. self.age = age
  5. self.gender = gender
  6. obj = People('wy', 18, 'famela')
  7. print(dir(obj)) # 打印所有的属性
  8. # 使用字符串去操作属性
  9. print(hasattr(obj, 'name')) # 查看属性是否存在
  10. print(getattr(obj, 'name')) # 查看当前属性值
  11. setattr(obj, 'name', 'new_name') # 修改属性值
  12. print(getattr(obj, 'name')) # 查看修改后的属性值
  13. delattr(obj, 'name') # 删除'name'属性
  14. print(dir(obj)) # 再查看属性已经没有了'name'

str, del

  • __str__:会在对象被打印时自动触发,print功能打印的就是它的返回值,另外该方法需要返回字符串类型
  • __del__:会在对象被删除时自动触发。但是python有自动的垃圾回收机制,因此几乎不用 ```python class People: def init(self, name, age):

    1. self.name = name
    2. self.age = age

    def str(self):

    1. return '打印对象时自动触发' # 返回类型必须是字符串

obj = People(‘lili’, 18) print(obj) # obj.str

  1. <a name="U1YXN"></a>
  2. # class关键字的机制分析
  3. XXXXXXX
  4. <a name="HJT0J"></a>
  5. # 异常处理
  6. ```python
  7. try:
  8. 代码块
  9. except 异常信息1 as e:
  10. 异常1后输出的内容
  11. except 异常信息2 as e:
  12. 异常2后输出的内容
  13. ...
  14. else:
  15. 以上异常均不是时,输出的内容
  16. finally:
  17. 无论代码块有无异常,均会输出的内容
  18. # 多个异常处理可以写在一起
  19. except (异常信息1,异常信息2) as e: