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'>

转载于:https://www.cnblogs.com/yangzhenwei123/p/6759272.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值