python 面向对象

面向对象

对象:是指现实中的物体实体化,对象有很过属性(名字、年龄..),也有很多行为(学习、吃饭..),实例即对象。对象同时也是通过类定义的数据结构实例,对象包括两个数据成员(类变量和实例变量)和方法。对象可以包含任意数量和类型的数据。

实例化:创建一个类的实例,类的具体对象化,实例就是类的实例化,d1 = gog(),d1即为实例

:拥有相同属性和方法(行为)的对象划为一组,称为类,类是创建对象的工具

方法:类中定义的函数

类变量:在类中被定义的变量,通常以self.variable的形式被定义,类变量通常不作为实例变量使用

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行修改,这个过程叫方法的覆盖,也叫方法的重写

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

Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。

类定义  语法格式

  class 类名(继承列表):

    """类的文档字符串"""

    类变量的定义

    实例方法的定义

    类方法的定义(@classmethod)

    静态方法的定义(@staticmethod)

作用:

  创建一个类,类用于描述对象的行为和属性,类用于创建此类的一个或者多个对象(实例)类名实质上是变量,它绑定一个类

类的文档字符串

类内第一个没有赋值给任何变量的字符串为类的文档字符串,类的文档字符串可以用类的 __doc__属性访问

help(Dog)    查看文档字符串

类.__doc__属性用来绑定文档字符串

类变量的定义

类变量就类的属性,此属性属于类,不属于此类的实例

作用:通常用来存储该类创建的对象的共有属性

说明:类变量可以通过该类或该类的实例直接访问;类变量可以通过此类的实例对象的__class__属性间接访问

class Human:
    total_count = 0  # 类变量

    def __init__(self, name):
        print(name, '对象被创建')


print(Human.total_count)  # 类直接访问类变量 0
h1 = Human('小张')
print(h1.total_count)  # 0 用此类的实例可以访问类变量
h1.total_count = 100  # 为对象添加实例变量
print(h1.total_count)  # 100, 优先访问对象的实例变量
print(Human.total_count)  # 0, 访问类的类变量
print(h1.__class__.total_count)  # 0 通过此类的实例对象的__class__属性来访问类变量

初始化方法 __init__()

1、初始化方法__init__()会在构造函数创建实例后自动调用

2、初始化方法如果需要return语句返回,则只能返回None

3、一般类都会倾向于将(实例)对象创建为有初始化状态的

4、实例方法至少有一个形参,第一个形参代表调用这个方法的实例,一般命名为'self',因此类可能会定义一个名为__init__()的特殊方法(构造方法)

5、__init__有形参时,参数会通过__init__()传递到实例化对象上。

class complex:
    # 构造函数,在实例化时做一些类的初始化工作,__init__用来传参的
    def __init__(self, name, age):  # 定义类的方法
        self.name = name    # 实例变量(静态属性)
        self.age = age

x = complex("作者",23)       # 类的实例化,变成具体对象
print(x.name,x.age)

# 作者 23

类的方法与普通的函数只有一个特殊的区别————他们必须有一个额外的第一参数名称self,按照惯例它的名称是self,谁调用这个类的方法,self就指向谁。self代表类的实例化,而非类

class Test:             #定义一个名为Test的类
    def prt(self):      #定义类的方法prt
        print(self)
        print(self.__class__)   # self.__class__指向类

t = Test()  #类的实例化
t.prt()     #访问类的方法

# <__main__.Test object at 0x000001836DFE10B8>
# <class '__main__.Test'>

self代表的是类的实例,代表当前对象的地址,而self.__class__则指向类名。

self不是python的关键词,我们把self换成其他的表示符也是可以的(在这里我们把self换成runoob)

class Test:  # 定义一个名为Test的类
    def prt(runoob):  # 定义类的方法prt
        print(runoob)
        print(runoob.__class__)


t = Test()  # 类的实例化
t.prt()  # 访问类的方法
# <__main__.Test object at 0x000001836DFE10B8>
# <class '__main__.Test'>

类的__slots__列表

作用:限定一个类创建的实例只能有固定属性(实例属性),不允许对象添加列表以外的属性(实例变量)

说明:__slots__列表绑定一个字符串列表,含有__slots__列表的类所创建的实例对象没有__dict__属性,即此实例不用字典来存储对象的属性(实例变量)

__slots__ = [" ", " "]

class Human:
    # 以下列表限制此类的对象只能有'name' 和'age' 属性
    __slots__ = ['name', 'age']

    def __init__(self, name, age):
        self.name, self.age = name, age


h1 = Human("Tarena", 15)
print(h1.age)  # 15
# h1.Age = 18  # 出错,h1对象没有Age属性,也不允许有Age属性
print(h1.age)  # 15

类方法 @classmethod

类方法是用于描述类的行为的方法,类方法属于类,不属于类的实例

说明:类方法需要使用@classmethod装饰器定义,

  def关键词来定义一个方法,类方法至少有一个形参,第一个参数用于绑定类,约定写为" cls ",类和该类的实例都可以调用类的方法

class people:  # 定义一个类
    # 定义类的属性
    name = ''
    age = 0
    # 定义私有属性,私有属性在类外部无法直接进行访问
    _weight = 0

    # 定义构造的方法
    def __init__(self, n, a, w):
        # 定义类的初始化属性
        self.name = n
        self.age = a
        self._weight = w

    # 定义类的方法
    @classmethod
    def speak(cls):
        print("%s说:我%d岁" % (self.name, self.age))


# 实例化类  把一个类变成具体对象叫做类的实例化
p = people("作者", 18, 30)
p.speak()       # 作者说:我18岁

静态方法 @staticmethod

静态方法是定义在类内部的函数,此函数的作用域是类的内部

说明:静态方法需要使用 @staticmethod装饰器定义,

  静态方法与普通函数定义相同,不需要传入self实例参数和cls参数,静态方法只能凭借该类或类创建的实例调用,静态方法不能访问类变量和实例变量(属性)

class A:
    @staticmethod
    def myadd(a, b):
        return a + b


print(A.myadd(100, 200))  # 300
a = A()  # 创建实例
print(a.myadd(300, 400))  # 700

实例方法、类方法、静态方法、函数小结

  不想访问类内和实例内的变量,用静态方法

  只想访问类内变量,不想访问实例变量,用类方法

  即要访问内变量,也想访问实例变量用实例方法

  函数与静态方法相同,只是静态方式的作用域定义在类内

class Classname:
    @staticmethod
    def fun():
        print('静态方法')

    @classmethod
    def a(cls):
        print('类方法')

    # 普通方法
    def b(self):
        print('普通方法')


Classname.fun()     # 静态方法
Classname.a()       # 类方法

C = Classname()     
C.fun()             # 类方法
C.a()               # 类方法
C.b()               # 普通方法

类的实例化

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

d1 = dog() # 调用构造函数创建实例化对象

类对象

类对象支持两种操作:属性引用和实例化。

类对象创建后,类命名空间中的所有命名都是有效属性名,类定义如下所示:

class Myclass:  # 定义一个自己的类
    """一个简单的类实例"""
    i = 12345  # 类变量

    def f(self):  # 定义类的方法
        return "你好呀"


# 类的实例化,用x来绑定以便后面使用,不然用完之后就释放了
x = Myclass()  # 把一个类变成具体对象的过程叫做实例化(初始化)
# 访问类的属性和方法
print("Myclass类的属性i:", x.i)     # 12345
print("Myclass类的方法f:", x.f())   # 你好呀!

 python支持 在类的外面 创建类的属性

class Dog:
    def eat(self, food):
        # print("小狗正在吃:", food)
        print(self.color, '', self.kinds, '正在吃', food)


dog1 = Dog()    # 类的实例化
dog1.kinds = '京巴'  # 为dog1对象添加kinds属性,绑定为'京巴'
dog1.color = '白色'  # dog1添加属性 为'白色'
dog1.color = '黄色'  # 改变dog1的color属性

# 访问dog1 的属性
print(dog1.color, "", dog1.kinds)  # 黄色 的 京巴

dog2 = Dog()
dog2.kinds = '哈士奇'
dog2.color = '黑白相间'
print(dog2.color, '', dog2.kinds)  # 黑白相间 的 哈士奇

