面向对象编程(Object Oriented Programing,OOP)是一种编程思想,OOP把对象当成程序的一个基本单元,一个对象包含数据和操做数据的方法。面向对象编程的三大特性以下:python
A、封装,能够隐藏实现细节,使代码模块化。mysql
B、继承,能够经过扩展已存在的类来实现代码重用,避免重复编写相同的代码。算法
C、多态,封装和继承的目的都是为了实现代码重用, 而多态是为了实现接口重用,使得类在继承和派生的时候可以保证任何一个类的实例都能正确调用约定好的属性和方法。sql
面向对象编程经过封装、继承、多态实现了软件工程的重用性、灵活性、扩展性三个目标。编程
类(Class)是用来描述具备相同的属性和方法的对象的集合,定义了集合中每一个对象所共有的属性和方法。ide
对象是类的实例,Python中对象包括两个数据成员(类变量和实例变量)和方法。模块化
方法是类中定义的函数。函数
类变量在类的全部实例化对象中是公用的。类变量定义在类中且在函数体外。工具
方法重写:若是从父类继承的方法不能知足子类的需求,能够对其进行重写(override)。学习
继承是一个派生类(derived class)继承基类(base class)的字段和方法。继承容许把一个派生类的对象做为一个基类对象对待。
实例化:建立一个类的实例,类的具体对象。
在python当中一切皆对象,每一个对象都有三个属性:id、类型type和数值。id是对象的地址,id相同则必为同一对象,不一样对象的值能够相同。
在学习过程当中有什么不懂得能够加个人 python学习交流扣扣qun,784-758-214 群里有不错的学习视频教程、开发工具与电子书籍。 与你分享python企业当下人才需求及怎么从零基础学习好python,和学习什么内容 # -*- coding:utf-8 -*- x = 10 print(id(x)) print(type(x)) # <class 'int'> print(x) y = 10 print(id(y)) print(type(y)) # <class 'int'> print(y) print(x is y) # True
类是一种抽象数据类型,是对现实世界的一类数据及其操做的封装。
类定义语法格式以下:
class ClassName: <statement-1> . . . <statement-N>
类实例化后,可使用其属性,建立一个类后,能够经过类名访问其类属性。
Person类有如下3个属性:
nationality:国籍
name:姓名
id:×××号码
import uuid class Person: nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id))
全部人的国籍基本都是相同的,且容许直接经过类或实例来访问,容许随意修改。
大部分人的姓名是不一样的,且容许直接经过类的实例来访问和随意修改。
全部人的×××号码都是不同的,且不容许直接经过类或实例来访问或随意修改。
import Person bauer = Person.Person("Bauer") bauer.hello()
Python中默认全部的成员都是公有成员,但私有成员是以两个下划线开头的名字表示私有成员,私有成员不容许直接访问,只能经过内部方法进行访问,私有成员也不容许被继承。
Python中经过在类变量、实例变量、类方法、实例方法前加__
前缀,能够将其对外进行隐藏,变为类的私有变量或函数。因为Python中内置变量或函数使用__
先后缀,所以,不推荐私有的变量或函数加__
先后缀,只加__
前缀。
Python做为动态语言,容许类或实例动态增长属性,与类内部的私有的属性并不相同。
Python类维护了一个用于保存类的数据的字典,字典内部Python将私有成员更名为_ClassName + __variable_name
,所以在类外经过访问私有变量新的名称能够访问相应的私有变量。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") print(bauer.__dict__) print(bauer._Person__id) """ output: {'name': 'Bauer', '_Person__id': 'ed496846-94c7-11e9-80c4-5ce0c5e8bcf0'} ed496846-94c7-11e9-80c4-5ce0c5e8bcf0 """
直接定义在class下的属性是公有属性/类属性,类属性是类的全部实例对象共同全部的,所以默认状况下类属性值只会保留一份,而不会为类的每一个实例都保存一份。
类属性可使用ClassName.VariableName访问,在实例方法内部也可使用self.__class__.VariableName
进行访问。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def sayHello(self): print("Hello,I come from %s" % self.__class__.nationality) if __name__ == "__main__": bauer = Person("Bauer") bauer.sayHello() jack = Person("Jack") print(Person.nationality, bauer.nationality, jack.nationality) bauer.nationality = "USA" print(Person.nationality, bauer.nationality, jack.nationality) Person.nationality = "Germany" print(Person.nationality, bauer.nationality, jack.nationality) """ output: Hello,I come from China China China China China USA China Germany USA Germany """
类属性能够经过类直接访问,也能够直接经过实例进行访问; 若是经过类的某个实例对类属性进行修改,本质上是为该实例添加了一个与类属性名称相同的实例属性,对真正的类属性没有影响,所以不会影响其它实例获取类属性的值; 经过类对类属性进行修改,必然会改变类属性的值,对类的全部实例是都有影响的。
实例属性又称成员属性或成员变量,是类的每一个实例对象单独持有的属性。实例属性必须在类的init方法中进行声明。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") jack = Person("Jack") print(bauer.name, jack.name) bauer.name = "Jack Bauer" jack.name = "Chen Jack" print(bauer.name, jack.name) #print(Person.name) ## AttributeError: type object 'Person' has no attribute 'name' """ output: Bauer Jack Jack Bauer Chen Jack """
经过类访问成员属性会报错:
print(Person.name)
实例属性能够直接经过实例对象来访问和更改,是每一个实例对象独有的,某个实例对象的实例属性被更改不会影响其它实例对象的相同属性的值。实例属性的值不能经过类来访问和修改。
Python做为动态语言,能够在类外部动态增长实例对象的属性。
私有属性和实例属性必须在__init__
方法中进行声明,但私有属性的属性名须要以双下划线__
开头,好比Person中的__id
属性。私有属性是一种特殊的实例属性,只容许在实例对象的内部(成员方法或私有方法中)访问,而不容许在实例对象的外部经过实例对象或类来直接访问,也不能被子类继承。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") bauer.hello() # print(bauer.__id) # AttributeError: 'Person' object has no attribute '__id' # print(Person.__id) # AttributeError: type object 'Person' has no attribute '__id' """ output: Hello, I am Bauer, I come from China, My ID is c0c02dcc-94aa-11e9-972c-5ce0c5e8bcf0 """
私有属性不能经过类直接访问,也不能经过实例对象直接访问,但私有属性能够经过成员方法进行访问。
私有属性能够经过成员方法或是实例对象._类名__私有变量名
的方式来访问。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def get_id(self): return self.__id if __name__ == "__main__": bauer = Person("Bauer") bauer.hello() print(bauer._Person__id) print(bauer.get_id()) """ output: Hello, I am Bauer, I come from China, My ID is c0c02dcc-94aa-11e9-972c-5ce0c5e8bcf0 354547ae-94ab-11e9-a52c-5ce0c5e8bcf0 354547ae-94ab-11e9-a52c-5ce0c5e8bcf0 """
Python的类中有一些内置的、特殊的属性,其名称以双下划线__
开头且以双下划线__
结尾。特殊属性不是私有属性,能够在类的外部经过实例对象去直接访问,且都有着各自特殊的意义。
__doc__
表示类的描述信息。
__module__
表示当前操做的对象对应的类的定义所在的模块名。
__class__
表示当前操做的对象对应的类名。
__dict__
是一个字典,保存类的全部的成员(包括属性和方法)或实例对象中的全部成员属性。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def __hello(self): # 私有方法 print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def say_hello(self): # 成员方法/实例方法 self.__hello() @classmethod def get_nationality(cls): # 类方法 return cls.nationality @staticmethod def add(a, b): # 静态方法 return a + b @property def id(self): return self.__id if __name__ == "__main__": bauer = Person("Bauer") print("Person Object") print(bauer.__class__) print(bauer.__doc__) print(bauer.__dict__) print(bauer.__module__) print("Person Class") print(Person.__class__) print(Person.__doc__) print(Person.__dict__) print(Person.__module__) """ output: Person Object <class '__main__.Person'> None {'name': 'Bauer', '_Person__id': 'f545f99a-94b5-11e9-aa3f-5ce0c5e8bcf0'} __main__ Person Class <class 'type'> None {'__module__': '__main__', 'nationality': 'China', '__init__': <function Person.__init__ at 0x7f49941d5d90>, '_Person__hello': <function Person.__hello at 0x7f49941d5e18>, 'say_hello': <function Person.say_hello at 0x7f49941d5ea0>, 'get_nationality': <classmethod object at 0x7f499b470be0>, 'add': <staticmethod object at 0x7f499b470c18>, 'id': <property object at 0x7f499b464908>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None} __main__ """
实例对象.__dict__
和 类.__dict__
的值是不一样的,实例对象.__dict__
的值中只包含成员属性和私有属性,类.__dict__
的值中包含类的类属性和全部方法;
__module__
和__class__
的值可用于反射来实例化一个类的对象。
成员方法经过类的实例对象去访问,第一个参数必须是当前实例对象,一般写为self;但也能够经过类名来调用成员方法,此时须要手动的传递一个类的实例对象给成员方法的self参数。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") bauer.hello() Person.hello(bauer) """ output: Hello, I am Bauer, I come from China, My ID is 0e4d0606-94af-11e9-a958-5ce0c5e8bcf0 Hello, I am Bauer, I come from China, My ID is 0e4d0606-94af-11e9-a958-5ce0c5e8bcf0 """
私有方法是以双下划线开头的成员方法。私有方法只能在实例方法内部访问,且不能被子类继承;私有方法的第一个参数也必须是当前实例对象自己,一般写为self。一般,先后加双下划线的命名方式用于Python内置的方法,不推荐自定义方法使用。若是开发者之前后加双下划线的方式命名成员方法,则相应成员方法是公有的。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def __hello(self): # 私有方法 print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def say_hello(self): # 成员方法/实例方法 self.__hello() if __name__ == "__main__": bauer = Person("Bauer") bauer.say_hello() """ output: Hello, I am Bauer, I come from China, My ID is 0e4d0606-94af-11e9-a958-5ce0c5e8bcf0 """
类方法是以@classmethod
来装饰的成员方法,类方法要求第一个参数必须是当前类。类方法可经过实例对象进行访问,还能够直接经过类名去访问,且第一个参数表示的是当前类,一般写为cls。类方法只能访问类属性,不能访问实例属性,所以第一个参数传递的是表明当前类的cls,而不是表示实例对象的self。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def __hello(self): # 私有方法 print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def say_hello(self): # 成员方法/实例方法 self.__hello() @classmethod def get_nationality(cls): # 类方法 return cls.nationality if __name__ == "__main__": bauer = Person("Bauer") print(bauer.get_nationality()) print(Person.get_nationality()) """ output: China China """
静态方法是以@staticmethod
来装饰的成员方法,静态方法一般经过类名进行访问,也能够经过类的实例对象进行访问。本质上,静态方法已经与类没有任何关联,由于静态方法不要求必须传递实例对象或类参数。
静态方法内部能够访问类变量,能够直接使用ClassName.Varaible_Name
方式对类变量进行访问。
静态方法对参数没有要求,所以能够任意给静态方法定义参数,若是给静态方法定义表示当前类的参数,那么就能够访问类属性;若是给静态方法定义了表示当前类的实例对象的参数,那么就能够访问实例属性;若是没有给静态方法定义当前类参数或当前实例参数,那么就不能访问类或实例对象的任何属性。
import uuid class Person(object): sum = 0 nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) Person.sum += 1 def __hello(self): # 私有方法 print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def say_hello(self): # 成员方法/实例方法 self.__hello() @classmethod def get_nationality(cls): # 类方法 return cls.nationality @staticmethod def add(a, b): # 静态方法 return a + b @staticmethod #静态方法,内部使用类变量 def counter(): return Person.sum @staticmethod def get_counter(cls): #静态方法,传递当前类 return cls.sum if __name__ == "__main__": bauer = Person("Bauer") print(bauer.add(1, 2)) print(Person.add(1, 2)) print(Person.counter()) print(Person.get_counter(Person)) """ output: 3 3 1 1 """
属性方法是以@property
来装饰的成员方法,是以访问实例属性的方式对实例属性进行访问的成员方法;属性方法第一个参数必须是当前实例对象,且属性方法必需要有返回值。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def __hello(self): # 私有方法 print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) def say_hello(self): # 成员方法/实例方法 self.__hello() @classmethod def get_nationality(cls): # 类方法 return cls.nationality @staticmethod def add(a, b): # 静态方法 return a + b @property def id(self): return self.__id if __name__ == "__main__": bauer = Person("Bauer") print(bauer.id) # print(bauer.id()) # TypeError: 'str' object is not callable """ output: 631baef4-94b3-11e9-babe-5ce0c5e8bcf0 """
Python中属性方法一般用于在属性方法内部进行一系列的逻辑计算,最终将计算结果返回。
类内部定义的方法,在没有被任何装饰器修饰的状况下,是为了绑定到对象的,self关键字含有自动传值的过程,无论写不写self。 默认状况下,在类内部定义的方法都是绑定到对象的方法。 绑定方法绑定到谁的身上,谁就做为第一个参数进行传入,绑定到类的方法给对象使用是没有任何意义的。
绑定到对象的方法,调用的时候会将对象参数自动传入;绑定到类的方法,调用的时候会将类做为参数自动传入。
静态方法是非绑定方法,不与类或对象绑定,谁均可以调用,没有自动传值效果。非绑定方法不与类或对象绑定,类和对象均可以调用,但没有自动传值。
# -*- coding:utf-8 -*- import time import hashlib import pickle import os """ HOST = "127.1.1.1" PORT = 3306 DB_PATH = r"/usr/lib/mysql/db" """ class MySQL: HOST = "127.1.1.1" PORT = 3306 DB_PATH = r"/var/lib/mysql" @staticmethod def create_id(): m = hashlib.md5(str(time.perf_counter()).encode("utf-8")) return m.hexdigest() def __init__(self,host,port): self.id = self.create_id() self.host = host self.port = port @classmethod def from_conf(cls): return cls.HOST, cls.PORT def save(self): file_path = r"%s%s%s"%(MySQL.DB_PATH,os.sep,self.id) #将对象以二进制的形式写到磁盘 pickle.dump(self,open(file_path,"wb")) def get(self): file_path = r"%s%s%s" % (MySQL.DB_PATH, os.sep, self.id) return pickle.load(open(file_path,"rb")) if __name__ == '__main__': conn1 = MySQL("127.0.0.1","3306") print(conn1.id) conn1.save() result = conn1.get() print(result.id)
Python的类中有一些内置的、特殊的方法,其名称是以双下划线__
开头且以双下划线__
结尾。特殊方法不是私有方法,能够在类的外部经过实例对象去直接访问,且都有着各自特殊的意义。
__init__
方法是类构造函数,是类的特殊的方法,在建立类对象时自动调用,不能有返回值。定义以下:
def __init__(self): pass
__init__
方法的第一个参数必须是建立的实例自己,一般推荐使用self。类的实例属性、私有属性必须在__init__
方法进行声明。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) print(self.name, "__init__") if __name__ == "__main__": bauer = Person("Bauer") """ output: Bauer __init__ """
__del__
是类的析构方法,当对象在内存中被释放,会自动触发执行__del__
方法,如实例对象的做用域退出时,或者执行 del 实例对象操做时。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) print(self.name, "__init__") def __del__(self): print(self.name, "__del__") if __name__ == "__main__": bauer = Person("Bauer") del bauer """ output: Bauer __init__ Bauer __del__ """
若是类中定义了__str__
方法,那么在打印对象时默认输出__str__
方法的返回值,不然会打印出实例对象的内存地址。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) print(self.name, "__init__") def __del__(self): print(self.name, "__del__") def __str__(self): return "name: %s, nationality: %s, id: %s" % (self.name, self.nationality, self.__id) if __name__ == "__main__": bauer = Person("Bauer") print(bauer) """ output: Bauer __init__ name: Bauer, nationality: China, id: 0a9a80c2-94c0-11e9-891d-5ce0c5e8bcf0 Bauer __del__ """
__setitem__
、__getitem__
、__delitem__
用于索引操做,如对字典的操做,分别表示设置、获取、删除某个条目、数据。能够经过__setitem__
,__getitem__
、__delitem__
方法来定义一个类对字典进行封装,从而能够对字典中key的操做进行控制,尤为是删除操做。
若是一个类实现了__setitem__
,__getitem__
、__delitem__
方法,就能够执行一些字典操做。
class ChineseDict(object): def __init__(self, init=None): self.__dict = init if init is not None else {} def __setitem__(self, key, value): print('__setitem__', key) self.__dict[key] = value def __getitem__(self, item): print('__getitem__', item) return self.__dict.get(item, None) def __delitem__(self, key): print('__delitem__', key) if key is not None and key.startswith('wh'): print('You can not delete this item ') return None return self.__dict.pop(key, None) if __name__ == "__main__": dic = ChineseDict(init={'name': 'Bauer', 'nationality': 'China', "age": 23}) print(dic["name"], dic["nationality"], dic["age"]) del dic["age"] print(dic["age"]) """ output: __getitem__ name __getitem__ nationality __getitem__ age Bauer China 23 __delitem__ age __getitem__ age None """
__new__
方法会在__init__
方法前被执行,会建立并返回一个新的实例对象,而后传递给__init__
。__new__
不是一个成员方法,而是一个静态方法。
在Python中,一切皆对象,在新式类中,为了将类型(int,str,float等)和类统一,全部的类都是type类型的对象。在类中有一个属性 __metaclass__
能够指定当前类由哪一个类进行实例化。而建立对象过程当中,构造函数不是__init__
方法,而是__new__
方法,__new__
方法会返回一个对象,即对象构造函数。
类实例化对象内部实现过程的代码段:
class PersonType(type): def __init__(cls, what, bases=None, dic=None): super(PersonType, cls).__init__(what, bases, dic) def __call__(cls, *args, **kwargs): obj = cls.__new__(cls) cls.__init__(obj, *args, **kwargs) return obj class Dog: __metaclass__ = PersonType def __init__(self,name,age): self.name=name self.age=age def __new__(cls, *args, **kwargs): return object.__new__(cls) if __name__ == "__main__": obj = Dog("Dog", 3) print(obj.name, obj.age) """ output: Dog 3 """
类中定义__call__
方法时,类对象实例能够做为一个函数去调用,而函数的调用方式是函数名()。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def __call__(self, *args, **kwargs): print("name: ", self.name, "args: ", *args) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") bauer("China", 26) """ output: name: Bauer args: China 26 """
Python中类的继承按照父类中的方法是否已实现可分为两种:
实现继承 :指直接继承父类的属性和已定义并实现的的方法;
接口继承 :仅继承父类类的属性和方法名称,子类必须自行实现方法的具体功能代码。
若是是根据要继承的父类的个数来分,有能够分为:
单继承: 只继承1个父类。
多继承: 继承多个父类。
class Person(object): def __init__(self, name, age): self.name = name self.age = age def walk(self): print('%s is walking...' % self.name) def talk(self): print('%s is talking...' % self.name) class Teacher(Person): def __init__(self, name, age, level, salary): super(Teacher, self).__init__(name, age) self.level = level self.salary = salary def teach(self): print('%s is teaching...' % self.name) class Student(Person): def __init__(self, name, age, class_): Person.__init__(self, name, age) self.class_ = class_ def study(self): print('%s is studying...' % self.name) if __name__ == "__main__": t1 = Teacher('Bauer', 33, 'Senior', 20000) s1 = Student('Jack', 13, 'A class') t1.talk() t1.walk() t1.teach() s1.talk() s1.walk() s1.study() """ output: Bauer is talking... Bauer is walking... Bauer is teaching... Jack is talking... Jack is walking... Jack is studying... """
Teacher类 和Student类都继承 Person类,所以Teacher和Student是Person的子类/派生类,而Person是Teacher和Student的父类/基类/超类;
Teacher和Student对Person的继承属于实现继承,且是单继承;
Teacher类继承了Person的name和age属性,及talk()和walk()方法,并扩展了本身的level和salary属性,及teach()方法;
Student类继承了Person的name和age属性,及talk()和walk()方法,并扩展了本身的class属性,及study()方法;
Teacher和Student对Person类属性和方法继承体现了 代码的重用性, 而Teacher和Student扩展的属性和方法体现了 灵活的扩展性;
子类 Teacher 和 Student 也能够在本身的类定义中从新定义父类中的talk()和walk()方法,改变其实现代码,即方法重写override。
派生类的构造函数须要显式调用父类的构造函数,对父类的属性成员进行初始化,调用父类的构造函数时须要显式传递实例对象self。
子类须要在本身的__init__
方法中的第一行位置调用父类的构造方法,上述代码给出了两种方法:
super(子类名, self).__init__(父类构造参数)
,如super.(Teacher, self).__init__(name, age)
,推荐方式。
父类名.__init__(self, 父类构造参数)
,如Person.__init__(self, name, age)
。
isinstance能够判断一个变量是不是某一种数据类型,也能够判断对象是不是类的对象或者是类的子类对象。
issubclass用来判断一个类是不是某个类的子类,返回的是一个bool类型数据。
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) class Teacher(Person): pass if __name__ == "__main__": bauer = Teacher("Bauer") print(isinstance(bauer, Person)) print(issubclass(Teacher, Person)) """ output: True True """
Python支持多层父类继承,子类会继承父类全部的属性和方法,包括父类的父类的全部属性和方法。Python虽然支持多继承,但Python对多继承的支持的也是有限的。
多继承时,使用super只会调用第一个父类的属性方法,所以,要想调用特定父类的构造器只能显式调用父类名.__init__
。
若是父类中有相同的方法名,而在子类使用时未显式指定调用的具体赋类的方法,Python会根据继承顺序从左至右搜索查找父类中是否包含方法。
class A(object): def __init__(self): print("class A") def hello(self): print('hello, class A') def func2(self): print('class A: func2') class B(A): def __init__(self): A.__init__(self) print("class B") def hello(self): print('hello, class B') class C(A): def __init__(self): A.__init__(self) print("class C") def hello(self): print('hello, class C') class D(B, C): def __init__(self): B.__init__(self) C.__init__(self) print("class D") if __name__ == "__main__": d = D() d.hello() print(D.mro()) """ output: class A class B class A class C class D hello, class B [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] """
若是子类从多个父类派生,而子类没有本身的构造函数时,按顺序继承,哪一个父类在最前面且有本身的构造函数,就继承其构造函数。
class A(object): def __init__(self): print("class A") def hello(self): print('hello, class A') def func2(self): print('class A: func2') class B(A): def __init__(self): A.__init__(self) print("class B") def hello(self): print('hello, class B') class C(A): def __init__(self): A.__init__(self) print("class C") def hello(self): print('hello, class C') class D(B, C): pass if __name__ == "__main__": d = D() d.hello() print(D.mro()) """ output: class A class B hello, class B [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] """
若是子类从多个父类派生,而子类没有本身的构造函数时,若是最前面第一个父类没有构造函数,则依次查找后序继承父类的构造函数。
class A(object): def __init__(self): print("class A") def hello(self): print('hello, class A') def func2(self): print('class A: func2') class B(A): def hello(self): print('hello, class B') class C(A): def __init__(self): A.__init__(self) print("class C") def hello(self): print('hello, class C') class D(B, C): pass if __name__ == "__main__": d = D() d.hello() print(D.mro()) """ output: class A class C hello, class B [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] """
类的属性__mro__
或者方法mro()都能打印出类的继承顺序,super()在执行时查找MRO列表,到列表当前位置的类中去查找其下一个类。
为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配属性的类为止。
在Python 3.x中不管是否显式指定继承object,全部的类都是新式类,在多继承的状况下,经典类查找父类属性或方法的顺序是深度优先,新式类查找父类属性的顺序是广度优先。
super是MRO中的一个类。MRO全称Method Resolution Order,表明类的继承顺序。对于定义的每个类,Python会计算出一个方法解析顺序(MRO)列表,MRO列表是一个简单的全部基类的线性顺序列表。
MRO列表的构造是经过一个C3线性化算法来实现的,MRO会合并全部父类的MRO列表并遵循以下三条准则:
A、子类会先于父类被检查。
B、多个父类会根据它们在列表中的顺序被检查。
C、若是对下一个类存在两个合法的选择,选择第一个父类。
MRO能够保证多继承状况每一个类只出现一次,super().init相对于类名.init,在单继承上用法基本无差,但在多继承上,super方法能保证每一个父类的方法只会执行一次,而使用类名的方法会致使方法被执行屡次。
单继承时,使用super方法,不能所有传递,只能传父类方法所需的参数,不然会报错;多继承时,使用类名.init方法须要把每一个父类所有写一遍,而使用super方法只需一条语句便执行所有父类的方法,所以多继承须要所有传参。
9、类的多态性
多态一般是经过继承接口的方式实现的,Python中没有接口,但Python中能够经过在一个成员方法体中抛出一个NotImplementedError异常来强制继承接口的子类在调用接口方法前必须先实现接口方法。
class Animal(object): # Animal Interface def __init__(self, name): self.name = name def walk(self): raise NotImplemented('Subclass must implement the abstract method by self') def talk(self): raise NotImplemented('Subclass must implement the abstract method by self') class Dog(Animal): def talk(self): print('%s is talking:wang wang...' % self.name) def walk(self): print('%s is a Dog,walk by 4 legs' % self.name) class Duck(Animal): def talk(self): print('%s is talking: ga ga...' % self.name) def walk(self): print('%s is a Duck,walk by 2 legs' % self.name) if __name__ == "__main__": dog = Dog('Trump') dog.talk() dog.walk() duck = Duck('Tang') duck.talk() duck.walk() """ output: Trump is talking:wang wang... Trump is a Dog,walk by 4 legs Tang is talking: ga ga... Tang is a Duck,walk by 2 legs """
接口的全部子类必须实现接口中定义的全部方法;接口的各个子类在实现接口中同一个方法时,具体的代码实现各不相同,即多态。
Python中反射机制是经过hasattr、getattr、setattr、delattr四个内置函数实现的,四个内置函数不只能够用在类和对象中,也能够用在模块等。
hasattr(key)返回的是一个bool值,判断某个成员或者属性在不在类或者对象中。
getattr(key,default=xxx)获取类或者对象的成员或属性,若是不存在,则会抛出AttributeError异常,若是定义了default那么当没有属性的时候会返回默认值。
setattr(key,value)假若有key属性,那么更新key属性,若是没有就添加key属性并赋值value。
delattr(key)删除某个属性。
实例代码以下:
import uuid class Person(object): nationality = "China" def __init__(self, name): self.name = name self.__id = str(uuid.uuid1()) def hello(self): print("Hello, I am %s, I come from %s, My ID is %s" %(self.name, self.nationality, self.__id)) if __name__ == "__main__": bauer = Person("Bauer") setattr(bauer, "sex", "Man") print(getattr(bauer, "name")) print(getattr(bauer, "nationality")) print(getattr(bauer, "sex")) helloFunc = getattr(bauer, "hello") helloFunc() if hasattr(bauer, "job"): print(getattr(bauer, "job")) delattr(bauer, "sex") print(getattr(bauer, "name")) print(getattr(bauer, "nationality")) print(getattr(bauer, "sex")) # AttributeError: 'Person' object has no attribute 'sex'
在面向对象编程中,单例模式是一个类只有一个对象,全部的操做都经过单例对象来完成,实现代码以下:
class Instance: __instance = None @classmethod def get_instance(cls): if cls.__instance: return cls.__instance else: cls.__instance = Instance return cls.__instance obj1 = Instance.get_instance() print(id(obj1)) obj2 = Instance.get_instance() print(id(obj2)) # output: # 35307304 # 35307304
Python中使用try except finally组合来实现异常扑捉,except中的Exception是全部异常的父类,异常处理的示例以下:
try: int("12a") #可能出现异常的代码 except IndexError as e: # 捕捉索引异常的子异常 print("IndexError:",e) except ValueError as e: # 捕捉value错误的子异常 print("ValueError:",e) except Exception as e: # 使用Exception捕获,Exception可以捕获全部的异常 print("Exception:",e) else: # 若是没有异常发生,执行else中的代码块 print("true") finally: # 不论是否发生异常,在最后都会执行finally中的代码,假如try里面的代码正常执行,先执行else中的代码,再执行finally中的代码 print("finally")
Exception是全部异常的父类,能够自定义Exception的子类,实现自定义异常处理。
class TypeErrorException(Exception): def __init__(self, message): self.message = message def __str__(self): # 打印异常的时候会调用对象里面的__str__方法返回一个字符串 return self.message if __name__ == "__main__": try: raise TypeErrorException("Type error") except TypeErrorException as e: print("TypeErrorException:",e) except Exception as e: print("Exception:",e) else: print("true") finally: print("finally")
断言assert通常用在判断执行环境上,只要断言的条件不知足,就抛出异常,后续代码不会被执行。
print("Assert test") ok = True result = False assert ok == result print("Assert test") # output: """ Assert test Traceback (most recent call last): File "test.py", line 6, in <module> assert ok == result AssertionError """