day16-面向对象基础(三)

今日摘要

今天主要整理一下这俩天学习的内容,面向对象也快学完了,深刻的认识到面向对象就是一个思想,怎么把思想理解了,其他也就不是什么事了

1.类的约束

2.类的类方法与静态方法

3.类的反射

4.类的内置方法以及双下方法

 

开始今日份总结

 

1.类的约束

类的约束,就是对类进行一些正确的引导,约束,统一规范,满足正确的开发方式

  1.1类的约束的第一种方式

class A:
    def pay(self,money):#规定都必须有pay方法
        raise Exception('未定义指定函数')

class Alipay(A):
    def pay(self,money):
        print('本次消费%s'%money)

class JDpay(A):
    def pay(self,money):
        print('本次消费%s'%money)

class Wechatpay(A):
    def zhifu(self,money):
        print('本次消费%s'%money)

w1 = Wechatpay()

def pay(obj,money):#约束一下,约定所有人的支付必须是使用统一的接口,但是这样也没又很强烈的约束功能
    obj.pay(money)

pay(w1,100)
#这种事如果没有定义指定的方法会抛出错误

  1.2类的约束的第二种方式

from abc import ABCMeta,abstractmethod
class A(metaclass=ABCMeta):
    def pay(self,money):
        print('请创建正确的方法')
@abstractmethod
class Alipay(A):
    def pay(self,money):
        print('本次消费%s'%money)
class JDpay(A):
    # def zhifu(self,money):
    #     print('本次消费%s'%money)

    def pay(self, money):
        print('此次消费%s' % money)
def pay(obj,money):
    obj.pay(money)
j1 = JDpay()
pay(j1,100)
#第二种方式就是调用abc模块,但是这种在日常使用中,很少用到,一般都是用第一种。

2.绑定方法与非绑定方法

在类内部一般包含俩种方法,一种为绑定方法,一种为非绑定方法

  2.1绑定方法

绑定方法:绑定给谁,就由谁来执行,谁用就会把调用者当做第一个方法传入

绑定给对象的方法:类内没有被任何装饰器修饰的方法

绑定给类的方法:类内定义的装饰器装饰的classmethod修饰的方法

看了一圈以及源码对于怎么用,或者是使用场景都没有说,真的是一头雾水,写一点自己能理解的把

#原本
class Test_time():
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    def out_data(self):
        print('现在日期为{}年{}月{}日'.format(self.year,self.month,self.day))


t1 = Test_time(2018,12,28)
t1.out_data()
如果传入数据为不是正确的数据,例如‘2018-12-28’,就需要其他函数对数据进行整理


class Test_time():
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    def out_data(self):
        print('现在日期为{}年{}月{}日'.format(self.year,self.month,self.day))

    @classmethod
    def data_solite(cls,msg):
        year, month, day = map(int, msg.split('-'))
        ret = cls(year,month,day)
        return ret
msg ='2018-12-28'
t2 =Test_time.data_solite(msg)
t2.out_data()

这样的好处就是你以后重构类的时候不必要修改构造函数,只需要额外添加你要处理的函数,然后使用装饰符

在我的理解中,类方法就是将一个类在没有实例化对象之前调用类里面的方法,或者是先行修改内容,这样就不需要修改构造函数,相当于重置构造函数。

  2.2非绑定方法

没有自动传值这么一个说法,就是一个普通函数,一个普通的工具,对于对象和类都可以调用。不与类或者对象进行绑定

就是在方法上加@staticmethod

import time

class TimeTest(object):
    def __init__(self, hour, minute, second):
        self.hour = hour
        self.minute = minute
        self.second = second

    @staticmethod
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())


print(TimeTest.showTime())
t = TimeTest(2, 10, 10)
nowTime = t.showTime()
print(nowTime)
#类与对象都可以调用,使用对应的方法

3.类的反射

类的反射也是类的内置方法,也是一个特别重要的点

  3.1 hasattr 判断对象或者类是否存在指定的属性,看代码以及结果

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

    def talk(self):
        print("%s is talking."%self.name)

p1 = people('alex',18)
print(hasattr(p1,'name'))
print(hasattr(p1,'sex'))

结果
True
False

hasattr判断完成后,会返回一个布尔值,有就返回True,无就返回False

  3.2getattr 获取到一个对象或者类的属性,加()就是执行,看代码

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

    def talk(self):
        print("%s is talking."%self.name)

p1 = people('alex',18)
print(getattr(p1,'name'))
print(getattr(p1,'sex','man'))
print(getattr(p1,'sex'))

结果
alex
man
  File "D:/PycharmProjects/s2018/day6/test.py", line 13, in <module>
    print(getattr(p1,'sex'))
AttributeError: 'people' object has no attribute 'sex'

对于getattr,如果对象或者是类有输入的属性,则,返回正确属性。无则报错,如果我们指定默认值,则返回默认值,在看一下其他

class people:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def talk(self):
        print("%s is talking."%self.name)

p1 = people('alex',18,'woman')

getattr(p1,'talk')()#getattr获取到方法后加()就是执行
print(getattr(p1,'sex','man'))#类内如果对属性已经确认过,显示对象已经确认的值,而不显示默认值

结果
alex is talking.
woman

  3.3setattr 是修改已有的属性或者是新加一个属性,看代码

class people:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def talk(self):
        print("%s is talking."%self.name)

p1 = people('alex',18,'woman')

print('修改前',p1.age)
setattr(p1,'age',20)
print('修改后',p1.age)
setattr(p1,'country','China')
print(p1.__dict__)

结果
修改前 18
修改后 20
{'country': 'China', 'name': 'alex', 'sex': 'woman', 'age': 20}

  3.4delattr就是对现有的对象或者类的属性就行删除,这个比较简单,看代码

