Python基础学习14--面向对象2

面向对象

类的成员描述符

类的成员描述符是为了在类中对类的成员属性进行相关操作而创建的一种方式

  • get:获取属性的操作
  • set:修改或者添加属性操作
  • delete:删除属性的操作

如果想使用类的成员描述符,有3中方法:

  • 使用类实现描述器
  • 使用属性修饰符:@property
  • 使用property函数
    • property函数实现简单
    • property(fget, fset, fdel, doc)

无论哪种修饰符都是为了对成员属性进行相应的控制

  • 类的方式:适合多个类中的多个属性共用一个描述符
  • property:在当前类中使用,可以控制一个类中多个属性
  • 属性修饰符:适用于当前类中使用,控制一个类中的一个属性

 类的内置属性

  • __dict__:以字典的方式显示类的成员组成
  • __doc__:获取类的文档信息
  • __name__:获取类的名称,如果在模块中使用,获取模块的名称
  • __bases__:获取某个类的所有父类,以元组的方式显示

代码实例如下:

# 定义学生的成绩
# 成绩只能为整数,否则报错
# 成绩分数限制在[0,100]
class StudentOne(object):

    def get_score(self):
        return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

# 调用方式:
s1 = StudentOne()

s1.set_score(60)    # 设置分数
print(s1.get_score())      # 查询分数

# s1.set_score(999)    # 如果范围不在[0,100],则报错

# 为了方便,节省时间,我们不想写s.set_score(60),直接写s.score = 60不是更快么,这里引入property方法
class StudentTwo(object):
  '''
  未遇行藏谁肯信,如今方表名踪。
  无端良匠画形容。当风轻借力,一举入高空。   才得吹嘘身渐稳,只疑远赴蟾宫。
  雨余时候夕阳红。几人平地上,看我碧霄中。   
''' def fget(self): return self._score def fset(self, value): if not isinstance(value, int): raise ValueError('score must be an integer!') if value < 0 or value > 100: raise ValueError('score must between 0 ~ 100!') self._score = value def fdel(self): pass # property的四个参数顺序是固定的 # fget - - 获取属性值的函数 # fset - - 设置属性值的函数 # fdel - - 删除属性值函数 # doc - - 属性描述信息 score = property(fget, fset, fdel, '这是个property的例子') # 调用方式: s2 = StudentTwo() s2.score = 99 # 设置分数 print(s2.score) # 查询分数 # s2.score = -1 # 报错 # 类的内置属性实例 print(StudentTwo.__dict__) # 显示类的成员组成 print(StudentTwo.__doc__) # 获取类的文档信息 print(StudentTwo.__name__) # 获取类的名称 print(StudentTwo.__bases__) # 获取该类的父类,以元组的方式显示

 输出结果如下:

# s.set_score(60)
# s.get_score()
60
# s.set_score(999)
# ValueError: score must between 0 ~ 100!

# 使用property()方法后的输出结果:
99
# s.set_score = -1
# ValueError: score must between 0 ~ 100!

# print(StudentTwo.__dict__) 
{'__module__': '__main__', '__doc__': '\n    未遇行藏谁肯信,如今方表名踪。\n    无端良匠画形容。当风轻借力,一举入高空。\n    才得吹嘘身渐稳,只疑远赴蟾宫。\n    雨余时候夕阳红。几人平地上,看我碧霄中。\n    ', 'fget': <function StudentTwo.fget at 0x03161588>, 'fset': <function StudentTwo.fset at 0x03161540>, 'fdel': <function StudentTwo.fdel at 0x031614B0>, 'score': <property object at 0x03166C60>, '__dict__': <attribute '__dict__' of 'StudentTwo' objects>, '__weakref__': <attribute '__weakref__' of 'StudentTwo' objects>}

# print(StudentTwo.__doc__) 
    未遇行藏谁肯信,如今方表名踪。
    无端良匠画形容。当风轻借力,一举入高空。
    才得吹嘘身渐稳,只疑远赴蟾宫。
    雨余时候夕阳红。几人平地上,看我碧霄中。

# print(StudentTwo.__name__) 
StudentTwo

# print(StudentTwo.__bases__) 
(<class 'object'>,)

类的常用魔术方法

魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发

魔术方法的统一特征,方法名被前后各两个下划线包裹

更多参考:http://python.jobbole.com/88367/

操作类相关

  • __init__:构造函数
  • __new__:对象实例化方法,此函数比较特殊,一般不需要使用
  • __call__:对象作为函数使用的时候触发
  • __str__:当对象被当作字符串使用的时候调用
  • __repr__:返回字符串,跟__str__的区别:

实例代码如下:

class A():
    def __init__(self):
        print("我是__init__")

    def __call__(self):
        print("我是__call__")

    def __str__(self):
        return "我是__str__"

a = A()

# __call__:作为函数使用时调用,如下:
a()

# __str__:作为字符串使用时调用,如下:
print(a)

输出结果如下:

# 自动调用
我是__init__

# a()
我是__call__

# print(a)
我是__str__

描述符相关

  • __set__
  • __get__
  • __delete__

属性操作相关

  • __getattr__:当访问类中不存在的属性时,自动调用
  • __setattr__:对成员属性进行设置时,自动调用
    • 参数:
      • self用来获取当前对象
      • 被设置的属性名称,以字符串形式出现
      • 需要对属性名称设置值
    • 作用:进行属性设置的时候进行验证或者修改
    • 注意:在该方法中不能对属性直接进行赋值操作,否则会陷入死循环

代码实例如下: 

class Person():
    name = "NoName"
    age = 18

    def __getattr__(self, name):    # 如果访问类中不存在的属性时,会自动调用该方法
        print("我没有name, age之外的属性")      # 如果访问的属性不是name、age,则输出该语句
        print(name)                 # 并输入访问的属性值

    def __setattr__(self, name, value):     # 对成员属性的值进行设置时,会自动调用该方法
        print("设置属性: {0} = {1}".format(name, value))
        # 下面语句会导致死循环
        # self.name = value
        # 此种情况,为了避免死循环,规定统一调用父类魔法函数
        super().__setattr__(name, value)

a = Person()
print(a.name)   # 访问属性name的值

print(a.addr)   # 访问属性addr的值,改属性不存在

# 更改属性age的值为20
a.age = 20

输出结果如下:

# print(a.name)   # 访问属性name的值
NoName

# print(a.addr)   # 访问属性addr的值,改属性不存在
我没有name, age之外的属性
addr
None    # 返回None?why?提示:return

# a.age = 20    # 更改属性age的值为20
设置属性: age = 20

运算分类相关魔术方法

  • __gt__:进行大于判断的时候触发的函数
    • 参数:
      • self
      • 第2个参数是第2个对象
      • 返回值可以实任意值,推荐返回 布尔值

代码实例如下:

class Student():
    def __init__(self, name):
        self._name = name

    def __gt__(self, obj):      # 进行 > 号判断的时候触发调用
        print("猜一猜, {0} 会比 {1} 大吗?".format(self, obj))
        return self._name > obj._name   # 此处返回布尔值,可自定义返回值

stu1 = Student("one")
stu2 = Student("two")
print(stu1 > stu2)    # 字符串比较参考之前的文档

class Stu(Student):
    def __str__(self):
        return '{}'.format(self._name)      # 该处是将<__main__.Student object at 0x03953350>进行优化显示的处理

stu3 = Stu("one")
stu4 = Stu("two")
print(stu3 > stu4)

输出结果如下:

猜一猜, <__main__.Student object at 0x02D149B0> 会比 <__main__.Student object at 0x02D147D0> 大吗?
False

猜一猜, one 会比 two 大吗?
False

类和对象的3种方法

实例方法

  • 需要实例化对象才能使用的方法

静态方法

  • 不需要实例化,通过类直接访问

类方法

  • 类方法是将类本身作为对象进行操作的方法

区别:

  • 实例方法只能被实例调用
  • 静态方法(由@staticmethod装饰器的方法)、类方法(由@classmethod装饰器的方法),可以被类或类的实例对象调用
  • 实例方法,第一个参数必须要默认传递实例对象,一般使用self
  • 静态方法,参数没有必要
  • 类方法,第一个参数必须要默认传递,一般使用cls

代码实例如下:

class Person():
    def __init__(self, name):
        self.name = name

    # 实例方法
    def play(self):  # 加self区别于普通函数
        print('Hi {}, Come play with me..?'.format(self.name))

    # 静态方法
    # 不需要使用第一个参数表示自身或者类
    @staticmethod  # 声明静态,去掉则编译报错;还有静态方法不能访问类变量和实例变量
    def sleep():  # 使用了静态方法,则不能再使用self
        print("Sorry, I want sleeping...?")
# 类方法 # 类方法的第一个参数,一般命名为cls,区别于self @classmethod # 类方法 def hug(cls): print("Let me give you a hug...") p = Person("Mike") # 实例方法调用 p.play() # 静态方法调用 p.sleep() Person.sleep() # 类方法调用 p.hug() Person.hug()

输出结果如下:

# 实例方法调用
# p.play()
Hi Mike, Come play with me..?

# 静态方法调用
# p.sleep()
# Person.sleep()
Sorry, I want sleeping...?
Sorry, I want sleeping...?

# 类方法调用
# p.hug()
# Person.hug()
Let me give you a hug...
Let me give you a hug...

 自定义类

类其实是一个类定义和各种方法的自由组合

可以定义类和函数,然后自己通过类直接赋值

可以借助于MethodType实现

借助于type实现

利用元类实现--MetaClass

  • 元类是类
  • 被用来床在别的类

代码实例如下:

# ***********实例--1**************
class A():
    pass

def say(self):
    print("say的函数在saying...")

class B():
    def saying(self):
        print("类中方法saying在saying")

say('哈哈ing')    # 调用函数

A.say = say       # 组装一个类
a = A()
a.say()

b = B()
b.saying()

# ***********实例--2**************
from types import MethodType

class C():
    pass

def Song(self):
    print("函数Song在songing")

c = C()
c.Song = MethodType(Song, C)
c.Song()

# ***********实例--3**************
# 利用type造一个类
# 先定义类应该具有的成员函数
def play(self):
    print("函数play在playing...")

def talk(self):
    print("函数talk在talking...")

#用type来创建一个类
D = type("AName", (object, ), {"class_play":play, "class_talk":talk})

# 然后可以像正常访问一样使用类
d = D()

d.class_play()
d.class_talk()

输出结果如下:

# say('哈哈ing')    # 调用函数
say的函数在saying...

# a.say()       # 组装一个类
say的函数在saying...

# b.saying()
类中方法saying在saying

# c.song() 函数Song在songing
# d.class_play() 函数play在playing... # d.class_talk() 函数talk在talking...

元类的理解和使用

  参考:https://segmentfault.com/a/1190000011447445

 

posted @ 2019-04-16 15:59  落晨  阅读(169)  评论(0编辑  收藏  举报