本篇文章主要是对python学习时的一些总结,作为学习笔记记录。
在最开始的时候,就说到python是面向对象的,解释型的,弱类型的编程语言,之前我们介绍了解释型和弱类型,那么python的面向对象是什么呢?
基础名词
名词 | 描述 |
类 | 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法 |
属性 | 类中定义的变量,位于方法之外 |
方法 | 类中定义的函数 |
实例 | 类的具体对象 |
实例化 | 创建一个类的实例的过程 |
封装 | 在类中对数据的赋值、内部调用对外部用户是透明的 |
继承 | 即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待 |
多态 | 一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现 |
方法重写 | 如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写 |
类定义
class Classname:
statements
类的私有属性
__private_attrs:以两个下划线开头,说明该属性为私有,不能够在类的外部被使用或者直接说明,在类内部可以使用self.__private_attrs进行访问。
类的方法
类方法以def关键字定义,同时类方法一般需要包含self参数,表示实例本身。
类的私有方法
__private_method:以两个下划线开头,说明该方法为私有方法,只能够在类的内部调用,不能在类外部调用,在类内部可以使用self.__private_method()进行调用。
class A:
attrs = value # 公有属性
__private_attrs = value # 私有属性
def methodname(self,args): # 公有方法
pass
def __private_method(self, args): # 私有方法
pass
其实类的私有属性和私有方法并不是真的不能在类外部访问,而是python解释器又一次对类的私有属性和私有方法进行了修饰,从而改变了私有属性和私有方法的名称,也就是说,只要我们能够找到改变后的名称,我们就能够实现类的私有属性和私有方法的外部访问。
class A:
a = 10
__b = 20
def func(self):
print("func")
def __foo(self):
print("foo")
print(dir(A))
aa = A()
print(aa.a)
print(aa._A__b)
aa.func()
aa._A__foo()
结果为:
['_A__b', '_A__foo', '__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__', 'a', 'func']
10
20
func
foo
从上面的结果可以看出,私有属性__b名称变为了_A__b,私有方法__foo名称变为了_A__foo,因此我们使用原有的私有属性和私有方法名称自然不能进行访问,也就保证了私有。
实例
实例化
在定义完之后,可以通过Classname()的形式来创建类对象。类对象的创建也叫实例化。
class A:
pass
a = A()
这样就创建了一个类A的对象。
属性引用
属性引用可以使用Classname.attributename的形式进行引用。
方法调用
方法调用可以使用Classname.methodname(args)的形式进行调用。
class A:
name = 'A'
def func(self):
print('A.func')
a = A() # 实例化
print(a.name) # 属性引用
a.func() # 方法调用
self
在上面类的定义中,类A的func方法有一个self参数,此参数表示的是类在实例化之后的实例本身,有点类似于C/C++中的this指针,对于类方法形参的参数名如果和内部属性名冲突,则可以用self来判别。
默认情况下,类方法都会有一个指向实例本身的参数,一般写作self,当然写作别的变量名也是可以的。
动态属性
在python中,用户可以动态地添加或者修改属性,而不必像C/C++一样事先定义好所有的数据成员。
class A:
name = 10
def func(self):
print('self.name = ', self.name)
print('A.name = ', A.name)
def foo(self):
print('new func')
a = A()
print(dir(a))
a.func()
a.name = 20
a.func()
a = A()
a.func()
a.age = 30
print(dir(a))
b = A()
b.func()
print(dir(b))
c = A()
c.name = 40
A.name = 50
c.func()
A.func = foo
c.func()
结果为:
['__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__', 'func', 'name']
self.name = 10
A.name = 10
self.name = 20
A.name = 10
self.name = 10
A.name = 10
['__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__', 'age', 'func', 'name']
self.name = 10
A.name = 10
['__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__', 'func', 'name']
self.name = 40
A.name = 50
new func
从上边的结果可以看出:
- 实例变量和类变量属于两个不同的变量空间,单独修改实例的变量并不会影响类中的变量,类变量可以认为是实例变量的初始值
- 实例可以动态地添加属性,新添加的属性并不影响其它实例的属性,也不影响类本身的属性,只是对该实例有所影响
- 对于相同的变量名,可以认为实例和类的有不同的变量空间,只有当实例中不存在此变量时,才会访问类中的对应变量
- 若对类变量进行修改,其结果会影响到后边的所有实例
- 类中的方法也是可以修改的,但是实例方法不允许修改