类的三个基本特征:封装、继承、多态。

  封装:将客观事物的共性(属性、方法)抽象归类

  继承:OOP的主要功能,可以通过“继承”与“组合”的方式实现

  多态:相同方法的不同表现,方法的覆盖与重载

魔法方法:__init__(self,[]) 类实例化过程中自动调用的方法,用于初始化类属性或者对象属性。

公有、私有:

  类的属性或者方法分为公有与私有,Python中没有用于区分的关键字,通过双下划线定义私有。但是这种定义是一种 name mangling (姓名重组)技术,即只是内部将类的方法或者属性按照特定的规则进行了重命名。新的私有属性或方法的名称为:  _classname__attribute。如下代码测试结果显示,当声明为私有时,无法通过该变量或方法的原始名称进行访问,会有 has no attribute的异常。通过内置属性__dict__可对类的变量进行查看,发现私有属性已经被重命名为 _Test__name,而实例对象仍然能够访问该属性。

1 class Test():
 2     __name = '已经崩盘了'
 3     def __init__(self):
 4         pass
 5     
 6 t = Test()
 7 #t.name             #'Test' object has no attribute 'name'
 8 #t.__name            #'Test' object has no attribute '__name'
 9 print(Test.__dict__)     # 调用 内置属性 查看类的全部变量
10 t._Test__name
11 
-------------------------------------------------------------------------------------------------------------------------------------------------
12 {'__module__': '__main__', '_Test__name': '已经崩盘了', 
'__init__': <function Test.__init__ at 0x00B057C8>, 
'__dict__': <attribute '__dict__' of 'Test' objects>, 
'__weakref__': <attribute '__weakref__' of 'Test' objects>, 
'__doc__': None}
13 
14 '已经崩盘了'

父类 基类 超类:

  父类又叫做超类(super)。子类继承父类时需要对父类进行初始化。因此需要主动调用父类的 __init()__方法,调用父类__init__()方法有两种方式:如下代码第 9 行 与第 10 行。

  为什么子类继承父类后需要调用父类的__init__()方法,因为子类中也存在一个 __init__()方法,会对父类的方法进行覆盖,从而无法使用父类__init__()中的属性或方法。

1 import random
 2 
 3 class Father():
 4     def __init__(self):
 5         self.x = random.randint(1,10)
 6         
 7 class Child(Father):
 8     def __init__(self):
 9         super().__init__()
10         #Father.__init__(self)
11         pass
12     
13 c = Child()
14 c.x

类的组合:

  当几个类之间存在关系,但又很难构成继承关系时,可以通过组合的方式让类横向产生关系。如下代码所示,通过在类中实例化其他类实现类的组合。

class A():
    def __init__(self):
        print("Class A")
        self.x = 10
        
class B():
    def __init__(self):
        print('Class B')
        
class Combine():
    def __init__(self):
        self.a = A()              #在类中对其他类进行实例化
        self.b = B()              # 用于关联类横向之间的关系

c = Combine()
print(c.a.x)
##############################
Class A
Class B
10

Mix-in

属性名与方法名相同,会发生覆盖:

  当定义属性与方法时,需要注意,不能使属性名与方法名相同,否则后先定义的会被覆盖。原因在于,一切皆对象导致无法做出区分。

1 class A():
 2     x = 10
 3     def x(self):
 4         print('This is a function!')
 5           
 6 a = A()
 7 
 8 a.x()
 9 a.x
10 
11 ###############################
12 This is a function!
13 
14 <bound method A.x of <__main__.A object at 0x003A2B90>>

绑定:严格要求方法需要有实例才能被调用,这种限制就是Python所谓的绑定概念。

  类通过参数 self 进行绑定,self表示对象,即当方法中形参包含该参数时,调用时必须为该方法传入一个对象参数,没有则不用(类中不允许这种情况,但是不会报错)。而self做为一个形参可以使用其他名称代替,self并不是一个关键字。

  测试代码如下,注意对象于类的变量列表,由于x,y均为 实例变量,即只有实例化属于对象所有,所以 x,y不会出现在类的变量列表中,而对象为调用setXY函数之前,对象也不存在x,y变量,这很好理解,因为代码还未执行,更不会产生赋值操作(Python赋值即定义)。fun()函数不存在形参,因此可以被类调用,相反 setXY不能被类调用。

class A():
    def setXY(self,x,y):
        self.x = x
        self.y = y
        
    def fun():
        print('This is s function')
        
a = A()       #实例化一个对象 a
#分别打印类的变量与对象的变量
print("类的变量列表为:")
print(A.__dict__)
print('对象的变量列表为:')
print(a.__dict__)

# 对象调用 函数
a.setXY(10,20)
# 查看各自变量
print(A.__dict__)
print(a.__dict__)

# 类调用函数
A.fun()
#A.setXY(1,2)          # 抛出异常 缺少参数 y
A.setXY(a,1,2)         #原因在于缺少了 对象这个参数
print(A.__dict__)
print(a.__dict__)
print(a.x,a.y)

#################################################
类的变量列表为:
{'__module__': '__main__', 'setXY': <function A.setXY at 0x00B05B28>, 'fun': <function A.fun at 0x00B05858>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
对象的变量列表为:
{}
{'__module__': '__main__', 'setXY': <function A.setXY at 0x00B05B28>, 'fun': <function A.fun at 0x00B05858>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
{'x': 10, 'y': 20}
This is s function
{'__module__': '__main__', 'setXY': <function A.setXY at 0x00B05B28>, 'fun': <function A.fun at 0x00B05858>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
{'x': 1, 'y': 2}
1 2

Python中 一切皆对象,即各种数据类型也不例外,当为对象的属性进行赋值时,若对象的属性不存在则为对象添加改属性,否则进行赋值。

  AttributeError:可通过加入判断对赋值的属性进行筛选,避免数据的安全性问题。

相关的BIF:

issubclass(class, classinfo): object 是所有类的基类
isinstance(object, classinfo) #可用于判断变量的类型 字符串,列表等
hasattr(object, name)
getattr(object, name, [default])
setattr(object, name, value)
delattr(object, name)
proprity(fget=none, fset=none, fdel = none) 用于提高代码的封装性。

类中变量的生存空间:

  类变量:在类的方法中进行更改时需要使用类进行引用

  实例变量:可以在类的方法之间调用

  函数局部变量:只能在该方法中使用

测试代码如下所示:

1 class A():
 2     z = 10
 3     def __init__(self,x,y):
 4         #z += 1  #local variable 'z' referenced before assignment
 5         A.z +=1
 6         self.x = x
 7         self.y = y
 8         d = 1
 9         
10     def fun(self):
11         print('This is s function')
12         print(self.x)
13         print(d)
14         
15 a = A(10,20)
16 print(a.z)
17 print(A.z)
18 b = A(1,2)
19 print(b.z)
20 print(A.z)
21 a.fun()     #name 'd' is not defined