首先因为python的基础太过简单,想学习python基础的完全可以找本书或者找个视频看看,个人推荐廖雪峰的网站。下面的几节主要总结一下python面向对象之后的一些知识,以作笔记只用,才疏学浅....
基本概念
OOP(面向对象编程):OOP是一种程序设计范型,同时也是一种程序设计方法。对象指的是类的实例,它将对象作为程序的基本单元,将程序和数据一起封装其中,以提高程序的重用性、灵活性和扩展性。
新式类和旧式类
新式类对应的是python2版本的,而新式类对应的是python3版本的。从形式上来看主要的区别就是新式类在定义类的时候要在类名后面加上(object),表示这个类是继承与object类的,所有的新式类都是继承object类的。目前大家都是用的python3版本,也就不用在纠结新式类和旧式类之间细微的区别。
创建类
#定义一个类,类名为A,继承于object类
class A(object):
#定义一个初始化方法,这个self的作用相当于Java中的this
def __init__(self,name):
self.name = name
#定义一个获取名字的方法
def getName(self):
return self.name
#定义一个设置名字的方法
def setName(self,name):
self.name = name
#初始化一个A类的实例化对象,注意这里有一个初始化的操作
a = A("张三")
print(a.getName())
a.setName("李四")
print(a.getName())
"""
输出为:张三
李四
"""
辨析相关概念:类属性和实例属性
根据属性定义的位置不同可以分为类属性和实例属性,直接通过代码看这二者的区别:
class B(object):
#定义一个类属性,在类对象中
x = 7
#声明一个实例化对象
f = B()
print(f.x) #输出为7,证明类在实例化对象的时候是会回去类属性的
print(B.x) #输出为7,类属性可以通过类名.类属性的形式调用类属性
f.x += 1
print(f.x) #输出为8,证明实例属性在上面的加一操作后有了效果
print(B.x) #输出仍然还是7
#上面的代码说明实例化对象只是复制了一份给到自己的实例化属性而已
del f.x
print(f.x) #输出为7,实例化属性被删除后,会自动调用类属性
B.x += 1
print(f.x) #输出为8,类属性控制着实例属性
f.x += 3
print(f.x) #输出为11
print(B.x) #输出为8
"""
输出为778778118
"""
class B(object):
y = [1, 2]
b = B()
print(b.y)
print(B.y)
b.y.append(3)
print(b.y)
print(B.y)
"""
输出为[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]
"""
从上面可以看出来,对于可变类型和不可变类型,类属性和实例属性是没有必然的联系的。对于可变类型,如第一段代码,类属性控制着实例属性,实例属性只不过是复制了一份而已。对于不可变类型,实例属性和类属性是一起的,也就是说无论变动谁,另一方都会相应跟着改变。
命名空间
定义类时,所有位于class语句中的代码都是在某个命名空间中执行,即类命名空间。
命名空间因为对象的不同也有所区别,可以分为以下几种。
- 内置命名空间:Python运行起来,他们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们在任何程序中直接运行他们,比如前面的id()函数,不需要什么操作,拿过来就能使用。
- 全局命名空间:每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不互相干扰。
- 本地命名空间:模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间,如果函数返回了结果或者抛出了异常,则本地命名空间也就结束了。
继承
所谓继承就是将父类的方法和属性全部继承到子类中去;如果子类重写了父类的方法,就使用子类中的方法,父类中的方法将被掩盖。还有就是在多重继承中,遵循的是广度优先的原则。直接看代码:
#定义一个父类
class A(object):
#定义几个方法
def __init__(self):
pass
def speak(self):
print("I Love You")
def set_height(self, height):
print("the height is " , height)
def breast(self, n):
print("My Breast is:", n)
#定义一个子类继承父类的所有属性和方法
class Girl(A):
#重写父类的方法
def speak(self):
print("I Hate You")
if __name__=='__main__':
a = A()
b = Girl()
a.speak()
a.set_height(1.6)
a.breast(80)
b.speak()
b.set_height(1.8)
b.breast(120)
"""输出为
I Love You
the height is 1.6
My Breast is: 80
I Hate You
the height is 1.8
My Breast is: 120
"""
下面看一个多重继承的例子:
class A(object):
def eye(self):
print("two eyes")
def breast(self, size):
print("the breast is ", size)
class B(object):
age = 28
def color(self):
print("The girl is white")
class C(A, B):
pass
if __name__=='__main__':
c = C()
c.eye()
c.breast(80)
print(c.age)
c.color()
"""
输出为:two eyes
the breast is 80
28
The girl is white
"""
super函数:
如果子类和父类同时都有初始化方法,那么子类的初始化方法就会覆盖掉父类的初始化方法,super方法就可以使子类在初始化的时候调用父类的初始化方法。看代码:
class A(object):
def __init__(self):
self.height = 160
def about(self, name):
print("{0:} is about {1:}".format(name, self.height))
class Girl(A):
def __init__(self):
#调用父类的初始化函数,否则重写的方法中无法调用self.height这个属性,注意调用super的语法
#super(子类名, self).__init__()
super(Girl, self).__init__()
self.breast = 90
def about(self, name):
print("{0:} is about {1:}".format(name, self.height))
#调用父类的方法
super(Girl, self).about(name)
if __name__=='__main__':
a = Girl()
a.about("tom")
"""
输出为:tom is about 160
"""
方法
方法是类内部定义的函数,只不过这个函数的第一个参数是self,这个是默认的,也就是说所有类中的函数第一个参数都是self。
静态方法和类方法:
class StaticMethod(object):
@staticmethod
def foo():
print("this is static method")
class ClassMethod(object):
@classmethod
def bar(cls):
print("this is class method")
if __name__=="__main__":
static_foo = StaticMethod() #实例化
static_foo.foo() #实例调用静态方法
StaticMethod.foo() #通过类来调用静态方法
print('*'*50)
class_bar = ClassMethod()
class_bar.bar()
ClassMethod.bar()
"""
输出为:
this is static method
this is static method
**************************************************
this is class method
this is class method
"""
对于上面这段代码,包含了@符号,在Python中:
- @staticmethod表示下面的方法是静态方法
- @classmethod表示下面的方法是类方法
先看静态方法,虽然名为静态方法,但也是方法,所以依然用def进行定义。需要注意的是文件名后面的括号中没有self,这和前面定义的类中的方法有所不同。没有self,也就意味着无法访问实例变量、类和实例的属性了,因为他们都是通过self传递的。
类方法的参数是cls,这个参数是定义类方法必须要有的。在类方法中,能够访问类属性,但是不能访问实例属性。
两种方法都是要通过实例进行调用,也可以通过类来进行调用,这也是区别一般方法的地方,一般方法必须通过绑定实例来进行调用。
多态和封装
多态:是指在面向对象程序执行时,相同的信息可能会送给多个不同的类别的对象,系统可依据对象所属类别,引发对应类别的方法而有不同的行为。简单来说,多态就是指形同的信息给予不同的对象而引发不同的动作。
在Python中,著名的repr()函数就是多态的典型例子,它能够针对任何对象返回一个字符串。
def length(x):
print("The length of ", repr(x), "is", len(x))
length("how are you")
length([1, 2, 3])
"""
输出为:
The length of 'how are you' is 11
The length of [1, 2, 3] is 3
"""
下面再看一个多态的例子:
class Animal(object):
def __init__(self, name=""):
self.name = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print("MOW")
class Dog(Animal):
def talk(self):
print("WOW")
a = Animal()
a.talk()
#虽然都是talk方法,但是不同的对象调用就会有不同的输出结果,这就是多态的一种
c = Cat("Missy")
c.talk()
d = Dog("Rocky")
c.talk()
下面介绍封装:
封装就是将某些部分隐藏起来,在程序外边看不到,比如说类就是一种封装,我们在执行的时候有好多方法是看不到却可以直接进行调用的。
python中私有化也很简单,就是在准备私有化的属性(包括方法,数据)之前加上双下划线;看代码
class Protect(object):
def __init__(self):
self.me = "qiwsir"
self.__name = "kivi"
def __python(self):
print("i love python")
def code(self):
print("which language do you like ")
self.__python()
if __name__=="__main__":
p = Protect()
print(p.me)
#下面这句话会报错,因为定义name为私有属性,无法通过实例化对象进行访问
#私有属性和私有方法只能在类中进行调用
print(p.__name)
当然如果要调用某些私有属性怎么办?可以使用property函数,但是一般来说都是直接在类中定义一个调用函数,这样就可以通过调用函数来调用私有属性了。
特殊属性和方法
- 类名/实例对象.__dict__:显示类或者实例对象的所有属性和方法;
- __setattr__(self, name, value):如果要给name赋值,就调用这个方法;
- __getattr__(self, name):当name被访问,如果它不存在,此方法被调用;
- __getattribute__(self, name):当name被访问时自动被调用,无论name是否存在都会被调用;
- __delattr__(self, name):如果要删除name,这个方法就被调用;
class A(object):
def __getattr__(self, name):
print("you are use getattr")
def __setattr__(self, name, value):
print("you are use setattr")
#加上这一句话就是为了将value值赋值给实例属性name,否则只会调用这句话而不会进行赋值操作
self.__dict__[name] = value
a = A()
print(a.y)
a.y = 7
print(a.y)
花絮:property详解:
以下是property()函数的语法:
class property([fget[, fset[, fdel[, doc]]]])
- fget -- 获取属性值的函数
- fset -- 设置属性值的函数
- fdel -- 删除属性值函数
- doc -- 属性描述信息
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
#当调用c.x的时候自动调用getx函数,c.x = value时自动调用setx函数,del c.x时自动调用delx函数
x = property(getx, setx, delx, "I'm the 'x' property.")
c = C()
print(c.x)
c.x = 10
print(c.x)
del c.x
#输出为None,10