Python面向对象

面向对象

面向对象

  • 一种认识世界、分析世界的方法论。将事物抽象成类

  • 类是抽象的概念,是事物的抽象,是一类事物的共同特征的集合(属性方法的集合)

对象

  • instanceobject;是类的具象,是一个实体

哲学

  • 一切皆对象
  • 对象(类)是数据操作的封装
  • 对象是独立的,对象之间可以相互作用
  • OOP现有最接近人类认知的编程范式

面向对象三要素

Python面向对象_第1张图片

Python类

  • 定义
class ClassName:
	block
  1. 必须使用class关键字
  2. 类名必须是用大驼峰命名
  3. 类定义完成后,即产生了一个类对象,绑定到标识符ClassName

Python面向对象_第2张图片

类对象及类属性

  • 类对象,定义类即产生一个类对象
  • 类属性,类定义中的变量和类定义的方法都是类的属性
  • 类变量,上图中x是类MyClass的变量
  • foo是方法对象method,不是普通的函数对象function,一般要求至少有一个参数(可以是self,只是惯用标识符,可换名字)。
  • self指代当前实例本身

实例化

  • 语法:a = MyClass()
  • 实例化只能创建一个该类实例(对象),新的对象
  • 实例化:__new__ → 实例化后会自动调用初始化方法。
  • 初始化:__init__(self)(return None)首个参数必须是self,其他参数随意,可以不定义,在实例化后隐式调用
  • 方法属于类

实例对象instance

  • 类实例化后必获得一对象,就是实例对象
  • 实例对象会绑定方法,调用方法时采用instance.function();函数签名是function(self),self即为instance,function保存在instance中,而不是class中。称为实例变量
  • 实例变量是每个实例独有的;类变量是类的变量,是类的所有实例共享的属性和方法
  • Python中每个对象都有不同的属性。函数、类都是对象,类的实例也是对象

self

Python面向对象_第3张图片

实例变量和类变量

  • 实例变量是每个实例独有的;类变量是类的变量,是类的所有实例共享的属性和方法
class Person:
    age = 3
    def __init__(self,name):
        self.name = name

tom = Person('tom',22) # __init__() takes 2 positional arguments but 3 were given
tom = Person('tom') # 实例化,初始化
jax = Person('jax')

print(tom.name,tom.age) # tom 3
print(jax.name,jax.age) # jax 3
print(Person.age) # 3
Person.age = 30 # 赋值重新定义变量
print(Person.age,tom.age,jax.age) # 30 30 30

属性访问顺序

  • 所有对象可以动态给自己增加一个属性。实例.__dict__[变量名]实例.变量名都可以访问
  • 访问属性
  • 类的属性共享,实例的属性不共享
  • 实例属性的查找顺序
  • 实例使用 . 点号访问属性,先找自己的字典__dict__;若没有,则通过属性__class__找自己的类,然后去类中的字典__dict__中找
  • 若使用__dict__[变量名]访问,则不用以上方式查找。此为指明使用字典的key查找,不是属性查找

装饰一个类

  • 增加类变量
def add(name,cls):
    cls.NAME = name # 动态增加类属性
  • 增加类变量改进成装饰器
def add_name(name='TOM'):
    def wrapper(cls):
        cls.NAME = name
        return cls
    return wrapper
@add_name(name='JAX') # Person = wrapper(Person)
class Person:
    AGE = 3
print(Person.NAME) # JAX
print(Person.AGE) # 3

类方法

  • 通过cls可以直接操作类的属性,无法操作类的实例
class Pe:
    @classmethod
    def class_method(cls):
        print('class={0.__name__}({0})'.format(cls)) # class = Pe()
        cls.h = 111
Pe.class_method()
print(Pe.__dict__) # {...}

静态方法

  • 调用时不会隐式的传入参数
class P:
    @classmethod
    def class_method(cls):
        print('class={0.__name__}({0})'.format(cls)) # class=P()
        cls.h = 123
    @staticmethod
    def static_method():
        print(P.h) # 123

P.class_method()
P.static_method()
print(P().static_method()) # None
print(P.__dict__) # {...}
  • 普通方法:实例调用方法时会将自身作为第一参数传入(self),类调用时则不传入参数
  • 类方法:添加装饰器后,调用时都会将其类作为第一参数传入(cls)
  • 静态方法:调用时不会将实例&类作为第一参数传入(*any)
  • 类未实例化则无实例,有类未必有实例,有实例必有类

私有属性

  • 私有属性(使用双下划线开头的属性名)
class Person:
    def __init__(self,name,age=11):
        self.name = name
        self.__age = age

    def growup(self,i=1):
        if i > 0 and i < 100:
            self.__age += i
p1=Person('tom')
p1.growup(22) # 33
p1.__age=123
print(p1.__age) # 'Person' object has no attribute '__age'
  • 访问私有变量(双下划线声明实例变量时解释器会将其改名为‘_类名__变量名’)
class Person:
    def __init__(self,name,age=11):
        self.name = name
        self.__age = age

    def growup(self,i=1):
        if i > 0 and i < 100:
            self.__age += i

    def getage(self):
        return self.__age
p1 = Person('tom')
p1.__age = 25
print(p1.__age) # 25
print(p1.getage()) # 11
print(p1.__dict__) # {'name': 'tom', '_Person__age': 11, '__age': 25}
  • 保护变量(变量名前使用一个下划线)
class Person:
    def __init__(self,name,age=17):
        self.name = name
        self._age = age

