• 中文
    • 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
  • 1.3k
  • 请登录之后再进行评论

    登录
    单栏布局 侧栏位置: