一、面向对象1
1-1、定义类
语法:
class 类名:
方法列表
# 定义类
class Car:
def getCarInfo(self):
# 定义属性,和Java等语言差别很大。
print('车轮子个数:%d, 颜色%s' % (self.wheelNum, self.color))
def move(self):
print("车正在移动...")
def toot(self):
print("车在鸣笛...嘟嘟..")
1-2、创建对象
# 创建对象
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4
BMW.getCarInfo()
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)
注意:
- BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法。
- 第一次使用BMW.color = '黑色'表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改
- BMW是一个对象,它拥有属性(数据)和方法(函数)
1-3、魔法函数
- 在python中方法名如果是_ _ xxxx _ _(self)的,那么就有特殊的功能,因此叫做“魔法”方法
- 当使用print输出对象的时候,只要自己定义了 _ _ str _ _(self)方法,那么就会打印从在这个方法中return的数据
1-3-1、构造方法: _ _ init _ _(self)
# 定义类
class Car:
# 构造方法
def __init__(self):
print "__init__方法"
self.wheelNum = 8
self.color = '蓝色'
def getCarInfo(self):
# 定义属性,和Java等语言差别很大。
print('车轮子个数:%d, 颜色%s' % (self.wheelNum, self.color))
# 方法
def move(self):
print("车正在移动...")
def toot(self):
print("车在鸣笛...嘟嘟..")
# 创建对象
BMW = Car()
BMW.getCarInfo()
注意:
-
init()方法,在创建一个对象时默认被调用,不需要手动调用
-
init(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
-
init(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去
1-3-2、_ _ str_ _(self)方法
# 定义类
class Car:
# 构造函数
def __init__(self, newWheelNum, newColor):
self.wheelNum = newWheelNum
self.color = newColor
# 类似Java中的toString()方法
def __str__(self):
msg = "嘿。。。我的颜色是" + self.color + "我有" + str(self.wheelNum) + "个轮胎..."
return msg
def move(self):
print('车在跑,目标:夏威夷')
BMW = Car(4, "白色")
print(BMW)
1-4、self
魔法函数中的self参数
- 所谓的self,可以理解为自己
- 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思
- 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可
二、面向对象2
2-1、私有属性
如果有一个对象,当需要对其进行修改属性时,有2种方法
对象名.属性名 = 数据 ---->直接修改
对象名.方法名() ---->间接修改
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
将属性定义为私有属性
添加一个可以调用的方法,供调用
class People(object):
def __init__(self, name):
# 声明私有属性,类似Java中的private
self.__name = name
def getName(self):
return self.__name
def setName(self, newName):
if len(newName) >= 5:
self.__name = newName
else:
print("error:名字长度需要大于或者等于5")
xiaoming = People("dongGe")
print(xiaoming.__name)
# 执行报错
2-2、_ _ del _ _(self)方法
- 创建对象后,python解释器默认调用_ _ init _ _()方法;
- 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为 _ _ del _ _()方法。当对象被销毁,例如内存被释放或程序结束时,会自动被调用,类似OC的dealloc()方法。
- del 对象:类似OC的release()方法,让引用计数 -1,此时引用计数为1
import time
class Animal(object):
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.__name = name
# 析构方法
# 当对象被销毁,例如内存被释放或程序结束时,会自动被调用,类似OC的dealloc()方法
def __del__(self):
print("%s对象被干掉了..." % self.__name)
def move(self):
print("%s对象在移动" % self.__name)
# 引用计数为1
cat = Animal("波斯猫")
# 引用计数为2
cat1 = cat
# 类似OC的release()方法,让引用计数 -1,此时引用计数为1
del cat
# 调用完del方法后,cat指针指向的对象引用计数 -1,cat指针被释放,再次使用会报错
# del cat
# cat.move()
# 报错,cat指针已经被销毁了
# 类似OC的release()方法,让引用计数 -1,此时引用计数为0,对象释放,会在此时调用_ _ del _ _方法。如果注释下面代码,则cat对象会在程序结束后释放。
del cat1
print("程序2秒钟后结束,所以内存中的对象都会被释放")
time.sleep(2)
2-3、单继承
- 子类在继承的时候,在定义类时,小括号()中为父类的名字
- 父类的属性、方法,会被继承给子类
- 私有的属性,不能通过对象直接访问,但是可以通过方法访问
- 私有的方法,不能通过对象直接访问
- 私有的属性、方法,不会被子类继承,也不能被访问
- 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
class Animal(object):
def __init__(self, name="动物", color="白色"):
self.__name = name
self.color = color
def __test(self):
print self.__name
print self.color
def test(self):
print self.__name
print self.color
class Dog(Animal):
def dogTest1(self):
print self.__name # 不能访问到父类的私有属性
print self.color
def dogTest2(self):
self.__test() # 不能访问父类中的私有方法
self.test()
A = Animal()
print(A.__name) # 程序出现异常,不能访问私有属性
print(A.color)
A.__test() # 程序出现异常,不能访问私有方法
A.test()
D = Dog(name="旺财", color="黄色")
D.dogTest1()
D.dogTest2()
2-4、多继承
- Python和C++一样支持多继承
# 定义一个父类
class A:
def printA(self):
print('----A----')
# 定义一个父类
class B:
def printB(self):
print('----B----')
# 定义一个子类,继承自A、B
class C(A, B):
def printC(self):
print('----C----')
obj_C = C()
obj_C.printA()
obj_C.printB()
obj_C.printC()
- 有多个父类的同名方法时,调用同名方法时,方法的调用顺序和多继承的顺序有关系
- pass关键字来进行占位,让代码不要报错先能正常运行
#! /usr/bin/env python
# -*- coding: utf-8 -*-
class base(object):
def test(self):
print('----base test----')
class A(base):
def test(self):
print('----A test----')
# 定义一个父类
class B(base):
def test(self):
print('----B test----')
# 定义一个子类,继承自A、B
class C(A, B):
# pass关键字来进行占位,让代码不要报错先能正常运行
pass
# def test(self):
# print('----C test----')
obj_C = C()
obj_C.test()
print(C.__mro__) # 可以查看C类的对象搜索方法时的先后顺序。注意和继承的父类顺序有关系
# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.base'>, <type 'object'>)
2-5、重写父类方法与调用父类方法
2-5-1、重写父类方法
所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法。
class Cat(object):
def sayHello(self):
print("Cat--sayHello")
class Bosi(Cat):
def sayHello(self):
print("Bosi--sayHello")
bosi = Bosi()
bosi.sayHello()
# Bosi--sayHello
2-5-2、调用父类的方法
*方法1(Python2)
def __init__(self, name):
# 调用父类的__init__方法1(Python2)
Cat.__init__(self, name)
- 方法2(Python2)
def __init__(self, name):
# 调用父类的__init__方法2(Python2)
super(Bosi, self).__init__(name)
- 方法3(Python3)
def __init__(self, name):
# 调用父类的__init__方法3(Python3)
super().__init__(name)
示例
# coding=utf-8
class Cat(object):
def __init__(self, name):
self.name = name
self.color = 'yellow'
class Bosi(Cat):
def __init__(self, name):
# 调用父类的__init__方法1(python2)
# Cat.__init__(self, name)
# 调用父类的__init__方法2(python2)
super(Bosi, self).__init__(name)
# 调用父类的__init__方法3(python3)
# super().__init__(name)
self.color = 'green'
def getName(self):
return self.name
bosi = Bosi('xiaohua')
print(bosi.name)
print(bosi.color)
2-6、多态
多态的概念是应用于Java和OC这一类强类型语言中,而Python崇尚“鸭子类型”。所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。简单来说就是父类指针指向子类对象。
class F1(object):
def show(self):
print 'F1.show'
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
def Func(obj):
print obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
2-7、类属性和实例属性
- 实例属性:也就是对象属性,某一个对象所拥有的属性,通过对象可以访问到各自的实例属性。
- 类属性:顾名思义就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,和Java/C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象或者实例对象访问。
2-7-1、类属性
class People(object):
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = People()
print(p.name) #正确,可以通过实例对象来访问类属性。
print(People.name) #正确,可以通过类对象来访问类属性。
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
2-7-2、实例属性(对象属性)
class People(object):
address = '山东' #类属性
def __init__(self):
self.name = 'xiaowang' #实例属性
self.age = 20 #实例属性
p = People()
p.age =12 #实例属性
print(p.address) #正确,可以通过实例对象访问类属性
print(p.name) #正确,可以通过实例对象访问自己的实例属性
print(p.age) #正确,可以通过实例对象访问自己的实例属性
print(People.address) #正确,可以通过类对象访问类属性
print(People.name) #错误,不能通过类对象访问实例属性
print(People.age) #错误,不能通过类对象访问实例属性
2-7-3、通过实例(对象)去修改类属性的坑!!!
- 如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。看下面例子:
class People(object):
country = 'china' # 类属性
print("1" + People.country)
p = People()
print("2" + p.country)
p.country = 'japan' # 一定要注意,这句代码相当于是给p对象添加一个实例属性!!!类似下面
p.name = 'cehae' #给p对象添加一个name实例属性
print("3" + p.country) # 实例属性会屏蔽掉同名的类属性,此时访问的是上面添加的country实例属性
print("4" + People.country)
print("5" + p.country)
del p.country # 删除实例属性
print("6" + p.country) # 删除实例属性后,此时访问的是类属性
2-8、类方法和静态方法
2-8-1、类方法
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。
class People(object):
country = 'china'
# 类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
@classmethod
def setCountry(cls, country):
cls.country = country
p = People()
print p.getCountry() # 可以用实例对象来调用类方法
# china
print People.getCountry() # 可以用类对象来调用类方法
# china
p.setCountry('japan') # 可以用实例对象来调用类方法
People.setCountry('us') # 可以用类对象来调用类方法
print p.getCountry() # 可以用实例对象来调用类方法
# us
print People.getCountry() # 可以用类对象来调用类方法
# us
2-8-2、静态方法
静态方法是指类中无需实例参与即可调用的方法(不需要self参数),在调用过程中,无需将类实例化,直接在类之后使用.号运算符调用方法。
通常情况下,静态方法使用@staticmethod装饰器来声明。
示例代码:
class ClassA(object):
@staticmethod
def func_a():
print('Hello Python')
if __name__ == '__main__':
ClassA.func_a()
# 也可以使用实例调用,但是不会将实例作为参数传入静态方法
ca = ClassA()
ca.func_a()
这里需要注意的是,在Python 2 中,如果一个类的方法不需要self参数,必须声明为静态方法,即加上@staticmethod装饰器,从而不带实例调用它。
而在Python 3中,如果一个类的方法不需要self参数,不再需要声明为静态方法,但是这样的话只能通过类去调用这个方法,如果使用实例调用这个方法会引发异常。
class ClassA(object):
def func_a():
print('Hello Python')
if __name__ == '__main__':
ClassA.func_a()
# 以下使用实例调用会引发异常
ca = ClassA()
ca.func_a()
异常信息:
func_a() takes 0 positional arguments but 1 was given
因为func_a没有声明为静态方法,类实例在调用func_a时,会隐式地将self参数传入func_a,而func_a本身不接受任何参数,从而引发异常。
2-8-3、静态方法/类方法/实例方法的总结
Python静态方法/类方法/实例方法的总结1
Python静态方法/类方法/实例方法的总结2
-
1.实例方法:第一个参数强制为实例对象,可以通过这个实例对象访问实例属性,可以通过实例对象的_ _ class _ _属性访问类属性。只能使用实例对象调用实例方法。
-
2.类方法:类方法的第一个参数强制为类对象,可以通过这个类对象访问类属性,由于没有传入实例对象,不能访问实例属性。可以使用类对象和实例对象来调用类方法。
-
3.静态方法:没有默认的第一个参数,其实跟类没什么关系,只是绑定在类命名空间下的函数而已。可以使用类对象和实例对象来调用静态方法。
-
4.同时出现三者同名的方法,调用时以最后声明的为准!!!
class People(object):
country = 'china'
# 实例方法,Python2中实例方法必须带有self参数
def getCountry(self):
print "实例方法"
return People.country
# 静态方法,用staticmethod来进行修饰
@staticmethod
def getCountry():
print "静态方法"
return People.country
# 类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
print "类方法"
return cls.country
p = People()
print p.getCountry()
print People.getCountry()
2-9、延伸:Java/OC中的类方法/实例方法,类属性/对象属性
- Java/OC中的静态方法就是类方法,静态属性就是类属性。
- Java/OC中的实例方法也称对象方法。
Java类方法和实例方法
OC类方法和实例方法
OC静态变量