Python 深入浅出

来源:互联网 发布:wepy 知乎 编辑:程序博客网 时间:2024/06/05 23:43

Python 面向对象

在 Python 中,所有的数据类型都可以视为对象,当然也可以自定义对象,自定义对象数据类型就是面向对象中的类 Class 的概念。

  • 类:用来描述具有相同属性和方法的对象的集合,它定义了该集合中每个对象的共有的属性和方法。
  • 类变量:类变量在整个实例化的对象中是公有的,类变量定义在类中且在函数体外。
  • 实例变量:定义在方法中的变量,只能作用于当前实例。
  • 实例化:即创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。

创建类

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾。

class ClassName:    '类的帮助信息'  #类文档信息    类变量    方法    数据属性

例子:

class Employee(object):    'Employee 雇员类'    empCount = 1  # 类变量    def __init__(self, name, age):        self.__name = name  # 实例变量        self.__age = age  # 实例变量    def printCount(self):        print("Total employee = %d" % Employee.empCount)    def printEmployee(self):        print("name = %s ,age = %d" % (self.__name, self.__age))
  • 类名后面的 (object) 表示这个类是从哪个类继承下来的, object 是所有类的父类。
  • _ init_() 方法是是类的构造函数或初始化方法,当创建类的实例时就会调用这个方法。
  • self 代表类的实例,self 参数在定义类的方法时必须有的,在创建实例时,self 参数不需要传入,解释器自己会把实例变量传进去。
  • 实例变量在变量名前面加上两个下划线就变成了一个私有变量,只有类内部可以访问,外部不能访问;这样确保外部代码不能随意修改对象内部的属性的值。双下划线的变量不能再类外直接访问,是因为解释器对外把 __name 变量改成了 _Person__name ,所以,任然可以通过 _Student__name 来访问 __name 变量。
  • 同时,可以给类定义get ,set 方法,用于获取和修改类的属性。

创建实例对象

创建实例使用 类名(参数…),其中参数对应于定义类时的 init 方法中的参数。

e = Employee("tomcat",22)e.printCount()e.printEmployee()

输出结果:

Total employee = 1

name = tomcat ,age = 22

Python 内置类属性

  • _ dict _:类的属性,由类的数据属性组成
  • _ doc _:类的文档字符串
  • _ name _:类名
  • _ module _:类定义所在的模块
  • _ bases _:类的所有父类构成元素


print("Employee.__doc__:",Employee.__doc__)print("Employee.__name__:",Employee.__name__)print("Employee.__module__:",Employee.__module__ )print("Employee.__bases__:",Employee.__bases__)print("Employee.__dict__:",Employee.__dict__)

输出结果:

Employee.doc: Employee 雇员类
Employee.name: Employee
Employee.module: main
Employee.bases: (<class ‘object’>,)
Employee.dict: {‘module‘: ‘main‘, ‘doc‘: ‘Employee 雇员类’, ‘empCount’: 1, ‘init‘: <function Employee.init at 0x0175F780>, ‘printCount’: <function Employee.printCount at 0x0175F5D0>, ‘printEmployee’: <function Employee.printEmployee at 0x0175F588>, ‘dict‘: <attribute ‘dict’ of ‘Employee’ objects>, ‘weakref‘: <attribute ‘weakref’ of ‘Employee’ objects>}

继承

语法: class 派生类名(基类名):

基类:

class Animal(object):    def run(self):        print("Animal run.....")

子类:

class Dog(Animal):    passclass Cat(Animal):    passdog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Animal run…..

Animal run…..

子类自动继承了父类中方法。

注意:
1. 在继承中基类的构造(init() 方法) 不会被自动调用,需要在其派生类的构造中亲自专门调用。
2. 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量,区别在于类中调用普通函数时,并不需要带上 self 参数。
3. Python 总是首先查找对应类型的方法,如果他不能再派生类中找到对应的方法,他才开始到基类中逐个查找。

方法覆盖

class Dog(Animal):    def run(self):        print("Dog run....")class Cat(Animal):    def run(self):        print("Cat run....")dog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Dog run….

Cat run….

当子类和父类都存在相同的方法时,子类方法覆盖了父类的方法,在代码执行时,调用的是子类中的那个方法。

多态

def run_animal(animal):    animal.run()run_animal(dog)run_animal(cat)

输出结果:

Dog run….

Cat run….

可见,Animal类型的参数,可以传入 Dog,Cat 类型变量,只有传入的参数类型是 Animal 的子类,都可以接收。

鸭子模型