dog1.eat('骨头')  # 黄色 的 京巴 正在吃 骨头
dog2.eat('窝头')  # 黑白相间 的 哈士奇 正在吃 窝头

# 定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0,在变量前面加双下划线

删除属性del语句

  del 变量名  删除变量

  del 列表[整数表达式]  删除列表中的元素

  del 字典[键]        删除字典中的键

  del 对象.属性       删除对象的属性

析构方法:

  class 类名:

    def __del__(self):

      ......

说明:析构方法在对象被销毁时做任何事情,因为销毁的时间难以确定

预置实例属性

  __dict__属性

  __dict__属性绑定一个存储此实例自身变量的字典

class Dog:
    pass


dog1 = Dog()
print(dog1.__dict__)  # {}
dog1.kinds = '京巴'
print(dog1.__dict__)  # {'kinds': '京巴'}

__class__属性:

  此属性用于绑定创建此实例的类

 作用:可以借助于此属性来访问创建此实例的类

class Dog:
    pass


dog1 = Dog()
print(dog1.__class__)  # <class '__main__.Dog'>
dog2 = dog1.__class__()
print(dog2.__class__)  # <class '__main__.Dog'>

用于类的函数:

  isinstance(obj, class_or_tuple) 返回这个对象obj是否是某个类的对象或某些类中的一个类的对象,如果是则返回True,否则返回False,type(obj) 返回对象的类型

继承/派生

继承是指从已有的类中派生出新的类,新类具有原类的行为,并能扩展新的行为

派生类就是从一个已有类中衍生成新类,在新类上可以添加新的属性和行为

作用:1.用继承派生机制,可以将一些共有功能加在基类中,实现代码的共享

      2、在不改变基类的代码的基础上改变原有的功能

名词:基类(base class)/超类(super class)/父类(father class)

     派生类(derived class) / 子类(child class)

单继承

单继承:

  语法:

    class 类名(基累名):

      语句块

  说明:单继承是指由一个基类衍生出的新的类

class Derived_Class_Name(Base_Class_Name1):
    <statement-1>
    .
    .
    <statement-N>

单继承实例

class Human:  # 人类的共性
    def say(self, what):
        print("say:", what)

    def walk(self, distance):  # 走路
        print("走了", distance, '公里')


class Student(Human):
    def study(self, subject):
        print("正在学习:", subject)


class Teacher(Student):
    '''说话,行走,教学'''
    def teach(self, subject):
        print("正在教:", subject)

h1 = Human()
h1.say('天气晴了')
h1.walk(5)
print('---------------')
s1 = Student()
s1.walk(4)
s1.say('感觉有点累')
s1.study('Python')
print('===============')
t1 = Teacher()
t1.walk(6)
t1.say('吃点啥好呢')
t1.teach('面向对象')
t1.study('转魔方')

继承说明:python3 任何类都直接或间接的继承自object类,object 类是一切类的超类

类的__base__属性:__base__属性用来记录此类的基类

覆盖

覆盖是指在有继承关系的类中,子类中实现了与基类同名的方法,在子类的实例调用该方法时,实际调用的是子类中的覆盖版本

class A:
    def works(self):
        print("A.works被调用")

class B(A):
    """B类继承A类"""
    def works(self):
        print("B.works被调用")

a = A()
a.works()  # A.works被调用

b = B()
b.works()  # B方法被调用

用类名显式调用

子类对象显式调用基类(被覆盖)方法的方式:基类名.方法名(实例, 实际调用传参)

class A:
    def works(self):
        print("A.works被调用")

class B(A):
    ''' B类继承自A类'''
    def works(self):
        print("B.works被调用")

b = B()
b.works()  # B.works被调用
A.works(b)  # 用类名显式调用, A.works被调用

super函数

super(cls, obj)返回绑定超类的实例(要求obj必须是cls类型的实例),一般obj就是selfcls一般就是当前类的类名

super()  返回父类的实例,

常见用法:super(__class__, 实例方法的第一个参数),必须在方法内调用,一般super(class_name, self).父类方法  # 中间参数可以省略,如下例