class people:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def talk(self):
        print("%s is talking."%self.name)

p1 = people('alex',18,'woman')

print('修改前',p1.__dict__)
delattr(p1,'name')
print('修改后',p1.__dict__)

结果
修改前 {'age': 18, 'name': 'alex', 'sex': 'woman'}
修改后 {'age': 18, 'sex': 'woman'}

  3.5类的反射其他用法

在说一下在类的反射中其他用法

#可以用于反射的方面有实例化对象, 类,其他py文件 本py文件
# 1.操作类的角度
class A:
    country = 'China'
    area = '深圳'

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

    def func(self):
        print(666)

print(getattr(A,'country'))
print(getattr(A,'area'))
print(getattr(A,'name'))
getattr(A,'func')(23)
print(hasattr(A,'func2'))

# 2.其他py文件(模块)
# 不用反射之前:
import attr
print(attr.flag)
ret = attr.func
# print(ret(10))
print(attr.B.name_list)
obj = attr.B('barry','')
# print(obj.name_list)
print(obj.name)
ret = 'B'
# 用反射的方法:
import attr
print(getattr(attr,'flag'))
# 1,找到func 并执行
ret = getattr(attr,'func')
print(ret(10))
#2,找到B类并调用 name_list func函数
b = getattr(attr,'B')
print(b.name_list)

print(getattr(attr.B,'name_list'))
getattr(attr.B,'func')(1)

#3,找到B类实例化对象在找 name,name_list func函数
b = getattr(attr,'B')
obj = b('alex','')
print(obj.name)
print(obj.name_list)

# 4,本模块的反射
import sys
obj = sys.modules[__name__]
print(obj)
def func():
    print(666)

ret = input('>>>')
# ret()
getattr(obj,ret)()

def func1():
    print('in func1')

def func2():
    print('in func2')

def func3():
    print('in func3')

l1 = [func1,func2,func3]
for i in l1:
    i()
import sys
obj = sys.modules[__name__]
l1 = ['func%s' % i for i in range(1,4)]
# print(l1)
for i in l1:
    getattr(obj,i)()

到底什么对象可以反射

  • 实例化对象
  • 其他模块
  • 本模块(对于本模块,需要创建sys文件进行设定,如果本模块中包含模块则不需要)

4.类的内置方法以及双下方法

类的内置方法其实包含类的反射中四个方法,上面已经写了就不在描述

  4.1其他内置方法

# isinstance 判断此对象是不是该类(或者是该类的子类)实例化的对象
class A: pass

class B(A): pass

obj = B()
s1 = 'afds'
print(isinstance(obj,B))  #True
print(isinstance(obj,A))  #True
print(isinstance(s1,str))  #True

# issubclass 判断的是此类是不是后面类的派生类
class D: pass

class A(D): pass

class B(A): pass

abj = B()

print(issubclass(B,A)) #True
print(issubclass(B,D)) #True

  4.2双下方法

# 特殊双下方法
# __init__
# len
# s1 = 'fdsafdsa'
# l1 = [1,2,3]
# dic = {'name':'alex','age': 12}
# i = 12
# # print(len(s1))
# int
# # print(len(l1))
# list
# print(len(dic))
# print(len(i))

#
# class A:
# #     def __init__(self,name,age):
# #         self.name = name
# #         self.age = age
# #         self.sex = '男'
# #
# #     def __len__(self):
# #         # print(666)
# #         return len(self.__dict__)
# # a = A('barry', 18)
# # # len(a)  # len(对象) 如果此类中有__len__ 就_方法会自动执行__len_
# # print(len(a))
# print(hash('fsdaf'))
# class A:
#     def __init__(self,name,age):
#         self.name = name
#         self.age = age
#         self.sex = '男'
#
#     def __len__(self):
#         # print(666)
#         return len(self.__dict__)
#
#     def __hash__(self):
#         return 1

    # def __str__(self):
    #     print(555)
    #     return 'fdsaf'

# object
# a = A('barry', 18)
# print(hash(a))
# print(a)  # 对一个对象打印时,自动触发类中的__str__方法
# print(a,type(a))

# __call__方法
# class Foo:
#
#     def __init__(self):
#         print(11)
#
#     def __call__(self, *args, **kwargs):
#         pass


# obj = Foo()
# obj()  # 对象() 触发 __call__方法


# __new__ 构造方法

# class A:
    # def __init__(self,name):
    #     self.name = name
    #     print('in A __init__')

# object
# obj = A('alex')

# object
# class A:
#     def __init__(self,name):
#         self.name = name
#         print('in A __init__')
#     def __new__(cls, *args, **kwargs):
#         print('in A __new__')
#         return object.__new__(cls)
#
# a = A('春哥')
# print(a.name)
# 1, 类名() 执行object.__new__方法,开辟的对象空间并返回
# 2,自动执行__init__方法,将空间创给self
# 3,在__init__给对象封装属性。

__call__的三件事

  1. 先造一个空对象obj:obj = object.__new__(self)
  2. 初始化obj:self.__init__(obj,*args,**kwargs)
  3. 返回obj:return obj

单例模式,比较重要!

class A:
    __instance = None
    def __init__(self,name,age):
        self.name =name
        self.age = age
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

ret1 = A('alex',123)
ret2 = A('wusir',22)
ret3 = A('barry',18)
print(ret1)
print(ret2)
print(ret3)
#结果
<__main__.A object at 0x01702470>
<__main__.A object at 0x01702470>
<__main__.A object at 0x01702470>
#就会发现单例模式就是无论怎么实例化,生成的都是同一个,这样节省名称空间
posted @ 2019-01-19 14:58  柴犬砍柴  阅读(167)  评论(0编辑  收藏  举报