Python面向对象基础
note:
重要强调:
python的作用域和命名空间
(1)命名空间 是从命名到对象的映射
①内置命名空间
②全局命名空间:模块
③本地命名空间:模块中的函数和类
(2)作用域 是一个 python 程序可以直接访问命名空间的正文区域
一:简介
类:用来描述具有相同的属性和方法的对象的集合
方法:类中定义的函数
类变量:类变量在整个实例化的对象中是公用的。
类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
实例变量:定义在方法中的变量,只作用于当前实例的类。(注意区分实例变量和类变量)
实例变量用于对每一个实例都是唯一的数据,类变量用于类的所有实例共享的属性和方法
用构造方法初始化的属性叫做实例变量,直接在类中定义的属性叫做类变量。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override)
实例化:创建一个类的实例,类的具体对象
对象:通过类定义的数据结构实例
二:语法格式
class classname:
<statement-1>
<statement-n>
三:类对象
类对象支持两种操作:属性引用和实例化。
(1)类对象创建后,类命名空间中所有的命名都是有效属性名myclass.f
(2)实例化:将类对象看作是一个返回新的类实例的无参数函数x = myclass()
四:类属性
公有属性:在类中定义,可以在类间调用,可以通过析构函数进行初始化
私有属性:在类中定义,以双下划线开始,在类外不能被直接调用,只能被类内部方法使用!
调用方法:用公有方法返回!
五:类方法
(1)类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,
按照惯例它的名称是 self
(2)在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,
类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例
(3)两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类地外部调用
(4)类的专有方法
六:构造函数
类有一个名为 __init__() 的特殊方法(构造方法),
该方法在类实例化时会自动调用类有一个名为 __init__() 的特殊方法(构造方法),
该方法在类实例化时会自动调用
可以声明带默认参数的实例变量!
七:析构函数
实例化的对象调用结束时候调用!
八:类的继承
(1)语法结构
class derivedclassname(baseclassname1):
<statement-1>
.
<statement-n>
(2)多类继承的时候,新式类(python3)按照广度优先的原则,
(找一个爸爸,再找下一个爸爸。。。。)
class derivedclassname(base1, base2, base3):
<statement-1>
.
<statement-n>
(3)基类名与派生类定义在同一个作用域中,除了类,还可以用表达式,
基类定义在另一个模块中时这一点非常有用:
class derivedclassname(modname.baseclassname):
这种写法在模块化程序中很重要!
(4)方法重写
①父类方法的功能不能满足你的需求,可以在子类重写你父类的方法
super(child,c).mymethod() #用子类对象调用父类已被覆盖的方法
子类,对象, 方法
②派生类对基类的方法重写,重写后的基类方法叫做费捆绑方法,
不能直接调用,需要使用super函数。
注意:
①子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__。
②重写了__init__ 时,实例化子类,就不会调用父类已经定义的 __init__
③如果重写了__init__ 时,要继承父类的构造方法,可以使用 super 关键字
super(子类,self).__init__(参数1,参数2,....)
父类名称.__init__(self,参数1,参数2,...)
八:多态和封装
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。
例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,
并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,
并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。
任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,
这种决定类型的方式因此得名。
http://www.php.cn/python-tutorials-366356.html
(关于多态不是太懂!)
1 # -------------------------------------------------------------------------------------------------------------# 2 # 创建类 3 # -------------------------------------------------------------------------------------------------------------# 4 5 6 class myclass: # 类的命名为大驼峰原则 7 """一个简单的类实例""" 8 i = 12345 # 类的公有属性 9 10 def __init__(self, real): # 带参数的构造函数(方法) 11 self.r = real 12 # self.i = imag 13 14 def func(self): # 类的方法和普通函数的区别 15 m = self.i + self.r 16 return m 17 # -------------------------------------------------------------------------------------------------------------# 18 # 类的实例化 19 # -------------------------------------------------------------------------------------------------------------# 20 21 22 print("------------------------类的实例化-----------------------------------") 23 x = myclass(2) 24 y = myclass(3) 25 # print(x.__doc__) 26 # 访问类的属性和方法 27 print("myclass 类的属性 i 为:", x.i) 28 print("myclass 类的属性 i 为:", y.i) 29 30 # 对于可变对象如列表、字典、集合,应该声明为实例变量,因为实例化后的对象会改变原来的值! 31 x.i = 23 32 print("实例化x后 i 为:", x.i) 33 print("实例化y后 i 为:", y.i) 34 print("myclass 类的方法 f 输出为:", x.func()) 35 36 # -------------------------------------------------------------------------------------------------------------# 37 # 类的继承 38 # -------------------------------------------------------------------------------------------------------------# 39 print("------------------------类的继承-------------------------------------") 40 41 42 # 定义基类 43 class people: 44 # 定义类变量 45 # name = '' 46 # age = 0 47 # 定义私有属性,私有属性在类外部无法直接进行访问 48 # __weight = 0 49 # 定义构造方法,初始化类变量的值 50 51 def __init__(self, n, a, w): # 构造函数 52 # print('调用了构造函数') # 测试构造函数的调用 53 self.name = n 54 self.age = a 55 self.__weight = w 56 # 上面的变量可以全部定义为私有变量!因为在外部没有必要使用! 57 58 def speak(self): 59 print("%s 说: ’我 %d 岁 %dkg’" % (self.name, self.age, self.__weight)) 60 61 def my_print(self, name): 62 print(self.name) # self的作用是类级别上的变量 63 print(name) # 不带self可能是变量的值 64 65 def get_name(self): # opp家族传统理念:getter + setter 66 return self.name # 为了得到类中的数据并且抱枕数据的安全(无受保护的数据类型) 67 68 def get_age(self): # 通过self实现内容的间接调用 69 return self.age 70 71 # @property # 72 def get_weight(self): # 通过self实现内容的间接调用 73 return self.__weight 74 75 def __del__(self): # 注意学习python的垃圾回收机制 76 print('调用了父析构函数') 77 # 总结:对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中, 78 # 通过对象或者self间接的调用内容 79 80 # 继承:子可以继承父亲的所有内容 81 # 定义派生类 82 83 84 class student(people): 85 86 def __init__(self, n, a, w, g): 87 self.__grade = g 88 people.__init__(self, n, a, w) # 调用父类的构造函数 89 90 # 保变量的值不被改变 ,又要得到值 91 def lo_ol(self): 92 print('i am not a good student!') 93 print('my grade is %d' % self.__grade) 94 95 def __del__(self): # 注意学习python的垃圾回收机制 96 print('调用了子析构函数') 97 98 99 myinfo = people('faith', 24, 60) 100 myinfo.speak() 101 myinfo.age = 10 102 myinfo.speak() 103 print(myinfo.age) # 类外直接使用 104 105 106 print("------------------------测试派生类-------------------------------------") 107 # 通过上面的代码可以得到下面的结论: 108 # 析构函数在对象释放的时候调用 109 # 可以直接在类外访问类的基本属性 110 # 不能在类外直接访问类的私有属性 111 112 stud = student('faith', 2, 2, 2) 113 stud.lo_ol() 114 stud.speak() 115 print("体重", stud.get_weight()) 116 # 方法重写 117 118 119 class parent: # 定义父类 120 def mymethod(self): 121 print('调用父类方法') 122 123 124 class child(parent): # 定义子类 125 def mymethod(self): 126 print('调用子类方法') 127 128 129 print("------------------------测试方法重写-------------------------------------") 130 c = child() # 子类实例 131 c.mymethod() # 子类调用重写方法 132 super(child, c).mymethod() # 用子类对象调用父类已被覆盖的方法 133 134 # 静态方法和类方法 135 print("------------------------测试静态方法和类方法-------------------------------------") 136 137 138 class apple: 139 def fun1(self): 140 return 'normal' 141 142 @staticmethod # 静态方法 143 def fun2(): 144 return 'staticmethod' 145 146 @classmethod 147 def fun3(cls): # 类方法(能够访问类属性) 148 return 'classmethod' 149 150 151 print(apple.fun1) # 非捆绑调用 152 print(apple.fun2) 153 print(apple.fun3) 154 print("-"*80) 155 156 157 apple = apple() # 捆绑调用 158 print(apple.fun1) 159 print(apple.fun2) 160 print(apple.fun3) 161 162 print("-"*80) 163 164 apple1 = apple() # 捆绑调用 165 print(apple1.fun1) 166 print(apple1.fun2) 167 print(apple1.fun3)