作用:借助super() 返回的实例间接调用其父类的覆盖方法

super().父类方法()

class A:
    def works(self):
        print("A.works被调用")


class B(A):
    """B类继承自A类"""
    def works(self):
        print("B.works被调用")

    def super_work(self):
        self.works()  # B.works被调用
        super(B, self).works()  # A.works被调用
        super().works()  # A.works被调用


b = B()
b.works()  # B.works被调用
super(B, b).works()  # A.works被调用
b.super_work()  # ...
# B.works被调用
# A.works被调用
# A.works被调用

super().works()  # 出错,只能在方法内调用

显式调用基类的初始化方法

当子类中实现了 __init__方法,基类的构造方法并不会被调用,def __init__(self, ...)

super().__init__(n,a)    # 参数不填的话,默认调用父类的所有初始化参数

class Human:
    def __init__(self, n, a):
        self.name, self.age = n, a
        print("Human的__init__方法被调用")

    def infos(self):
        print("姓名:", self.name)
        print("年龄:", self.age)


class Student(Human):
    def __init__(self, n, a, s=0):
        super().__init__(n, a)  # 显式调用父类的初始化方法
        self.score = s  # 添加成绩属性
        print("Student类的__init__方法被调用")

    def infos(self):
        super().infos()  # 调用父类的方法
        print("成绩:", self.score)


s1 = Student('小张', 20, 100)
s1.infos()

多继承

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    <statement-N>

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

class people:
    name = ''
    age = 0
    __weight = 0

    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w

    def speak(self):
        print("%s 说: 我 %d 岁。" % (self.name, self.age))

class speaker():
    topic = ''
    name = ''

    def __init__(self, n, t):
        self.name = n
        self.topic = t

    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s" % (self.name, self.topic))


# 多继承
class sample(speaker, people):
    a = ''

    def __init__(self, n, a, w, t):
        # 调用父类的构函数
        people.__init__(self, n, a, w)
        speaker.__init__(self, n, t)


test = sample('凌逆战', "大学生", 23, 'python')
test.speak()  # 方法名重复了,默认调用的是括号中排前地父类的方法
# 我叫 凌贤鹏,我是一个演说家,我演讲的主题是 python

方法重写

如果父类方法的功能不能满足需求,可以在子类重写父类的方法

class parent:  # 定义父类
    def my_method(self):
        print("调用父类的方法")


class child(parent):  # 定义子类
    def my_method(self):
        print("调用子类方法")


c = child()  # 子类实例

# 子类调用重写方法
c.my_method()       # 调用子类方法

# 用子类对象调用父类已被覆盖的方法
super(child, c).my_method()  
# 调用父类的方法

super()函数是用于调用父类(超类)的方法

Python 子类继承父类构造函数说明

类属性与方法

类的私有属性

__private_attrs:两个写划线开头,声明该属性为私有类,不能在类地外部被使用或直接访问,在类内部的方法使用时self.private_attrs

类的方法

在类地内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含self,且为第一个参数,self代表的是类的实例。

self的名字并不是规定死的,也可以是其他的,但最好按照规定用self

类的私用方法

__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类地外部调用。self.__private_methods

类的私有属性

class JustCounter:
    __secretCount = 0  # 私有变量
    publicCount = 0  # 公开变量

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print(self.__secretCount)


counter = JustCounter()
counter.count()     # 1
counter.count()     # 2
print(counter.publicCount)  # 2
print(counter.__secretCount)  
# 报错,实例不能访问私有变量
# Traceback (most recent call last):
#   File "test.py", line 16, in <module>
#     print (counter.__secretCount)  # 报错,实例不能访问私有变量
# AttributeError: 'JustCounter' object has no attribute '__secretCount'

类的私有方法

class Site:
    def __init__(self, name, url):
        self.name = name  # public
        self.__url = url  # private

    def who(self):
        print('name: ', self.name)
        print('url : ', self.__url)

    def __foo(self):  # 私有方法
        print('这是私有方法')

    def foo(self):  # 公共方法
        print('这是公共方法')
        self.__foo()


x = Site('菜鸟教程', 'www.runoob.com')
x.who()  # 正常输出
x.foo()  # 正常输出
x.__foo()  # 报错

类的专有方法

  Python除了自定义私有变量和方法外,还可以定义专有方法。专有方法是在特殊情况下或使用特殊语法时由python调用的,而不是像普通方法一样在代码中直接调用。看到形如__XXX__的变量或函数名时就需要注意下,这在python中是有特殊用途的 

  • __init__构造函数,在生成对象时调用
  • __del__:析构函数,释放对象时使用
  • __repr__:打印,转换
  • __setitem__ :按照索引赋值
  • __getitem__按照索引获取值
  • __len__获得长度
  • __str__:返回用户看到的字符串
  • __iter__:返回可迭代对象
  • __cmp__:比较运算
  • __call__使类像函数一样调用
  • __add__:加运算
  • __sub__:减运算
  • __mul__:乘运算
  • __div__:除运算
  • __mod__:求余运算
  • __pow__:乘方

__str__

class Student(object):
    def __init__(self, name):
        self.name = name
 
print(Student('zth'))    # <__main__.Student object at 0x03DFDDB0>

__str__方法必须要return一个字符串类型的返回值,

class Student(object):
    def __init__(self, name):
        self.name = name
        
    def __str__(self):
        return "学生的姓名:%s"%self.name
 
print(Student('zth'))
# 学生的姓名:zth

__iter__

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。__next__() 方法会返回下一个迭代器对象。

如果想要将一个类用于 for ... in 循环,类似 list 或 tuple 一样,就必须实现一个__iter__()  方法。该方法返回一个迭代对象,Python 的 for  循环会不断调用该迭代对象的  __next__()  方法,获得循环的下一个值,直到遇到 StopIteration 错误时退出循环。

class Fib(object):
    def __init__(self):
        self.a , self.b = 0,1           # 初始化两个计数器 a、b
        
    def __iter__(self):
        return self                     # 实例本身就是迭代对象。故返回自己
    
    def __next__(self):
        self.a ,self.b = self.b ,self.a+self.b      # 计算下一个值
        if self.a > 100:                 # 退出循环的条件
            raise StopIteration();
        return self.a                   # 返回下一值
 
for n  in Fib():
    print(n)
1
1
2
3
5
8
13
21
34
55
89
结果

__getitem__

上面创建的对象虽然能够作用于 for 循环,和 list 有点像,但是不能将它当成 list 使用。比如取第3个元素:

>>> Fib()[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Fib' object does not support indexing

若要像list一样按照索引来获取元素,需要实现__getitem__()方法

class temp():
    def __init__(self):
        self.a = [1, 2, 3, 4, 5]

    def __getitem__(self, index):
        return self.a[index]


if __name__ == "__main__":
    shili = temp()
    print(shili[3])     # 4

使用 __getitem__ 和 __iter__ 可以使类成为一个迭代器

# -*- coding: utf-8 -*-
 
class Library(object):
    def __init__(self):                                                     
        self.books = { 'title' : 'a', 'title2' : 'b', 'title3' : 'c', }
        
    def __getitem__(self, i):
        return self.books[i]
        
    def __iter__(self):
        # 方法1 使用生成器
        for titles in self.books:
            yield self.books[titles]
        # 方法2 使用迭代器
#        return self.books.itervalues()
 
library = Library()
 
# 1.普通方法
print library.books['title']
 
# 2.使用__getitem__
print library['title']
 
# 3.迭代器
for book in library:
    print book

__call__

定义一个__call__()方法,就可以直接对实例进行调用

class temp():
    def __call__(self, a, b):
        return a+b


if __name__ == "__main__":
    shili = temp()
    ab_sum = shili(1,2)
    print(ab_sum)     # 3

参考:https://blog.csdn.net/qq_41573234/article/details/82316207

运算符重载

class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return 'Vector (%d, %d)' % (self.a, self.b)

    def __add__(self, other):
        return Vector(self.a + other.a, self.b + other.b)


v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)      # Vector(7,8)

 

posted @ 2019-10-24 21:35  凌逆战  阅读(831)  评论(0编辑  收藏  举报