python3 面向对象_Python3快速入门(六)——Python3面向对象

2023-10-27

Python3快速入门(六)——Python3面向对象

一、面向对象技术简介

1、面向对象简介

面向对象编程(Object Oriented Programing,OOP)是一种编程思想,OOP把对象当成程序的一个基本单元,一个对象包含数据和操作数据的方法。面向对象编程的三大特性如下:

A、封装,可以隐藏实现细节,使代码模块化。

B、继承,可以通过扩展已存在的类来实现代码重用,避免重复编写相同的代码。

C、多态,封装和继承的目的都是为了实现代码重用, 而多态是为了实现接口重用,使得类在继承和派生的时候能够保证任何一个类的实例都能正确调用约定好的属性和方法。

面向对象编程通过封装、继承、多态实现了软件工程的重用性、灵活性、扩展性三个目标。

2、面向对象术语

类(Class)是用来描述具有相同的属性和方法的对象的集合,定义了集合中每个对象所共有的属性和方法。

对象是类的实例,Python中对象包括两个数据成员(类变量和实例变量)和方法。

方法是类中定义的函数。

类变量在类的所有实例化对象中是公用的。类变量定义在类中且在函数体外。

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行重写(override)。

继承是一个派生类(derived class)继承基类(base class)的字段和方法。继承允许把一个派生类的对象作为一个基类对象对待。

实例化:创建一个类的实例,类的具体对象。

3、对象的属性

在python当中一切皆对象,每个对象都有三个属性:id、类型type和数值。id是对象的地址,id相同则必为同一对象,不同对象的值可以相同。

# -*- coding:utf-8 -*-

x = 10

print(id(x))

print(type(x)) #

print(x)

y = 10

print(id(y))

print(type(y)) #

print(y)

print(x is y) # True

二、类的定义

1、类的定义

类是一种抽象数据类型,是对现实世界的一类数据及其操作的封装。

类定义语法格式如下:

class ClassName:

.

.

.

类实例化后,可以使用其属性,创建一个类后,可以通过类名访问其类属性。

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))

所有人的国籍基本都是相同的,且允许直接通过类或实例来访问,允许随意修改。

大部分人的姓名是不同的,且允许直接通过类的实例来访问和随意修改。

所有人的×××号码都是不一样的,且不允许直接通过类或实例来访问或随意修改。

2、类的实例化

import Person

bauer = Person.Person("Bauer")

bauer.hello()

3、类成员的可见性

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

"""

三、类的属性

1、类属性

直接定义在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

"""

类属性可以通过类直接访问,也可以直接通过实例进行访问; 如果通过类的某个实例对类属性进行修改,本质上是为该实例添加了一个与类属性名称相同的实例属性,对真正的类属性没有影响,因此不会影响其它实例获取类属性的值; 通过类对类属性进行修改,必然会改变类属性的值,对类的所有实例是都有影响的。

2、实例属性

实例属性又称成员属性或成员变量,是类的每个实例对象单独持有的属性。实例属性必须在类的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作为动态语言,可以在类外部动态增加实例对象的属性。

3、私有属性

私有属性和实例属性必须在__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

None

{'name': 'Bauer', '_Person__id': 'f545f99a-94b5-11e9-aa3f-5ce0c5e8bcf0'}

__main__

Person Class

None

{'__module__': '__main__', 'nationality': 'China', '__init__': , '_Person__hello': , 'say_hello': , 'get_nationality': , 'add': , 'id': , '__dict__': , '__weakref__': , '__doc__': None}

__main__

"""

实例对象.__dict__和 类.__dict__的值是不同的,实例对象.__dict__的值中只包含成员属性和私有属性,类.__dict__的值中包含类的类属性和所有方法;

__module__和__class__的值可用于反射来实例化一个类的对象。

五、类的方法

1、成员方法

成员方法通过类的实例对象去访问,第一个参数必须是当前实例对象,通常写为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

"""

2、私有方法

私有方法是以双下划线开头的成员方法。私有方法只能在实例方法内部访问,且不能被子类继承;私有方法的第一个参数也必须是当前实例对象本身,通常写为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

"""

3、类方法

类方法是以@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

"""

4、静态方法

静态方法是以@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