tom = Person('Tom')
print(tom._age) # 17
print(tom.__dict__) # {'name': 'Tom', '_age': 17}
  • 属性装饰器
class P:
    def __init__(self,name,age=15):
        self.name = name
        self.__age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self,age):
        self.__age = age

    @age.deleter
    def age(self):
        # del self.__age
        print('del')

tom = P('Tom')
print(tom.age) # 15
tom.age = 23
print(tom.age) # 23
del tom.age # del

面向对象例题

  • 随机整数生成类,指定生成的个数、范围、每批生成的个数

method 1:普通类实现

import random
class RandomGen:
    def __init__(self,start=1,stop=100,patch=10): # 实例化初始化,提供类属性
        self.start = start
        self.stop = stop
        self.patch = patch

    def generate(self):
        return [random.randint(self.start, self.stop) for x in range(self.patch)]

a = RandomGen()
print(a.generate())

method 2:类方法,作为工具实现

import random
class RandomGen:
    @classmethod  # 类方法
    def generate(self,start=1,stop=100,patch=10):
        return [random.randint(start, stop) for x in range(patch)]

a = RandomGen()
print(a.generate())

method 3:生成器实现version 1

import random
class RandomGenerator:
    def __init__(self,start=1,stop=100,patch=10): # 实例化初始化,提供类属性
        self.start = start
        self.stop = stop
        self.patch = patch
        self._gen = self._generate()
    def _generate(self):
        while 1:
            yield random.randint(self.start, self.stop) # 返回一个随机数

    def generate(self,count=0):
        patch = self.patch if count<=0 else count # 指定生成的次数,未指定则用缺省值(类属性patch=10)
        return [next(self._gen) for x in range(patch)] # 返回指定次数的随机数

a = RandomGenerator()
print(a.generate())
print(a.generate(5))

method 4:生成器实现version 2

import random
class RandomGenerator:
    def __init__(self,start=1,stop=100,patch=10):
        self.start = start
        self.stop = stop
        self.patch = patch
        self._gen = self._generate()

    def _generate(self):
        while 1: # yield一批数据
            yield [random.randint(self.start, self.stop) for _ in range(self.patch)]

    def generate(self,count=0):
        if count > 0: # 控制次数
            self.patch = count
        return next(self._gen)

a = RandomGenerator()
print(a.generate())
print(a.generate(5))

method 5:使用property

import random
class RandomGenerator:
    def __init__(self, start=1, stop=100, patch=10):
        self.start = start
        self.stop = stop
        self.patch = patch
        self._gen = self._generate()

    def _generate(self):
        while 1:
            yield [random.randint(self.start, self.stop) for _ in range(self.patch)]

    def generate(self):
        return next(self._gen)

    @property
    def patch(self):
        return self._patch

    @patch.setter
    def patch(self,value):
        self._patch = value

a = RandomGenerator()
print(a.generate())
a.patch = 5
print(a.generate())
  • 上题中的类随机生成20个数配对二维坐标并打印
import random
class RandomGen:
    @classmethod  # 类方法
    def generate(self, start=1, stop=100, patch=10):
        return [random.randint(start, stop) for x in range(patch)]

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

a = RandomGen()
points = [Point(x,y) for x, y in zip(a.generate(),a.generate())] # zip函数配对组成二维

for p in points:
    print('({}):({})'.format(p.x, p.y),end = '\t')

继承

  • 语法:
class 子类名(基类1[,基类2,...]):
	block
  • 从父类继承,括号中为继承的类的列表
  • 父类,称为基类,超类
  • 子类,称为派生类
  • 支持多继承,继承可以多级
  • 类定义时,若无基类,则继承自object(在Python3中object是所有对象的根基类)
class A:
	pass
等价于
class A(object)
	pass
  • __base__ # 类的基类
  • __bases__ # 类的基类元组
  • __mro__ #显示方法查找顺序,基类的元组
  • mro() # 同上,返回列表
  • __subclasses__() # 类的子类列表

继承中的访问控制

  • 属性查找顺序
  • 实例的__dict__类__dict__父类__dict__
  • 查找完成后若找到则立即返回,未找到则返回异常
  • 继承时,公有的,子类和实例都可以访问私有的,子类和实例不可直接访问,但私有变量所在的类内的方法中可以访问这个私有变量

方法的重写覆盖

  • super()可以访问到父类的属性
class Animal:
    def shout(self):
        print('Animals shouts')

class Cat(Animal):
    # 覆盖了父类方法
    def shout(self):
        print('miao')
    # 覆盖了自身的方法,显式调用了父类的方法
    # super()可以访问到父类的属性
    def shout(self):
        print(super()) # , >
        print(super(Cat, self)) # , >
        super().shout()
        super(Cat,self).shout() # Animals shouts ,等价于super()

a = Animal()
a.shout() # Animals shouts
c = Cat()
c.shout() # miao

print(a.__dict__) # {}
print(c.__dict__) # {}
print(Animal.__dict__) # {'__module__': '__main__', 'shout': , '__dict__': , '__weakref__': , '__doc__': None}
print(Cat.__dict__) # {'__module__': '__main__', 'shout': , '__doc__': None}
class A:
    def __init__(self,age):
        print('A init')
        self.age = age

    def show(self):
        print(self.age)

class B(A):
    def __init__(self,age,w):
        # 调用父类的__init__方法顺序决定show方法的结果
        super().__init__(age) # A.__init__(age)
        print('B init')
        self.age = age + 1
        self.w = w
b = B(10,5)
b.show()

你可能感兴趣的:(Python面向对象)