对于静态语言(Java)来说,如果需要传入 Animal 类型,则传入的对象必须是 Animal 类型或者他的子类,否则,将无法调用 run() 方法。但是,对用 Python 这种动态语言来说,则不一定需要传入 Animal 类型,只需保证传入的对象有一个 run() 方法即可。

type() 获取对象信息

使用 type() 函数可以判断出对象的类型。

print(type(123))print(type("123"))print(type(None))print(type([1,2,3]))print(type((1,2,3)))print(type({"Android":"Google","iOS":"Apple"}))print(type(True))print(type(abs))  # abs 绝对值,内置函数print(type(dog))

输出结果:

判断对象是否是函数

import typesdef function_add():    passfunction_res  = type(function_add) == types.FunctionTypeprint(function_res)

输出结果: True

对象是否是类的实例 - isinstance()

print("dog is Animal = " , isinstance(dog,Animal))print("123 is int = " , isinstance(123,int))print("'123' is str = " , isinstance('123',str))print("b'a' is bytes = " , isinstance(b'a',bytes))print("[1,2,3] is list or tuple",isinstance([1,2,3],(list,tuple))) # 判断一个变量是否是某些类型中的其中一种

输出结果:
dog is Animal = True

123 is int = True

‘123’ is str = True

b’a’ is bytes = True

[1,2,3] is list or tuple True

dir() 获取对象所有属性和方法

print(dir("abc"))print(dir(123))

输出结果:
[‘add‘, ‘class‘, ‘contains‘, ‘delattr‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getitem‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘init‘, ‘init_subclass‘, ‘iter‘, ‘le‘, ‘len‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘new‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rmod‘, ‘rmul‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘subclasshook‘, ‘capitalize’, ‘casefold’, ‘center’, ‘count’, ‘encode’, ‘endswith’, ‘expandtabs’, ‘find’, ‘format’, ‘format_map’, ‘index’, ‘isalnum’, ‘isalpha’, ‘isdecimal’, ‘isdigit’, ‘isidentifier’, ‘islower’, ‘isnumeric’, ‘isprintable’, ‘isspace’, ‘istitle’, ‘isupper’, ‘join’, ‘ljust’, ‘lower’, ‘lstrip’, ‘maketrans’, ‘partition’, ‘replace’, ‘rfind’, ‘rindex’, ‘rjust’, ‘rpartition’, ‘rsplit’, ‘rstrip’, ‘split’, ‘splitlines’, ‘startswith’, ‘strip’, ‘swapcase’, ‘title’, ‘translate’, ‘upper’, ‘zfill’]

[‘abs‘, ‘add‘, ‘and‘, ‘bool‘, ‘ceil‘, ‘class‘, ‘delattr‘, ‘dir‘, ‘divmod‘, ‘doc‘, ‘eq‘, ‘float‘, ‘floor‘, ‘floordiv‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘index‘, ‘init‘, ‘init_subclass‘, ‘int‘, ‘invert‘, ‘le‘, ‘lshift‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘neg‘, ‘new‘, ‘or‘, ‘pos‘, ‘pow‘, ‘radd‘, ‘rand‘, ‘rdivmod‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rfloordiv‘, ‘rlshift‘, ‘rmod‘, ‘rmul‘, ‘ror‘, ‘round‘, ‘rpow‘, ‘rrshift‘, ‘rshift‘, ‘rsub‘, ‘rtruediv‘, ‘rxor‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘sub‘, ‘subclasshook‘, ‘truediv‘, ‘trunc‘, ‘xor‘, ‘bit_length’, ‘conjugate’, ‘denominator’, ‘from_bytes’, ‘imag’, ‘numerator’, ‘real’, ‘to_bytes’]

注意:类似 XXX的属性和方法在 Python 中都是特殊用途的,比如 len方法返回长度,当调用 len() 函数获取对象的长度,实际上,在 len() 函数内部,他自动调用该对象的 len() 方法。

所以,以下写法是等价的:

print(len("123456"))print("123456".__len__())

我们自定义的类,想要使用 len(myObj),就需要自己写一个 len() 方法,因为, len() 方法内部调用的是 len() 方法。

class Rectangle(object) :    def __init__(self,length,width):        self.length = length        self.width = width    def __len__(self):        return 2*(self.length + self.width)rect = Rectangle(10,7)print(len(rect))

如果没有定义 len() 方法,那么输出报错:

Traceback (most recent call last):  File "E:/Python/HelloWorld.py", line 248, in <module>    print(len(rect))TypeError: object of type 'Rectangle' has no len()