"""

5、属性方法

属性方法是以@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中属性方法通常用于在属性方法内部进行一系列的逻辑计算,最终将计算结果返回。

6、方法的绑定

类内部定义的方法,在没有被任何装饰器修饰的情况下,是为了绑定到对象的,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的类中有一些内置的、特殊的方法,其名称是以双下划线__开头且以双下划线__结尾。特殊方法不是私有方法,可以在类的外部通过实例对象去直接访问,且都有着各自特殊的意义。

1、init构造方法

__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__

"""

2、del析构方法

__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__

"""

3、str

如果类中定义了__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__

"""

4、getitem、setitem、delitem

__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

"""

5、new

__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

"""

6、call

类中定义__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

"""

七、类的继承

1、派生类定义

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。

2、派生类构造函数

派生类的构造函数需要显式调用父类的构造函数,对父类的属性成员进行初始化,调用父类的构造函数时需要显式传递实例对象self。

子类需要在自己的__init__方法中的第一行位置调用父类的构造方法,上述代码给出了两种方法:

super(子类名, self).__init__(父类构造参数),如super.(Teacher, self).__init__(name, age),推荐方式。

父类名.__init__(self, 父类构造参数),如Person.__init__(self, name, age)。

3、isinstance

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

"""

八、类的多继承

1、多继承简介

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 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 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

[, , , , ]

"""

2、多继承查找顺序

类的属性__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方法只需一条语句便执行全部父类的方法,因此多继承需要全部传参。

九、类的多态性

多态通常是通过继承接口的方式实现的,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

十二、异常处理

1、异常处理简介

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")

2、自定义异常处理

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")

3、断言

断言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

assert ok == result

AssertionError

"""

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python3 面向对象_Python3快速入门(六)——Python3面向对象 的相关文章

  • mysql优化之(use temporary、use filesort)

    目录 一 use temporary 二 use filesort 三 extra的其它字段说明 一 use temporary 为了解决查询 MySQL需要创建一个临时表来容纳结果 use temporary产生条件 如果GROUP BY
  • 【实训项目】滴滴电竞APP

    1 设计摘要 2013年国家体育总局决定成立一支由17人组成的电子竞技国家队 第四届亚室会中国电竞代表队 出战第四届亚洲室内和武道运动会 2014年1月13日CCTV5 体育人间 播放英雄联盟皇族战队的纪录片 在2015到2019年间 我国
  • VMware16的安装

    一 学习目标 VMware Workstation的安装 创建虚拟机 二 要点 VMware Workstation的安装 为方便自己安装文件的寻找 最好创建一个以Linux操作系统命名的新文件夹 CentOS 7 x86 64 DVD 2
  • Nginx rtmp&&Centos FFmpeg安装配置

    Nginx yum install git yum y install gcc gcc c yum install y pcre pcre devel yum install y zlib zlib devel yum install y
  • 浏览器首页被篡改,教你如何改回来!

    原文 http www javaketang com html 2018 subject 1023 95 html 有时会遇到这个问题 浏览器的主页不知什么原因被篡改了 今天就教大家怎么改回来 主页被篡改 方法一 1 首先找到浏览器的设置
  • Android开源框架之ImageLoader

    特点 多线程下载图片 图片可以来源于网络 文件系统 项目文件夹assets中以及drawable中等 支持随意的配置ImageLoader 例如线程池 图片下载器 内存缓存策略 硬盘缓存策略 图片显示选项以及其他的一些配置 支持图片的内存缓
  • 软件发布版本命名规则

    软件发布版本命名规则 1 版本类型 1 1 正式版本 Enhance 增强版或者加强版 属于正式版 Full 完全版 属于正式版 Release 发行版 有时间限制 Upgrade 升级版 Retail 零售版 Plus 增强版 不过这种大
  • 数组筛选filter()

    var datas name 商品房 code 11 name 商铺 code 12 var data datas filter function item return item code 12 console log data name
  • 在LUA中使用GETTEXT实现多语言支持

    在Lua中使用gettext实现多语言支持 GNU gettext 是一套优秀的国际化工具 在 linux 中被大量采用 wordpress 也使用 gettext 实现多语言支持 本文介绍如何在 quick cocos2d x 中使用 g
  • 第二次ACOUG活动的收获

    author skate time 2010 04 25 本次ACOUG活动的收获 在4月24日参加ACOUG的第二次地面活动 这次活动的参见的人很多 整个活动的气氛非常好 众多专家高手在分享的他们的经验 在这个活动中 我得到的收获是 1
  • C#/.NET/.NET Core优秀项目框架推荐

    优质资源分享 学习路线指引 点击解锁 知识定位 人群定位 Python实战微信订餐小程序 进阶级 本课程是python flask 微信小程序的完美结合 从项目搭建到腾讯云部署上线 打造一个全栈订餐系统 Python量化交易实战 入门级 手
  • 云计算对于IT业务开展好处都有哪些?

    随着企业越来越多的开始部署采用云服务 您到底是需要增加还是减少IT员工数量 这取决于您所看到的调查或报道 对于您企业的IT员工和他们的工作安全来说 云计算可以是一件好事 也可能相当可怕 例如 根据微软和IDC最近的研究预测 到2015年 云
  • 模板函数递归不定参数展开template<typename First, typename ...KeyTypes>

    看到一篇文 https www cnblogs com qicosmos p 4325949 html 讲到了模板函数递归展开不定参数包 突然想起一段段代码如下 void MediaSource for each media const f
  • webpack的安装及打包

    1 创建项目目录并初始化 创建项目 并打开项目所在目录的终端 在命令框输入命令 npm init y 2 创建首页及js文件 创建一个src文件 在src里创建index html页面 初始化页面结构 在页面中摆放一个ul ul里面放置几个
  • eclipse使用技巧:快速显示行号

    1 把光标放在某个展开的类中 按下快捷键 Ctrl F10 gt 选择 Show Line Numbers 这尼玛也太简单了
  • linux 进程状态 rl,Linux进程状态详解

    Linux进程状态详解 以下部分的代码示例 来自于Linux内核的0 11版本源码 在定义进程的数据结构task struct时 有一个state字段是用来表示进程状态的 这里总结了下关于state字段的操作 关于进程的几个状态值在sche
  • 超详细CSS思维导图,自制

    CSS思维导图 这是自写的CSS思维导图 主要是还是留着自己有时候有些忘记的东西 就可以在上面查找一下 上面写的也是比较基础的CSS知识 相信以后也一定会用得上的 今天还是花了点时间的 啊现在有点累了 果然我这个身体板是差点啊 休息了休息了
  • jquery html方法xss,jQuery DOM方法中的XSS漏洞演示

    HTML 导入代码模板 XSS vulnerabilities in jQuery DOM methods Input Output native innerHTML The HTML5 spec states that script ta
  • 3.荔枝派 zero(全志V3S)-制作linux烧录镜像

    上面是我的微信和QQ群 欢迎新朋友的加入 目录 1 安装工具 2 生成新的img文件 3 分割虚拟磁盘 4 挂载虚拟磁盘并格式化 5 开始备份 6 卸载虚拟磁盘 7 烧录测试 最近学习linux 发现烧录镜像都有点麻烦 例如荔枝派 需要先用

