Python 深入浅出 - 面向对象

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):
    pass
class Cat(Animal):
    pass

dog = 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 types

def function_add():
    pass
function_res  = type(function_add) == types.FunctionType
print(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 = width

def __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):
    pass

stu = Student()
print("stu has attr name = ",hasattr(stu,"name"))  # False
# 实例对象绑定属性
stu.name = "tomcat"
print("stu has attr name = ",hasattr(stu,"name"))  # True
if hasattr(stu,"name"):
    print("name = ",stu.name)

# 实例对象绑定方法
def set_stu_name(self,name):
    self.name = name

from types import MethodType
stu.set_stu_name =  MethodType(set_stu_name,stu)
stu.set_stu_name("luck")
print(stu.name)

# 给所有实例绑定方法,即给 class 类绑定方法
def set_score(self,score):
    self.score = score

Student.set_score = set_score

stu2 = 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 = age

person = 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):
    pass
class Cat(Animal):
    pass

dog = 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 types

def function_add():
    pass
function_res  = type(function_add) == types.FunctionType
print(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 = width

def __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):
    pass

stu = Student()
print("stu has attr name = ",hasattr(stu,"name"))  # False
# 实例对象绑定属性
stu.name = "tomcat"
print("stu has attr name = ",hasattr(stu,"name"))  # True
if hasattr(stu,"name"):
    print("name = ",stu.name)

# 实例对象绑定方法
def set_stu_name(self,name):
    self.name = name

from types import MethodType
stu.set_stu_name =  MethodType(set_stu_name,stu)
stu.set_stu_name("luck")
print(stu.name)

# 给所有实例绑定方法,即给 class 类绑定方法
def set_score(self,score):
    self.score = score

Student.set_score = set_score

stu2 = 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 = age

person = 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):
    pass
class Cat(Animal):
    pass

dog = 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 types

def function_add():
    pass
function_res  = type(function_add) == types.FunctionType
print(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 = width

def __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):
    pass

stu = Student()
print("stu has attr name = ",hasattr(stu,"name"))  # False
# 实例对象绑定属性
stu.name = "tomcat"
print("stu has attr name = ",hasattr(stu,"name"))  # True
if hasattr(stu,"name"):
    print("name = ",stu.name)

# 实例对象绑定方法
def set_stu_name(self,name):
    self.name = name

from types import MethodType
stu.set_stu_name =  MethodType(set_stu_name,stu)
stu.set_stu_name("luck")
print(stu.name)

# 给所有实例绑定方法,即给 class 类绑定方法
def set_score(self,score):
    self.score = score

Student.set_score = set_score

stu2 = 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 = age

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值