• python 类的简单介绍


    1 面向过程的程序设计

         在说面向对象的程序设计以前,先说下我们之前写的那些面向过程的程序的特点:针对性很强,针对特定的需求所写;流水线式的设计,先实现什么再实现什么,结构非常清晰。但耦合度非常高,牵一发而动全身。
    总结面向过程的特点:

    1. 针对性强,只适用于该需求的程序设计
    2. 流水线设计,结构清晰。但可扩展性非常差。

         应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。


    2 什么是面向对象的程序设计

          面向对象的程序设计的核心思想:“一切皆对象”。如何理解?我们日常中,遇到的一个人,一本书等,都是一个具体的对象。那我们又是如何认定他是一个人的,一个人有哪些特性?他会说话,他用两只脚走路,他有2只手,用手吃饭。那只要有这些特性的对象,我们就称他为人。而类则是不同对象之间共性的抽象。类里包含了:特征(变量)和技能(函数)。这里所说的“人”,就是一个类。每一个具体的人,张三,李四就是一个具体的对象。对象就是类的具体表现。(有别于其他编程语言,如java类包括属性和方法。)

    OOP做出的程序项目优点很多:

    • 易维护
    • 效率高
    • 质量高
    • 易扩展

    3 类和对象

    • 定义一个人类,人有2只腿,用腿走路。
    class Person:
        legs_amount=2   #共有的属性
        def walk(self):
            print("person use two legs to walk.")
    

    3.1 类的作用

    类的作用:实例化和属性引用(这里类的属性包括变量属性和函数属性,有别于下面的对象属性)

    1. 属性引用
    print(Person.legs_amount)   #2
    #Person.walk()   #TypeError: walk() missing 1 required positional argument: 'self'
    print(Person.walk)  #<function Person.walk at 0x000001EBEBE7BAE8>
    Person.walk(111)  #person use two legs to walk.
    #调用一个不存在的函数
    Person.eat()
    #AttributeError: type object 'Person' has no attribute 'eat'
    

    用Person.walk()此时是把walk当普通函数来调用的,所以self作为位置参数必须接收一个值。看Person.eat()这个不存在的方法,错误显示的是“has no attribute”(翻译:不存在的属性),所以python中,类的函数,也称为类的属性。(不同于java)
    查看类的属性的方法:Person.__dict__

    print(Person.__dict__)
    

    结果:

    {'__module__': '__main__', 'legs_amount': 2, 'walk': <function Person.walk at 0x000001AE7871BAE8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    
    1. 实例化
      如何创建一个对象。将类名加上()来调用(类似于函数),再将它赋值给一个变量。那这个变量就是一个对象。该过程叫实例化对象。
    p1=Person()
    

    实例化对象p1以后,就可以直接用p1来调用他自己的属性和方法。

    print(p1.legs_amount)   #2
    print(p1.walk)   #<bound method Person.walk of <__main__.Person object at 0x0000023FD3C9A0F0>>
    p1.walk()   #person use two legs to walk.
    

    此时p1.walk()并不需要额外对self传参,打印p1.walk会发现此时p1.walk是bound method(绑定方法),而上面Person.walk打印的是function(函数)。也就是说类名调用自身的函数,是作为普通函数调用。而对象调用自身的“函数”,就是绑定方法。
    对象的属性:本身只有的特征(变量),__init__()中定义的变量。
    查看对象的属性的方法:p1.__dict__

    print(p1.__dict__)
    

    结果:

    {}
    

    为什么对象能引用不在自己名称空间的属性。
    绑定方法的核心就是“绑定”,将函数唯一绑定到一个确定的对象。谁调用,就作用于谁。(对象调用绑定方法也叫给对象发消息,告诉对象要干嘛。)

    3.2 类中self

    那为什么对象调用自身方法,不需要给self传位置参数?在回答这个问题之前,我们先引入数__init__()函数。

    class Person:
        legs_amount=2   #共有的属性
        def __init__(self):
            print("this is __init__()")
            print(self)
    
    p1=Person()   #Person.__init__(p1)
    print(p1)
    

    结果:

    this is __init__()
    <__main__.Person object at 0x000002619383A0F0>
    <__main__.Person object at 0x000002619383A0F0>
    

    我们可以发现,在函数实例化的时候,就会自动调用__init__()函数。(类似于java里的构造函数)
    而print(p1)和print(self)显示是用一个Person对象。所以p1=Person()实际执行的是Person.__init__(p1)(这里的self可以等同于java中class里的this)
    python中的__init__方法只能return None或空,不能return其他值。

    3.3 对象与对象之间的交互

    一个类实例化的不同对象之间会不会相互影响?

    class Person:
        legs_amount=2   #共有的属性
    
        def __init__(self,name):
            self.name=name
    
        def eat(self):
            print("%s eat food"%self.name)
    
    p1=Person("aa")
    print("p1.legs_amount:",p1.legs_amount)
    p1.eat()
    p1.legs_amount=1
    print("p1.legs_amount:",p1.legs_amount)
    print("----------")
    p2=Person("bb")
    print("p2.legs_amount:",p2.legs_amount)
    p2.eat()
    
    

    结果

    p1.legs_amount:2
    aa eat food
    p1.legs_amount:1
    ----------
    p2.legs_amount:2
    bb eat food
    

    可以发现,每个对象自己的属性(包括共有的属性,即__init__()里定义的变量)无论怎么修改都不会影响其他对象的属性值。p1.legs_amount=1,实际上是在自己的命名空间(__dict__)里面加入了leg_amount变量属性。相当于p1.__dict__["legs_amount"]=1

    #print(Person.name) #AttributeError: type object 'Person' has no attribute 'name'
    Person.legs_amount=1
    print("Person.legs_amount:",Person.legs_amount)
    print(",p2.legs_amount:",p2.legs_amount)
    

    结果:

    Person.legs_amount:1
    p2.legs_amount:1
    

    可以发现,Person并不能修改__init__()里定义的变量,但它可以修改共有的属性legs_amount,此时Person的实例化对象的legs_amount属性都随之发生改变。

    3.4 类名称空间与对象/实例名称空间

    创建一个类就会创建一个类的命名空间,用来存储类中定义的所有名字,这些名字统称为类的属性。
    类里面有两种属性:数据属性和函数属性
    其中类的数据属性是共享给所有对象的。

    p1=Person("aa")
    
    print(id(p1.legs_amount))   #1358668928
    print(id(Person.legs_amount))    #1358668928
    

    而类的函数属性是绑定到所有对象的。

    print(id(p1.eat))   #2271362786824
    print(id(Person.eat))     #2271394904944
    

         在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常。 **
         
    注意:创建类会创建类的命名空间,但不会创建作用域,所以在类里面调用类里定义的变量或函数,就必须用obj.name或类名.name**


    3.5 增加删除类和对象的属性

    #添加属性
    Person.hands_amount=2
    print("Person.hands_amount:",Person.hands_amount)
    print("p1.hands_amount:",p1.hands_amount)
    
    p1.age=20
    print("p1.age:",p1.age)
    #print(p2.age)  #AttributeError: 'Person' object has no attribute 'age'
    

    结果:

    Person.hands_amount: 2
    p1.hands_amount: 2
    p1.age: 20
    

    添加和修改属性的方法:类名或对象.属性=值。Person添加的属性,是大家共有的。对象添加的是对象私有的。删除属性:del 类名或对象.属性

    #删除属性
    Person.hands_amount=2
    print("Person.hands_amount:",Person.hands_amount)
    del Person.hands_amount
    print("Person.hands_amount:",Person.hands_amount)
    

    结果:

    Person.hands_amount: 2
    AttributeError: type object 'Person' has no attribute 'hands_amount'
    

    补充说明

    在python里面,类或对象.变量名的访问方式,是先在类或变量的命名空间中寻找该变量名

    3.6 总结

    1. 类名加()赋值给一个变量,就叫实例化。
    2. 实例化的时候,会优先调用\_\_init\_\_()方法。其中self就是对象本身。实例化的过程就是:类名.\_\_init\_\_(对象名)
    3. 类调用自己的函数,就是普通的调用。对象调用自身的函数,此时的函数叫绑定方法。
    4. 可以直接在类的外部给类或该类的实例添加修改删除属性。
    5. 类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响。

    4 类的特殊属性

    通常情况,类中以“__变量名”这种形式的,是私有变量。而以“__变量名__”的一类变量,有其特殊的意义。下面我们来介绍一下class里面这类特殊变量的具体用途。

    class Student:
        "student"
        school_name="society_school"
        def __init__(self,name,score):
            self.name=name
            self.score=score
    
        def print_score(self):
            print("%s 's score is %s"%(self.name,self.score))
    
    s=Student("alen",98)
    s.print_score()
    

    结果:

    alen 's score is 98
    {'name': 'alen', 'score': 98}
    

    4.1 查看类属性

    4.1.1 dir()

    打印类下的所有属性和方法,或打印对象的所有属性和方法(包括类的所有属性和它自己特有的属性)。返回的是一个名字的列表。

    print(dir(s))
    print(dir(Student))
    

    结果:

    ['__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__', 'name', 'print_score', 'school_name', 'score']
    ['__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__', 'print_score', 'school_name']
    

    4.1.2 __dict__()

    以键值对的方式打印,对象私有的属性和属性值,或类本身的属性和属性值。返回的是

    print(s.__dict__)
    print(Student.__dict__)
    

    结果:

    {'name': 'alen', 'score': 98}
    {'__module__': '__main__', 'school_name': 'society_school', '__init__': <function Student.__init__ at 0x0000018EE36FBAE8>, 'print_score': <function Student.print_score at 0x0000018EE36FBB70>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    

    4.2 特殊的类属性

    __name__

    类名.\_\_name\_\_
    以字符串的形式返回类的名字

    print(Student.__name__)
    print(s.__name__)
    

    结果:

    Student
    AttributeError: 'Student' object has no attribute '__name__'
    

    __doc__

    类名(或对象名).\_\_doc\_\_
    类的文档字符串

    print(s.__doc__)  
    print(Student.__doc__)
    

    结果:

    student
    student
    

    __base__

    类名.__base__# 类的第一个父类

    __bases__

    类名.__bases__# 类所有父类构成的元组

    __dict__

    类名.__dict__# 类的字典属性

    __module__

    类定义所在的模块

    print(s.__module__)
    print(Student.__module__)
    

    结果:

    __main__
    __main__
    

    __class__

    __class__和type()功能一样

    print(s.__class__)
    print(Student.__class__)
    print(type(s))
    print(type(Student))
    

    结果:

    <class '__main__.Student'>
    <class 'type'>
    <class '__main__.Student'>
    <class 'type'>
    
  • 相关阅读:
    千峰公开课徐老师讲解前端前沿技术总结
    网站被k到可以使用关键词搜索到首页优化总结
    SEO基础内容
    react项目后台及上线步骤
    超好用的图片压缩工具,推荐给你
    属性title样式自定义
    Vue.js_devtools_5.1.0.zip【需要的可自行下载】
    js异步执行 按需加载 三种方式
    Web安全之跨站脚本攻击(XSS)
    操作数组不要只会for循环
  • 原文地址:https://www.cnblogs.com/yangzhenwei123/p/6759272.html
Copyright © 2020-2023  润新知