随机推荐

  • 文件上传 相关知识

    文件上传 参考文章 平井缘 要点 1 示例一个 FormData 对象 要点 2 将上传时获取到的 file 文件 append 到 formdata 对象中 要点 3 配置上传接口的 请求头 方式一 表单提交文件 原生
  • JS Es6中判断b数组对象是否有跟a数组对象相同的数值(例如:id),有的话就过滤掉

    如下 数组 对象a和b let a id 1 value this id 2 value is let b id 1 value hello id 3 value world filter 方法创建一个新的数组 新数组中的元素是通过检查指定
  • 【数据分析】初识 AB 测试

    初识 AB 测试 1 简述 AB 测试 AB 测试是指为了评估模型 项目的效果 在 APP PC 端同时设计多个版本 在同一时间维度下 分别让组成成分相同 相似 的访客群组随机访问这些版本 收集各群组的用户体验数据和业务数据 最后分析评估出
  • Maven解决静态资源过滤问题

    前言 在我们使用Maven构建项目的时候 会默认过滤掉静态资源 所以 需要手动来配置 一 认识静态资源与动态资源 静态资源 包含HTMl 图片 CSS JS等不需要与数据库交互的一类文件 动态资源 需要与数据库交互 可以根据需要显示不同的数
  • 选择文件后自动上传文件' aria-label='选择文件后自动上传文件'> 选择文件后自动上传文件

    想要一个选择了文件就自动上传的效果 但之前的
  • 计算机毕业设计Node.js+Vue基于Java网络游戏后台管理系统(程序+源码+LW+部署)

    该项目含有源码 文档 程序 数据库 配套开发软件 软件安装教程 欢迎交流 项目运行 环境配置 Node js Vscode Mysql5 7 HBuilderX Navicat11 Vue Express 项目技术 Express框架 No
  • steam"无法连接到更新服务器"的问题

    问题现象如下图所示 在打开steam游戏时出现了上述问题 无法正常游戏 不光如此steam官网也无法正常显示 只有部分文字和图片 样式缺失 打开chrome的F12开发者工具 进入network模块监视可发现大量的请求并没有被响应 甚至没有
  • SQL语句执行顺序

    首先了解一下sql语句的执行步骤 1 语法分析 分析语句的语法是否符合规范 衡量语句中各表达式的意义 2 语义分析 检查语句中涉及的所有数据库对象是否存在 且用户有相应的权限 3 视图转换 将涉及视图的查询语句转换为相应的对基表查询语句 4
  • 软件测试必看!5分钟掌握sql查询的聚合函数

    数据查询操作之排序 语法格式 select from 表名 order by 字段名 asc desc 重点 1 字段名可以有多个 如果字段名1 相同 再按照字段名2排序 2 默认情况下按照从小到大去排列 3 asc 就是从小到大排列 de
  • 【图论】—— 有向图的强连通分量

    给定有向图 若存在 满足从 出发能到达 中所有的点 则称 是一个 流图 Flow Graph 记为 其中 称为流图的源点 在一个流图 上从 进行深度优先遍历 每个点只访问一次 所有发生递归的边 换言之 从 到 是对 的第一次访问 构成一棵以
  • Java中Juc并发编程基础

    1 什么是JUC 就是java util concurrent并发包下面使用的工具包 1 1 线程和进程 进程 是一个程序 QQ exe 网易云音乐 大数据领域的NameNode其实就是程序的集合 一个进程往往可以包含多个线程 至少包含一个
  • 同步和异步

    同步和异步通常用来形容方法的调用方式 同步方法表明调用一旦开始 调用者必须等待方法执行完成 才能继续执行后续方法 异步方法表明 方法一旦开始 立即返回 调用者无需等待其中方法执行完成 就可以继续执行后续方法 通常我们写的方法都是同步方法 方
  • 使用Nginx解决跨域问题

    目录 使用Nginx解决跨域问题 1 修改浏览器 客户端访问地址 2 在nginx conf配置文件需配置server 3 在Nginx中配置客户端访问的接口 按照规则或通配 并设置被代理的服务器 4 在Nginx中统一配置客户端访问的头部
  • java实时获取汇率

    1 分享三个觉得挺不错的汇率api 1 每小时免费50次查询配额 NOWapi 2 0 1元2000次 年 阿里云 汇率api 3 每天免费100次查询配额 需要实名认证 聚合科技 如果只是针对很少外币获取汇率的话 个人推荐去阿里云购买 毕
  • Java中使用Jar包时读取当前jar文件所在的目录工具

    在实际使用中 jar包所放的位置是不一定的所以要动态获取当前目录 package com gj5u publics util import java io File 获取打包后jar的路径信息 author Rex public class
  • angularJs摸态框实例加详细注解

  • mos 多路模拟电子开关_同步四开关 BuckBoost 180W 模块电源

    点击上方 21Dianyuan 关注我们 本文是 21Dianyuan 社区 原创 技术文章 作者 xueyiranpiao 感谢作者的辛苦付出 本电源主要应用于电池充电 电池为8串磷酸铁锂 10000mAH 0 6C 充电 也可以用于其它
  • Mybatis底层源码分析(最详细的版本)

    Mybatis底层源码分析 最详细的版本 1 概要介绍 MyBatis 是一款优秀的持久层框架 也是当前最流行的java持久层框架之一 它内部封装了jdbc 使开发 者只需要关注sql语句本身 而不需要花费精力去处理加载驱动 创建连接 创建
  • 网络编程知识预备(2) ——TCP三次握手与四次挥手、流量控制(滑动窗口)、拥塞控制、半连接状态、2MSL

    参考 浅显易懂的三次握手与四次挥手 作者 丶PURSUING 发布时间 2021 03 19 09 33 20 网址 https blog csdn net weixin 44742824 article details 114990198
  • python3 面向对象_Python3快速入门(六)——Python3面向对象

    Python3快速入门 六 Python3面向对象 一 面向对象技术简介 1 面向对象简介 面向对象编程 Object Oriented Programing OOP 是一种编程思想 OOP把对象当成程序的一个基本单元 一个对象包含数据和操