一、定义类
定义一个类,格式如下:
class 类名(object):
属性列表
方法列表
demo:定义一个Car类
class Car(object):
# 属性
wheelNum = 2
color = 'red'
# 方法
def getCarInfo(self):
print('车轮子个数:%d, 颜色%s'%(self.wheelNum, self.color))
二、创建对象
创建对象的格式为:
对象名 = 类名()
BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法了(BMW.wheelNum)
打印创建的类:
print(BWM)
<__main__.Carobject at 0x000000000212EE48>
可以获得这个类在内存中的地址(十六进制的数字)
三、属性
1、公有属性:
在类中我们可以定义一些属性,比如:
class people:
name = 'Tom'
age = 12
p = people()
print("name=%s, age=%d"%(p.name,p.age))
定义了一个people类,里面定义了name和age属性,默认值分别为’Tom’和12。
在定义了类之后,就可以用来产生实例化对象了,这句p = people( )实例化了一个对象p,然后就可以通过p来读取属性了。这里的name和age都是公有的,可以直接在类外通过对象名访问,如果想定义成私有的,则需在前面加2个下划线 即’__’
2、私有属性
class people:
__name = 'Tom'
__age = 12
p = people()
print("name=%s, age=%d"%(p.name,p.age))
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。
3、类内公有方法调用私有属性
但是如果外部代码要获取name和age怎么办?可以给people类增加get_name和get_age这样的
class Student(object):
...
def set_name(self, name):
self.__name= name
def set_age(self, age):
self.__age= age
用类内公有的方法调用私有属性,这样可以对参数做检查,避免传入无效的参数:
class People(object):
...
def set_age(self, score):
if 0 <= name<= 120:
self.__age= age
else:
raise ValueError('bad age')
四、方法
要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:
下面看个例子:
class people:
__name = 'Tom'
__age = 12
def getName(self):
return self.__name
def getAge(self):
return self.__age
p = people()
print p.getName(),p.getAge()
可以用公有的方法调用私有属性,解决私有属性不能再类外直接调用问题
五、 self
(每个类中的方法都要写self)
看如下示例:
# 定义一个类
class Animal:
# 方法
def setName(self, name):
self.name = name
def printName(self):
print '名字为:', self.name
# 定义一个函数
def myPrint(animalName):
animalName.printName()
dog1 = Animal()
dog1.setName('西西')
myPrint(dog1)
dog2 = Animal()
dog2.setName('北北')
myPrint(dog2)
运行结果:
self
小总结
所谓的self,可以理解为自己
可以把它当做C++中类里面的this指针一样理解,就是对象自身的意思,在用某个对象
调用该方法时,就将该对象作为第一个参数传递给self。
六、魔法方法
1、 构造方法:在创建一个对象时默认被调用,不需要手动调用
__init__()
方法是在创建对象后,被默认执行
在创建完对象后init()方法已经被默认的执行了,那么让对象在默认调用init()方法的时候传递一些参数 ,就需要在创建对象时将参数带入
注意到init方法的第一个参数永远是self,表示创建的实例本身,因此,在init方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了init方法,在创建实例的时候,就不能传入空的参数了,必须传入与init方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
看例子:
# 定义类
class Car:
# 构造器方法
def __init__(self, newWheelNum, newColor):
self.wheelNum = newWheelNum
self.color = newColor
# 方法
def run(self):
print ('车在跑,目标:夏威夷')
创建对象
BMW = Car(4, 'green')
print ('车的颜色为:',BMW.color)
print ('车轮子数量为:',BMW.wheelNum)
结果为:
车的颜色为: green
车轮子数量为: 4
2、__str__
3、__del__
:析构方法
创建对象时,默认调用构造方法;当删除一个对象时,同样也会默认调用一个方法,这个方法为析构方法
demo:
class Animal():
# 构造方法
def __init__(self):
print '---构造方法被调用---'
# 析构方法
def __del__(self):
print '---析构方法被调用---'
# 创建对象
dog = Animal()
# 删除对象
del dog
---构造方法被调用---
---析构方法被调用---
注意:当对一个类创建了多个对象时,所有的对象都被删除,析构方法才会被执行
4、__name__
属性,可以拿到函数的名字:
七、继承和多态
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
1、单继承
- 子类在继承的时候,在定义类时,小括号()中为父类的名字
- 父类的属性、方法,会被继承给子类
- 虽然子类,没有构造方法,但是父类有,所以在子类继承父类的时候,其构造方法也会被继承,所以只要创建Bosi的实例对象,就默认执行了那个继承过来的构造方法
比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:
class Animal(object):
def run(self):
print 'Animal is running...'
当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:
class Dog(Animal):
pass
class Cat(Animal):
pass
对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
继承有什么好处?最大的好处是子类获得了父类的全部功能。由于Animial实现了run()方法,因此,Dog和Cat作为它的子类,什么事也没干,就自动拥有了run()方法:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
运行结果如下:
Animal is running...
Animal is running...
当然如果创建的对象觉得父类中的方法不能满足要求时,可以对父类方法进行重写:
class Dog(Animal):
def run(self):
print("dog is run...")
class Cat(Animal):
def run(self):
print("cat is run ....")
dog = Dog()
dog.run()
cat = Cat()
cat.run()
运行结果如下:
dog is running...
cat is running...
当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。我们说这个过程是子类重写父类,并且我们也获得了继承的另一个好处:多态。
要理解什么是多态,我们首先要对数据类型再作一点说明。当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
a = list() # a是list类型
b = Animal() # b是Animal类型
c = Dog() # c是Dog类型
在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
Dog可以看成Animal,但Animal不可以看成Dog。
2、多继承
那么一个子类可不可以有多个父类,就像你既继承了母亲的遗产,又继承了父亲的遗产,在python中也可以继承多个类
- python中是可以多继承的
- 父类中的方法、属性,子类会继承
Python中多继承的格式如下:
# 定义一个父类
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()
运行结果:
----A----
----B----
如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?
在python3中,所执行的是广度调用,而且调用的顺序是从左到右,先去父类A中找,如果没有再去父类B中找,如果AB都没找到,程序会抛出异常
继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写;
有了继承,才能有多态。在调用类实例方法的时候,尽量把变量视作父类类型,这样,所有子类类型都可以正常被接收;
旧的方式定义Python类允许不从object类继承,但这种编程方式已经严重不推荐使用。任何时候,如果没有合适的类可以继承,就继承自object类。
一个类继承多个类,当调用一个方法时,会有个搜索的顺序,可以用 创建的对象.__mro__
来查看,他搜索的顺序
设计类时,尽可能不要出现相同的方法
多态补充
class Dog(object):
def print_self(self):
print("大家好,我是xxxx,希望以后大家多多关照....")
class Xiaotq(Dog):
def print_self(self):
print("hello everybody, 我是你们的老大,我是xxxx")
def introduce(temp):
temp.print_self()
dog1 = Dog()
dog2 = Xiaotq()
introduce(dog1)
introduce(dog2)
八、 类属性、实例属性
在了解了类基本的东西之后,下面看一下python中这几个概念的区别
先来谈一下类属性和实例属性
在前面的例子中我们接触到的就是类属性,顾名思义,
1、类属性
类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问
类属性一般写在class里面,del(方法)外面,可以直接:类名.类属性名
调用
class people:
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = people()
print p.name #正确
print people.name #正确
print p.__age #错误,不能在类外通过实例对象访问私有的类属性
print people.__age #错误,不能在类外通过类对象访问私有的类属性
2、实例属性
实例属性写在 del 内,必须实力化类之后才可以被实例化之后的对象调用
实例属性是不需要在类中显示定义的,比如:
在类外对类对象people进行实例化之后,产生了一个实例对象p,然后p.age = 12这句给p添加了一个实例属性age,赋值为12。这个实例属性是实例对象p所特有的,注意,类对象people并不拥有它(所以不能通过类对象来访问这个age属性)。当然还可以在实例化对象的时候给age赋值。
class people:
name = 'Tom'
#__init__()是内置的构造方法,在实例化对象时自动调用
def __init__(self,age):
self.agep = people(12)
print p.name #正确
print p.age #正确
print people.name #正确
print people.age #错误
外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
class people:
country = 'china'
print people.country
p = people()
print p.country
p.country = 'japan'
print p.country #实例属性会屏蔽掉同名的类属性
print people.country
del p.country #删除实例属性
print p.country
注意:
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
总结
实例属性属于各个实例所有,互不干扰;
类属性属于类所有,所有实例共享一个属性;
不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
类方法
https://www.cnblogs.com/scolia/p/5598114.html
类三种方法语法形式
class Foo(object):
"""类三种方法语法形式"""
def instance_method(self):
print("是类{}的实例方法,只能被实例对象调用".format(Foo))
@staticmethod
def static_method():
print("是静态方法")
@classmethod
def class_method(cls):
print("是类方法")
foo = Foo()
foo.instance_method()
foo.static_method()
foo.class_method()
print('----------------')
Foo.static_method()
Foo.class_method()
作者:python爱好者
链接:https://www.jianshu.com/p/212b6fdb2c50
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
九、调用被重写的方法
class Animal:
def eat(self):
print("-----吃----")
def drink(self):
print("-----喝----")
def sleep(self):
print("-----睡觉----")
def run(self):
print("-----跑----")
class Dog(Animal):
def bark(self):
print("----汪汪叫---")
class Xiaotq(Dog):
def fly(self):
print("----飞----")
def bark(self):
print("----狂叫-----")
#第1种调用被重写的父类的方法
#Dog.bark(self)
#第2种
super().bark()
xiaotq = Xiaotq()
xiaotq.fly()
xiaotq.bark()
xiaotq.eat()