另外,Python 提供了操作属性的方法:

  • getattr() : 获取属性
  • setattr() : 设置属性
  • hasattr() : 判断是否存在属性


class Rectangle(object) :def __init__(self,length,width):    self.length = length    self.width = widthdef __len__(self):    return 2*(self.length + self.width)rect = Rectangle(10,7)print("has attr length = ",hasattr(rect,"length"))print("has attr area = ",hasattr(rect,"area"))setattr(rect,"centerX",10)print("has attr centerX = ",hasattr(rect,"centerX"))print("get attr centerX = ",getattr(rect,"centerX"))

输出结果:

has attr length = True

has attr area = False

has attr centerX = True

get attr centerX = 10

实例属性和类属性

实例属性只属于某个实例,每个实例的属性的值可能不相同。
类属性是属于某个类的,所有实例共享同一个属性。

class Teacher(object):    job_occupation = "teacher"    def __init__(self, name):        self.name = name    def print(self):        print("name = ", self.name, "job = ",self.job_occupation)jane_teacher = Teacher("jane")tom_teacher = Teacher("tom")jane_teacher.print()tom_teacher.print()print(Teacher.job_occupation)

上面示例中, job_occupation 即是类属性,

输出结果:

name = jane job = teacher

name = tom job = teacher

teacher

注意:当实例属性和类属性使用相同的名字时,实例属性将屏蔽掉类属性。

实例动态绑定属性和方法

当创建了类的实例后,我们可以给该实例绑定任何属性和方法。

class Student(object):    passstu = Student()print("stu has attr name = ",hasattr(stu,"name"))  # False# 实例对象绑定属性stu.name = "tomcat"print("stu has attr name = ",hasattr(stu,"name"))  # Trueif hasattr(stu,"name"):    print("name = ",stu.name)# 实例对象绑定方法def set_stu_name(self,name):    self.name = namefrom types import MethodTypestu.set_stu_name =  MethodType(set_stu_name,stu)stu.set_stu_name("luck")print(stu.name)# 给所有实例绑定方法,即给 class 类绑定方法def set_score(self,score):    self.score = scoreStudent.set_score = set_scorestu2 = Student()stu2.set_score(90)print(stu2.score)

输出结果:

stu has attr name = False

stu has attr name = True

name = tomcat

luck

90

多重继承

Python 允许使用多重继承,即一个类继承多个类。

class Runnable(object):    def run(self):        print("run....")class Sleepable(object):    def sleep(self):        print("slepp...")class LiveAnimal(Runnable,Sleepable) :    def printAbility(self):        self.run()        self.sleep()liveAnimal = LiveAnimal()liveAnimal.printAbility()

输出结果:

run….

slepp…

定制对象的输出形式 : _ str _

和 Java 相似,默认情况下,直接打印出对象时,输出的是对象的内存地址,我们可以重写 _ str _ 方法来定制输出结果。

class Person(object):    def __init__(self,name,age):        self.name = name        self.age = ageperson = Person("mike",22)print(person)

没有重写 _ str _ 方法,输出结果:

<main.Person object at 0x01D8C4B0>

下面我们重写了 Person 的 _ str_ 方法,定制出我们想要的输出结果。

class Person(object):    def __init__(self, name, age):        self.name = name        self.age = age    def __str__(self):        return "name = %s , age = %s" % (self.name, self.age)person = Person("mike", 22)print(person)

输出结果:

name = mike , age = 22

Python 面向对象

在 Python 中,所有的数据类型都可以视为对象,当然也可以自定义对象,自定义对象数据类型就是面向对象中的类 Class 的概念。

  • 类:用来描述具有相同属性和方法的对象的集合,它定义了该集合中每个对象的共有的属性和方法。
  • 类变量:类变量在整个实例化的对象中是公有的,类变量定义在类中且在函数体外。
  • 实例变量:定义在方法中的变量,只能作用于当前实例。
  • 实例化:即创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。

创建类

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾。

class ClassName:    '类的帮助信息'  #类文档信息    类变量    方法    数据属性

例子:

