• 中文
    • English
  • 注册
  • 查看作者
    • 第十四章:面向对象编程

      一.  类和实例

      在Python中,定义类是通过class关键字,后面紧接着类名和父类,创建实例是通过类名+()实现,访问限制可以通过__属性以及get和set方法实现

      class Student(object):
      
          #构造方法
          def __init__(self, name, score):
              self.__name = name
              self.__score = score
      
          # setter方法
          def set_name(self, name):
              self.__name = name
      
          def set_score(self, score):
              self.__score = score
      
          # getter方法
          def get_name(self):
              return self.__name
      
          def get_score(self):
              return self.__score
      
          # toString
          def print_score(self):
              print('姓名 = %s ,分数 = %s' % (self.__name, self.__score))
      
      
      # 实例化对象
      jia = Student('张甲',100)
      
      print(jia.get_name())  # 张甲
      
      jia.print_score() # 姓名 = 张甲 ,分数 = 100

      二. 继承和多态

      子类继承父类,就获得了父类的全部功能,当子类和父类都存在相同的r方法时,子类的方法会覆盖父类的方法,也就是多态

      class Animal(object):
          def run(self):
              print("动物会跑")
      
      class Dog(Animal):
          def run(self):  #覆盖父类,称谓多态
              print('狗会跑')
          pass
      
      class Cat(Animal):
          pass
      
      def run2(animal):
          animal.run()
      
      dog = Dog()
      dog.run()  # 狗会跑
      
      run2(Dog()) #传入狗的实例,输出:狗会跑
      run2(Animal()) #传入动物的实例,输出:动物会跑

      以上面的代码为例,对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了。

      三. 获取对象信息

      1. 可以使用type()函数判断对象类型,type返回对应的Class类型

      print(type(123))  # <class 'int'>
      x = 123
      print(type(x))  # <class 'int'>
      
      print(type(x) == type(123)) #True

      2. 使用types模块中定义的常量可以判断一个对象是否是函数

      import types
      def fn():
          print("Hello")
      
      print(type(fn)) #<class 'function'>
      print(type(fn) == types.FunctionType) #True
      print(type(abs) == types.BuiltinFunctionType) #True
      print(type(lambda x:x) == types.LambdaType) #True
      print(type((x for x in range(10)))==types.GeneratorType) #True

      3. 判断class的类型,用type()不方便,所以我们总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。

      class Animal(object):
          def run(self):
              print("动物会跑")
      
      class Dog(Animal):
          def run(self):  #覆盖父类,称谓多态
              print('狗会跑')
          pass
      
      class Husky(Dog):
          def run(self):  # 覆盖父类,称谓多态
              print('我是哈士奇')
          pass
      
      a = Animal()
      b = Dog()
      c = Husky()
      
      print(isinstance(a,Animal))  #True
      print(isinstance(b,Dog)) #True
      print(isinstance(c,Dog)) #True

      4. isinstance()还可以判断一个变量是否是某些类型中的一种

      print( isinstance([1, 2, 3], (list, tuple))) #True

      5. 如果要获得一个对象的所有属性和方法,可以使用dir()函数,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态。

      class Dog(object):
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          def run(self):  #覆盖父类,称谓多态
              print('狗会跑')
          pass
      
      
      print(dir(Dog))
      '''
      ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run']
      '''
      d = Dog("嘎嘎",1)
      print(hasattr(d,'name')) # True
      print(hasattr(d,'names')) # False
      
      if(hasattr(d,'name')):
          d.name = "哈哈"
      # 只有在不知道对象信息的时候,我们才会去获取对象信息
      print(getattr(d,'name')) #哈哈
      print(getattr(d,'names','默认值')) # 默认值
      # print(getattr(d,'names')) # AttributeError错误
      print(getattr(d,'run'))  # <bound method Dog.run of <__main__.Dog object at 0x0000018BD8B6FB80>>
      getattr(d,'run')() #获得对象的方法,输出:狗会跑

      四. 实例属性和类属性

      一个类可以有实例属性和类属性,给实例绑定属性的方法是通过实例变量,或者通过self变量

      class Dog(object):
          def __init__(self, name):  # 方法一:通过self变量
              self.name = name
      
      
      d = Dog("狗命")
      d.age = 1 # 方法二:通过实例变量
      print(d.name,d.age) # 狗命 1

      直接在class中定义属性,这种属性是类属性,归类所有,但类的所有实例都可以访问到

      class Dog(object):
          name = "默认"
      
      
      d = Dog()
      print(d.name) # 默认
      
      d.name = "大狗"
      print(d.name) # 大狗
      print(Dog().name) # 默认

      千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性

      其他

      在评论区看到了一个很好的问题和很好的回答:

      老婆说啥都是对的:大神解释下,Animal.run和Animal().run 有什么区别?

      用户6553322904:永远记住,类只是一个模板,模板是不会亲自下海干活的。python中如果不加括号,除了个别的,那就是个标识符(你可以理解为变量)。加了括号代表运行前面的东西,比如f就是个标识符,f()代表运行f。Animal(). run,如果Animal是个类,就代表先运行Animal这个类,记得前面章节说的,类运行变为实例,实例才能亲自下海干活。Animal(). run就是这个实例里的run函数(run没加括号表示没运行run,仅仅是个函数而已),Animal(). run()就是先运行Animal生成一个实例,然后运行这个实例里的run函数。你可以试一下Animal. run()也就是运行Animal这个类里的run函数,会报错,告诉你缺少self,这个self是什么呢?就是你创建的实例。再回想一遍前面所说的,类只是个模板,打个比方,网站上的PPT模板怎么能干活呢,你得把它下载下来变成你的实例才能干活。而继承是什么呢,差不多就是,有人把PPT模板复制到另一个PPT模板中,变成了一个新模板(注意是模板)。而拿你的实例做一些东西,比如Animal().run(),或者a=animal();a. run(),就像是在给别人展示你的ppt(不是模板,网上ppt模板怎么能给别人展示呢?),你也可以稍加修改你的ppt(不是修改ppt模板),比如a. eye=blue。

      参考资料

      [1] 廖雪峰-Python教程

      [2] 廖雪峰-Python教程评论

    • 0
    • 0
    • 0
    • 937
    • 请登录之后再进行评论

      登录

      赞助本站

      • 支付宝
      • 微信
      • QQ

      感谢一直支持本站的所有人!

      单栏布局 侧栏位置: