Python_OOP_2

类的成员描述符(属性)

  • 类的成员描述符是为了在类中对类的成员属性进行相关操作而进行的一种方式
    • get: 获取属性的操作
    • set: 设置属性的操作
    • delet: 删除属性的操作
  • 如果想使用类的描述符,大概有三种方式
    • 使用类实现描述器
    • 使用属性修饰符
    • 使用property函数
      • property 函数很简单
      • property (fget, fset, fdel, doc)
#property 实例
class Person():
    def fgetname(self):
        return self._name, self._age

    def fgetage(self):
        return self._age

    def fsetname(self,name):
        self._name= name.upper()

    def fsetage(self,age):
        self._age = abs(int(age))

    def fdelname(self):
        self._name= 'Noname'
    name = property(fgetname, fsetname, fdelname, "change name to upper")
    age = property(fgetage, fsetage)

p = Person()
p.name = "abby hua"
p.age = 20.34334
print(p.name)
print(p.age)
'''
输出结果:
ABBY HUA
20
'''
  • 无论哪种修饰符,都是为了对成员属性进行相应的控制
    • 类的方式: 适合多个类中的多个属性共用一个描述符
    • property: 适用当前类中使用,可以控制一个类中多个属性
    • 属性修饰符: 适用当前类中使用,控制一个类中的一个属性

类的内置属性

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

#类的内置属性举例
print(Person.__dict__)
print(Person.__doc__)
print(Person.__name__)
print(Person.__bases__)
'''
输出结果:
{'__module__': '__main__', '__doc__': '\n    这是一个person的说明文档\n    ', 'fgetname': <function Person.fgetname at 0x00000000028087B8>, 'fgetage': <function Person.fgetage at 0x0000000002808AE8>, 'fsetname': <function Person.fsetname at 0x0000000002808B70>, 'fsetage': <function Person.fsetage at 0x0000000002808BF8>, 'fdelname': <function Person.fdelname at 0x0000000002808C80>, 'name': <property object at 0x000000000206C868>, 'age': <property object at 0x0000000002811818>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}

    这是一个person的说明文档
    
Person
(<class 'object'>,)
'''

类的常用魔术方法

  • 魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发。
  • 魔术方法有统一特征,方法名被前后两个下划线包裹
  • 操作类
    • __init__: 构造函数
    • __new__: 对象实例化方法,此函数较特殊,一般不需要使用
    • __call__: 对象当函数使用的时候触发
# 魔术方法__call__实例
class Animal():
    def __init__(self):
        print("I am in __init__ method")

    def __call__(self):
        print("I am in __call__ method")
a = Animal()
a()
'''
I am in __init__ method
I am in __call__ method
'''
- `__str__` :当对象被当做字符串使用的时候触发
#魔术方法__str__实例
class Dog():
    '''
    def __str__(self):
        return "I am in __str__ method"
    '''

d = Dog()
print(d)
'''
输出结果: 
I am in __str__ method
不定义__str__时,输出结果为: <__main__.Dog object at 0x00000000027EEF60>
'''
- `__repr__`:返回字符串
- `__str__和__repr__`的区别:
	- `__repr__`目的是为了表示清楚,是为开发者准备的。
	- `__str__` 目的是可读性好,是为使用者准备的。
#魔术方法__str__和__repr__区别
class Date():
    def __init__(self, time):
        self.time = time

    #输出结果不带引号
    def __str__(self):
        print("I am in Date __str__ method")
        print("date name is %s " % self.time)
        return self.time
    '''
    输出结果: 
    I am in Date __str__ method
    date name is 2019/10/30 
    2019/10/30
    '''

    #输出结果带引号,而且可以直接通过eval()函数调用
    def __repr__(self):
        print("I am in Date __repr__ method")
        print("date name is %r" % self.time)
        return self.time
    '''
    输出结果:
    I am in Date __repr__ method
    date name is '2019/10/30'
    2019/10/30
    '''

today = "2019"
d = Date(today)

#__str__和__repr__都定义时,默认只调用__str__, 只有当__str__没有定义, 才会调用__repr__
print(d)
  • 描述符相关
    • __set__
    • __get__
    • __delete__
  • 属性操作相关
    • __getattr__ : 访问一个不存在的属性时触发
# 魔法方法__getattr__实例
class Student():
    def __init__(self, name):
        self.name = name

    def __getattr__(self,  name):
        print("attribute %s not exist" % name)


s = Student("abby")
print(s.name)

#没有定义__getattr__时,调用不存在的成员,输出AttributeError: 'Student' object has no attribute 'age'
print(s.age)

'''
输出结果:
abby
attribute age not exist
None
'''
- `__setattr__` :对成员属性进行设置的时候触发
	- 参数: 
		- self用来获取当前对象
		- 被设置的属性名称,以字符串形式出现
		- 需要对属性名称设置值
	-  作用: 进行属性设置的时候进行验证或者修改
	- 注意: 在该方法中不能直接对属性进行赋值操作,否则进入死循环
#魔法方法__setattr__实例
class Teacher():

    def __init__(self, name, value):
        print("I am in __init__ method start")
        self.name = value
        print("I am in __init__ method end")

    def __setattr__(self, name, value):
        print("I am in __setattr__ method start")
        super().__setattr__(name, value)
        print("I am in __setattr__ method end")

t = Teacher("name", "Miss Tang")

'''
输出结果:
I am in __init__ method start
I am in __setattr__ method start
I am in __setattr__ method end
I am in __init__ method end
'''
  • 运算分类相关魔术方法
    • __gt__ : 进行大于判断的时候触发的函数
      • 参数
        • self
        • 第二个参数是第二个对象
        • 返回值可以是任意值, 推荐返回布尔值
#魔法方法__gt__实例
class Compare():
    def __init__(self, name):
        self.name = name

    def __gt__(self, obj):
        print("In __gt__ method")
        print("{0} 和 {1} 谁大呢?".format(self.name, obj.name))
        return self.name > obj.name
c1 = Compare ('abby')
c2 = Compare ('betty')
print(c1>c2)
'''
In __gt__ method
abby 和 betty 谁大呢?
False
'''

类和对象的三种方法

  • 实例方法
    • 需要实例化对象才能使用的方法,使用过程中可能需要借助对象的其他对象的方法完成
  • 静态方法
    • 不需要实例化,通过类直接访问
  • 类方法
    • 不需要实例化
  • 参看如下案例:
#实例方法,类方法,静态方法实例
class Woman():
    #实例方法, 参数一般为self
    def eat(self):
        print(self)
        print("Eating"+"."*10)

    #类方法,参数一般为cls
    @classmethod
    def sleep(cls):
        print(cls)
        print("Sleeping"+"."*10)
    #静态方法,不需要参数
    @staticmethod
    def shop():
        print("Shopping" + "."*10)

xiaohui = Woman()
xiaohui.eat()
Woman.sleep()
#实例也可以调用类方法
xiaohui.sleep()
Woman.shop()
#实例也可以调用静态方法
xiaohui.shop()
'''
输出结果:
<__main__.Woman object at 0x0000000002556AC8>
Eating..........
<class '__main__.Woman'>
Sleeping..........
<class '__main__.Woman'>
Sleeping..........
Shopping..........
Shopping..........
'''
  • 三个方法区别

抽象类

  • 抽象方法: 没有具体实现的方法称为抽象方法
  • 抽象方法的主要作用是规范子类的行为和接口
#抽象方法实例
class Animal ():
    def sayHello(self):
        pass

class Dog(Animal):
    def sayHello(self):
        print("闻一下呗")

class Person(Animal):
    def sayHello(self):
        print("Have a hug")

d = Dog()
d.sayHello()
p = Person()
p.sayHello()
'''
输出结果:
闻一下呗
Have a hug
'''
  • 抽象类的使用需要借助abc模块
    • import abc
  • 抽象类: 包含抽象方法的类叫抽象类,通常称为ABC类
  • 抽象类的使用
    • 抽象类中可以包含具体方法,也可以包含抽象方法
    • 抽象类中可以有方法,也可以有属性
    • 抽象类不允许直接实例化
    • 必须继承才可以使用,且继承的子类必须实现所有继承来的抽象方法
    • 如果子类没有实现所有继承的抽象方法 ,则子类也不能实例化
    • 抽象类的主要作用是设定类的标准,以便于开发的时候具有统一的规范
#抽象类的实现
import abc
#固定格式,声明一个类并指定当前类的元类
class Human(metaclass = abc.ABCMeta):

    #定义抽象方法
    @abc.abstractmethod
    def eat(self):
        pass

    #定义类抽象方法, python 3.3以后已经不推荐使用类,用abc.abstracmetho代替
    @abc.abstractclassmethod
    def smoke(self):
        pass

    #定义静态抽象方法, python 3.3以后已经不推荐使用了,用abc.abstractmethod代替.
    @abc.abstractstaticmethod
    def sleep():
        pass

    def drink(self):
        print("drinking...")

自定义类

  • 自己组装类: 类其实是一个类定义和各种方法的自由组合
    • 通过类组装 , 可以定义类和函数,然后自己通过类直接赋值
#自己组装类实例
class A():
    pass

def sayHello(self):
    print("Hello......")

class B():
    def sayHello(self):
        print("Hello......")

sayHello(6)

#方法可以像属性一样赋值
A.sayHello = sayHello
a = A()
a.sayHello()

#上面通过赋值组装的类和class B的用法一样
b = B()
b.sayHello()
'''
输出结果:
Hello......
Hello......
Hello......
'''
- 通过类实例组装, 可以借助MethodType实现
#自己组装类实例2
#通过类实例组装
from types import MethodType

class C ():
    pass

def sayBye(self):
    print("Bye......")

c = C()
c.sayBye = MethodType(sayBye, C)
c.sayBye()
'''
输出结果:
Bye......
'''
- 借助于type实现
#自己组装类实例3
#借助type实现
def sayHi(self):
    print("say Hi......")

def sayGoodBye(self):
    print("say Goodbye ......")

D = type("DName", (object,), {"class_hi": sayHi, "class_goodbye": sayGoodBye})
d = D()
d.class_hi()
d.class_goodbye()
'''
输出结果:
say Hi......
say Goodbye ......
'''
- 利用元类实现 - MetaClass
	- 元类是类
	- 被用来创造别的类
#元类演示实例
#元类写法是固定的,必须继承自type
#元类一般命名以MetaClass结尾,不是强制规定,但一般遵循这个原则
class EMetaClass (type):
    #注意一下写法
    def __new__(cls, name, bases, attrs):
        #自己的业务处理
        print("我是元类,我是元类")
        attrs['id'] = '000000'
        attrs['addr'] = '地址不能为空'

        return  type.__new__(cls, name, bases, attrs)

#元类定义完就可以使用,使用注意写法
class Ee(object, metaclass = EMetaClass):
    pass

e = Ee()
print(e.id)
print(e.addr)
'''
输出结果:
我是元类,我是元类
000000
地址不能为空
'''
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值