class Employee(object):    'Employee 雇员类'    empCount = 1  # 类变量    def __init__(self, name, age):        self.__name = name  # 实例变量        self.__age = age  # 实例变量    def printCount(self):        print("Total employee = %d" % Employee.empCount)    def printEmployee(self):        print("name = %s ,age = %d" % (self.__name, self.__age))
  • 类名后面的 (object) 表示这个类是从哪个类继承下来的, object 是所有类的父类。
  • _ init_() 方法是是类的构造函数或初始化方法,当创建类的实例时就会调用这个方法。
  • self 代表类的实例,self 参数在定义类的方法时必须有的,在创建实例时,self 参数不需要传入,解释器自己会把实例变量传进去。
  • 实例变量在变量名前面加上两个下划线就变成了一个私有变量,只有类内部可以访问,外部不能访问;这样确保外部代码不能随意修改对象内部的属性的值。双下划线的变量不能再类外直接访问,是因为解释器对外把 __name 变量改成了 _Person__name ,所以,任然可以通过 _Student__name 来访问 __name 变量。
  • 同时,可以给类定义get ,set 方法,用于获取和修改类的属性。

创建实例对象

创建实例使用 类名(参数…),其中参数对应于定义类时的 init 方法中的参数。

e = Employee("tomcat",22)e.printCount()e.printEmployee()

输出结果:

Total employee = 1

name = tomcat ,age = 22

Python 内置类属性

  • _ dict _:类的属性,由类的数据属性组成
  • _ doc _:类的文档字符串
  • _ name _:类名
  • _ module _:类定义所在的模块
  • _ bases _:类的所有父类构成元素


print("Employee.__doc__:",Employee.__doc__)print("Employee.__name__:",Employee.__name__)print("Employee.__module__:",Employee.__module__ )print("Employee.__bases__:",Employee.__bases__)print("Employee.__dict__:",Employee.__dict__)

输出结果:

Employee.doc: Employee 雇员类
Employee.name: Employee
Employee.module: main
Employee.bases: (

继承

语法: class 派生类名(基类名):

基类:

class Animal(object):    def run(self):        print("Animal run.....")

子类:

class Dog(Animal):    passclass Cat(Animal):    passdog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Animal run…..

Animal run…..

子类自动继承了父类中方法。

注意:
1. 在继承中基类的构造(init() 方法) 不会被自动调用,需要在其派生类的构造中亲自专门调用。
2. 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量,区别在于类中调用普通函数时,并不需要带上 self 参数。
3. Python 总是首先查找对应类型的方法,如果他不能再派生类中找到对应的方法,他才开始到基类中逐个查找。

方法覆盖

class Dog(Animal):    def run(self):        print("Dog run....")class Cat(Animal):    def run(self):        print("Cat run....")dog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Dog run….

Cat run….

当子类和父类都存在相同的方法时,子类方法覆盖了父类的方法,在代码执行时,调用的是子类中的那个方法。

多态

def run_animal(animal):    animal.run()run_animal(dog)run_animal(cat)

输出结果:

Dog run….

Cat run….

可见,Animal类型的参数,可以传入 Dog,Cat 类型变量,只有传入的参数类型是 Animal 的子类,都可以接收。

鸭子模型

对于静态语言(Java)来说,如果需要传入 Animal 类型,则传入的对象必须是 Animal 类型或者他的子类,否则,将无法调用 run() 方法。但是,对用 Python 这种动态语言来说,则不一定需要传入 Animal 类型,只需保证传入的对象有一个 run() 方法即可。

type() 获取对象信息

使用 type() 函数可以判断出对象的类型。

print(type(123))print(type("123"))print(type(None))print(type([1,2,3]))print(type((1,2,3)))print(type({"Android":"Google","iOS":"Apple"}))print(type(True))print(type(abs))  # abs 绝对值,内置函数print(type(dog))

输出结果:

判断对象是否是函数

import typesdef function_add():    passfunction_res  = type(function_add) == types.FunctionTypeprint(function_res)

输出结果: True

对象是否是类的实例 - isinstance()

print("dog is Animal = " , isinstance(dog,Animal))print("123 is int = " , isinstance(123,int))print("'123' is str = " , isinstance('123',str))print("b'a' is bytes = " , isinstance(b'a',bytes))print("[1,2,3] is list or tuple",isinstance([1,2,3],(list,tuple))) # 判断一个变量是否是某些类型中的其中一种

输出结果:
dog is Animal = True

123 is int = True

‘123’ is str = True

b’a’ is bytes = True

[1,2,3] is list or tuple True

dir() 获取对象所有属性和方法

print(dir("abc"))print(dir(123))

输出结果:
[‘add‘, ‘class‘, ‘contains‘, ‘delattr‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getitem‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘init‘, ‘init_subclass‘, ‘iter‘, ‘le‘, ‘len‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘new‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rmod‘, ‘rmul‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘subclasshook‘, ‘capitalize’, ‘casefold’, ‘center’, ‘count’, ‘encode’, ‘endswith’, ‘expandtabs’, ‘find’, ‘format’, ‘format_map’, ‘index’, ‘isalnum’, ‘isalpha’, ‘isdecimal’, ‘isdigit’, ‘isidentifier’, ‘islower’, ‘isnumeric’, ‘isprintable’, ‘isspace’, ‘istitle’, ‘isupper’, ‘join’, ‘ljust’, ‘lower’, ‘lstrip’, ‘maketrans’, ‘partition’, ‘replace’, ‘rfind’, ‘rindex’, ‘rjust’, ‘rpartition’, ‘rsplit’, ‘rstrip’, ‘split’, ‘splitlines’, ‘startswith’, ‘strip’, ‘swapcase’, ‘title’, ‘translate’, ‘upper’, ‘zfill’]

[‘abs‘, ‘add‘, ‘and‘, ‘bool‘, ‘ceil‘, ‘class‘, ‘delattr‘, ‘dir‘, ‘divmod‘, ‘doc‘, ‘eq‘, ‘float‘, ‘floor‘, ‘floordiv‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘index‘, ‘init‘, ‘init_subclass‘, ‘int‘, ‘invert‘, ‘le‘, ‘lshift‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘neg‘, ‘new‘, ‘or‘, ‘pos‘, ‘pow‘, ‘radd‘, ‘rand‘, ‘rdivmod‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rfloordiv‘, ‘rlshift‘, ‘rmod‘, ‘rmul‘, ‘ror‘, ‘round‘, ‘rpow‘, ‘rrshift‘, ‘rshift‘, ‘rsub‘, ‘rtruediv‘, ‘rxor‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘sub‘, ‘subclasshook‘, ‘truediv‘, ‘trunc‘, ‘xor‘, ‘bit_length’, ‘conjugate’, ‘denominator’, ‘from_bytes’, ‘imag’, ‘numerator’, ‘real’, ‘to_bytes’]

注意:类似 XXX的属性和方法在 Python 中都是特殊用途的,比如 len方法返回长度,当调用 len() 函数获取对象的长度,实际上,在 len() 函数内部,他自动调用该对象的 len() 方法。

所以,以下写法是等价的:

print(len("123456"))print("123456".__len__())

我们自定义的类,想要使用 len(myObj),就需要自己写一个 len() 方法,因为, len() 方法内部调用的是 len() 方法。

class Rectangle(object) :    def __init__(self,length,width):        self.length = length        self.width = width    def __len__(self):        return 2*(self.length + self.width)rect = Rectangle(10,7)print(len(rect))

如果没有定义 len() 方法,那么输出报错:

Traceback (most recent call last):  File "E:/Python/HelloWorld.py", line 248, in <module>    print(len(rect))TypeError: object of type 'Rectangle' has no len()

另外,Python 提供了操作属性的方法:

  • getattr() : 获取属性
  • setattr() : 设置属性
  • hasattr() : 判断是否存在属性


class Rectangle(object) :def __init__(self,length,width):    self.length = length    self.width = widthdef __len__(self):    return 2*(self.length + self.width)rect = Rectangle(10,7)print("has attr length = ",hasattr(rect,"length"))print("has attr area = ",hasattr(rect,"area"))setattr(rect,"centerX",10)print("has attr centerX = ",hasattr(rect,"centerX"))print("get attr centerX = ",getattr(rect,"centerX"))

输出结果:

has attr length = True

has attr area = False

has attr centerX = True

get attr centerX = 10

实例属性和类属性

实例属性只属于某个实例,每个实例的属性的值可能不相同。
类属性是属于某个类的,所有实例共享同一个属性。

class Teacher(object):    job_occupation = "teacher"    def __init__(self, name):        self.name = name    def print(self):        print("name = ", self.name, "job = ",self.job_occupation)jane_teacher = Teacher("jane")tom_teacher = Teacher("tom")jane_teacher.print()tom_teacher.print()print(Teacher.job_occupation)

上面示例中, job_occupation 即是类属性,

输出结果:

name = jane job = teacher

name = tom job = teacher

teacher

注意:当实例属性和类属性使用相同的名字时,实例属性将屏蔽掉类属性。

实例动态绑定属性和方法

当创建了类的实例后,我们可以给该实例绑定任何属性和方法。

class Student(object):    passstu = Student()print("stu has attr name = ",hasattr(stu,"name"))  # False# 实例对象绑定属性stu.name = "tomcat"print("stu has attr name = ",hasattr(stu,"name"))  # Trueif hasattr(stu,"name"):    print("name = ",stu.name)# 实例对象绑定方法def set_stu_name(self,name):    self.name = namefrom types import MethodTypestu.set_stu_name =  MethodType(set_stu_name,stu)stu.set_stu_name("luck")print(stu.name)# 给所有实例绑定方法,即给 class 类绑定方法def set_score(self,score):    self.score = scoreStudent.set_score = set_scorestu2 = Student()stu2.set_score(90)print(stu2.score)

输出结果:

stu has attr name = False

stu has attr name = True

name = tomcat

luck

90

多重继承

Python 允许使用多重继承,即一个类继承多个类。

class Runnable(object):    def run(self):        print("run....")class Sleepable(object):    def sleep(self):        print("slepp...")class LiveAnimal(Runnable,Sleepable) :    def printAbility(self):        self.run()        self.sleep()liveAnimal = LiveAnimal()liveAnimal.printAbility()

输出结果:

run….

slepp…

定制对象的输出形式 : _ str _

和 Java 相似,默认情况下,直接打印出对象时,输出的是对象的内存地址,我们可以重写 _ str _ 方法来定制输出结果。

class Person(object):    def __init__(self,name,age):        self.name = name        self.age = ageperson = Person("mike",22)print(person)

没有重写 _ str _ 方法,输出结果:

<main.Person object at 0x01D8C4B0>

下面我们重写了 Person 的 _ str_ 方法,定制出我们想要的输出结果。

class Person(object):    def __init__(self, name, age):        self.name = name        self.age = age    def __str__(self):        return "name = %s , age = %s" % (self.name, self.age)person = Person("mike", 22)print(person)

输出结果:

name = mike , age = 22

Python 面向对象

在 Python 中,所有的数据类型都可以视为对象,当然也可以自定义对象,自定义对象数据类型就是面向对象中的类 Class 的概念。

  • 类:用来描述具有相同属性和方法的对象的集合,它定义了该集合中每个对象的共有的属性和方法。
  • 类变量:类变量在整个实例化的对象中是公有的,类变量定义在类中且在函数体外。
  • 实例变量:定义在方法中的变量,只能作用于当前实例。
  • 实例化:即创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。

创建类

使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾。

class ClassName:    '类的帮助信息'  #类文档信息    类变量    方法    数据属性

例子:

class Employee(object):    'Employee 雇员类'    empCount = 1  # 类变量    def __init__(self, name, age):        self.__name = name  # 实例变量        self.__age = age  # 实例变量    def printCount(self):        print("Total employee = %d" % Employee.empCount)    def printEmployee(self):        print("name = %s ,age = %d" % (self.__name, self.__age))
  • 类名后面的 (object) 表示这个类是从哪个类继承下来的, object 是所有类的父类。
  • _ init_() 方法是是类的构造函数或初始化方法,当创建类的实例时就会调用这个方法。
  • self 代表类的实例,self 参数在定义类的方法时必须有的,在创建实例时,self 参数不需要传入,解释器自己会把实例变量传进去。
  • 实例变量在变量名前面加上两个下划线就变成了一个私有变量,只有类内部可以访问,外部不能访问;这样确保外部代码不能随意修改对象内部的属性的值。双下划线的变量不能再类外直接访问,是因为解释器对外把 __name 变量改成了 _Person__name ,所以,任然可以通过 _Student__name 来访问 __name 变量。
  • 同时,可以给类定义get ,set 方法,用于获取和修改类的属性。

创建实例对象

创建实例使用 类名(参数…),其中参数对应于定义类时的 init 方法中的参数。

e = Employee("tomcat",22)e.printCount()e.printEmployee()

输出结果:

Total employee = 1

name = tomcat ,age = 22

Python 内置类属性

  • _ dict _:类的属性,由类的数据属性组成
  • _ doc _:类的文档字符串
  • _ name _:类名
  • _ module _:类定义所在的模块
  • _ bases _:类的所有父类构成元素


print("Employee.__doc__:",Employee.__doc__)print("Employee.__name__:",Employee.__name__)print("Employee.__module__:",Employee.__module__ )print("Employee.__bases__:",Employee.__bases__)print("Employee.__dict__:",Employee.__dict__)

输出结果:

Employee.doc: Employee 雇员类
Employee.name: Employee
Employee.module: main
Employee.bases: (

继承

语法: class 派生类名(基类名):

基类:

class Animal(object):    def run(self):        print("Animal run.....")

子类:

class Dog(Animal):    passclass Cat(Animal):    passdog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Animal run…..

Animal run…..

子类自动继承了父类中方法。

注意:
1. 在继承中基类的构造(init() 方法) 不会被自动调用,需要在其派生类的构造中亲自专门调用。
2. 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量,区别在于类中调用普通函数时,并不需要带上 self 参数。
3. Python 总是首先查找对应类型的方法,如果他不能再派生类中找到对应的方法,他才开始到基类中逐个查找。

方法覆盖

class Dog(Animal):    def run(self):        print("Dog run....")class Cat(Animal):    def run(self):        print("Cat run....")dog = Dog()cat = Cat()dog.run()cat.run()

输出结果:

Dog run….

Cat run….

当子类和父类都存在相同的方法时,子类方法覆盖了父类的方法,在代码执行时,调用的是子类中的那个方法。

多态

def run_animal(animal):    animal.run()run_animal(dog)run_animal(cat)

输出结果:

Dog run….

Cat run….

可见,Animal类型的参数,可以传入 Dog,Cat 类型变量,只有传入的参数类型是 Animal 的子类,都可以接收。

鸭子模型

对于静态语言(Java)来说,如果需要传入 Animal 类型,则传入的对象必须是 Animal 类型或者他的子类,否则,将无法调用 run() 方法。但是,对用 Python 这种动态语言来说,则不一定需要传入 Animal 类型,只需保证传入的对象有一个 run() 方法即可。

type() 获取对象信息

使用 type() 函数可以判断出对象的类型。

print(type(123))print(type("123"))print(type(None))print(type([1,2,3]))print(type((1,2,3)))print(type({"Android":"Google","iOS":"Apple"}))print(type(True))print(type(abs))  # abs 绝对值,内置函数print(type(dog))

输出结果:

判断对象是否是函数

import typesdef function_add():    passfunction_res  = type(function_add) == types.FunctionTypeprint(function_res)

输出结果: True

对象是否是类的实例 - isinstance()

print("dog is Animal = " , isinstance(dog,Animal))print("123 is int = " , isinstance(123,int))print("'123' is str = " , isinstance('123',str))print("b'a' is bytes = " , isinstance(b'a',bytes))print("[1,2,3] is list or tuple",isinstance([1,2,3],(list,tuple))) # 判断一个变量是否是某些类型中的其中一种

输出结果:
dog is Animal = True

123 is int = True

‘123’ is str = True

b’a’ is bytes = True

[1,2,3] is list or tuple True

dir() 获取对象所有属性和方法

print(dir("abc"))print(dir(123))

输出结果:
[‘add‘, ‘class‘, ‘contains‘, ‘delattr‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getitem‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘init‘, ‘init_subclass‘, ‘iter‘, ‘le‘, ‘len‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘new‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rmod‘, ‘rmul‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘subclasshook‘, ‘capitalize’, ‘casefold’, ‘center’, ‘count’, ‘encode’, ‘endswith’, ‘expandtabs’, ‘find’, ‘format’, ‘format_map’, ‘index’, ‘isalnum’, ‘isalpha’, ‘isdecimal’, ‘isdigit’, ‘isidentifier’, ‘islower’, ‘isnumeric’, ‘isprintable’, ‘isspace’, ‘istitle’, ‘isupper’, ‘join’, ‘ljust’, ‘lower’, ‘lstrip’, ‘maketrans’, ‘partition’, ‘replace’, ‘rfind’, ‘rindex’, ‘rjust’, ‘rpartition’, ‘rsplit’, ‘rstrip’, ‘split’, ‘splitlines’, ‘startswith’, ‘strip’, ‘swapcase’, ‘title’, ‘translate’, ‘upper’, ‘zfill’]

[‘abs‘, ‘add‘, ‘and‘, ‘bool‘, ‘ceil‘, ‘class‘, ‘delattr‘, ‘dir‘, ‘divmod‘, ‘doc‘, ‘eq‘, ‘float‘, ‘floor‘, ‘floordiv‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘getnewargs‘, ‘gt‘, ‘hash‘, ‘index‘, ‘init‘, ‘init_subclass‘, ‘int‘, ‘invert‘, ‘le‘, ‘lshift‘, ‘lt‘, ‘mod‘, ‘mul‘, ‘ne‘, ‘neg‘, ‘new‘, ‘or‘, ‘pos‘, ‘pow‘, ‘radd‘, ‘rand‘, ‘rdivmod‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘rfloordiv‘, ‘rlshift‘, ‘rmod‘, ‘rmul‘, ‘ror‘, ‘round‘, ‘rpow‘, ‘rrshift‘, ‘rshift‘, ‘rsub‘, ‘rtruediv‘, ‘rxor‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘sub‘, ‘subclasshook‘, ‘truediv‘, ‘trunc‘, ‘xor‘, ‘bit_length’, ‘conjugate’, ‘denominator’, ‘from_bytes’, ‘imag’, ‘numerator’, ‘real’, ‘to_bytes’]

注意:类似 XXX的属性和方法在 Python 中都是特殊用途的,比如 len方法返回长度,当调用 len() 函数获取对象的长度,实际上,在 len() 函数内部,他自动调用该对象的 len() 方法。

所以,以下写法是等价的:

print(len("123456"))print("123456".__len__())

我们自定义的类,想要使用 len(myObj),就需要自己写一个 len() 方法,因为, len() 方法内部调用的是 len() 方法。

class Rectangle(object) :    def __init__(self,length,width):        self.length = length        self.width = width    def __len__(self):        return 2*(self.length + self.width)rect = Rectangle(10,7)print(len(rect))

如果没有定义 len() 方法,那么输出报错:

Traceback (most recent call last):  File "E:/Python/HelloWorld.py", line 248, in <module>    print(len(rect))TypeError: object of type 'Rectangle' has no len()

另外,Python 提供了操作属性的方法:

  • getattr() : 获取属性
  • setattr() : 设置属性
  • hasattr() : 判断是否存在属性


class Rectangle(object) :def __init__(self,length,width):    self.length = length    self.width = widthdef __len__(self):    return 2*(self.length + self.width)rect = Rectangle(10,7)print("has attr length = ",hasattr(rect,"length"))print("has attr area = ",hasattr(rect,"area"))setattr(rect,"centerX",10)print("has attr centerX = ",hasattr(rect,"centerX"))print("get attr centerX = ",getattr(rect,"centerX"))

输出结果:

has attr length = True

has attr area = False

has attr centerX = True

get attr centerX = 10

实例属性和类属性

实例属性只属于某个实例,每个实例的属性的值可能不相同。
类属性是属于某个类的,所有实例共享同一个属性。

class Teacher(object):    job_occupation = "teacher"    def __init__(self, name):        self.name = name    def print(self):        print("name = ", self.name, "job = ",self.job_occupation)jane_teacher = Teacher("jane")tom_teacher = Teacher("tom")jane_teacher.print()tom_teacher.print()print(Teacher.job_occupation)

上面示例中, job_occupation 即是类属性,

输出结果:

name = jane job = teacher

name = tom job = teacher

teacher

注意:当实例属性和类属性使用相同的名字时,实例属性将屏蔽掉类属性。

实例动态绑定属性和方法

当创建了类的实例后,我们可以给该实例绑定任何属性和方法。

class Student(object):    passstu = Student()print("stu has attr name = ",hasattr(stu,"name"))  # False# 实例对象绑定属性stu.name = "tomcat"print("stu has attr name = ",hasattr(stu,"name"))  # Trueif hasattr(stu,"name"):    print("name = ",stu.name)# 实例对象绑定方法def set_stu_name(self,name):    self.name = namefrom types import MethodTypestu.set_stu_name =  MethodType(set_stu_name,stu)stu.set_stu_name("luck")print(stu.name)# 给所有实例绑定方法,即给 class 类绑定方法def set_score(self,score):    self.score = scoreStudent.set_score = set_scorestu2 = Student()stu2.set_score(90)print(stu2.score)

输出结果:

stu has attr name = False

stu has attr name = True

name = tomcat

luck

90

多重继承

Python 允许使用多重继承,即一个类继承多个类。

class Runnable(object):    def run(self):        print("run....")class Sleepable(object):    def sleep(self):        print("slepp...")class LiveAnimal(Runnable,Sleepable) :    def printAbility(self):        self.run()        self.sleep()liveAnimal = LiveAnimal()liveAnimal.printAbility()

输出结果:

run….

slepp…

定制对象的输出形式 : _ str _

和 Java 相似,默认情况下,直接打印出对象时,输出的是对象的内存地址,我们可以重写 _ str _ 方法来定制输出结果。

class Person(object):    def __init__(self,name,age):        self.name = name        self.age = ageperson = Person("mike",22)print(person)

没有重写 _ str _ 方法,输出结果:

<main.Person object at 0x01D8C4B0>

下面我们重写了 Person 的 _ str_ 方法,定制出我们想要的输出结果。

class Person(object):    def __init__(self, name, age):        self.name = name        self.age = age    def __str__(self):        return "name = %s , age = %s" % (self.name, self.age)person = Person("mike", 22)print(person)

输出结果:

name = mike , age = 22

原创粉丝点击