类和对象笔记

#!/usr/bin/pytnon3

class test01:
    name='test01'
    def __init__(self,value=123,key='key1'):# 构造方法,创建对象后会自动调用,若构造方法加上参数,则new对象也需要传入参数
        self.value=value
        self.key=key
    def function1(self):
        return self.value
a=test01() #创建对象
print(a.value)
print(a.function1())
a.add1='456' # 增加实例变量
print(a.add1)
del a.key # del 删除实例变量
del a.add1
# print(a.key)
# print(a.add1)
def info(self):
    print('info',self.value)
a.fromInfo=info # 函数不带圆括号,即是赋值
a.fromInfo(a) # 为对象动态添加的方法,不会自动绑定self,需要调用的时候传参
a.fromInfo1=lambda self:print('info1',self.value) # 使用lambda表达式动态增加方法
a.fromInfo1(a)
def intro(self,content):
    print('intro---',content)
from types import MethodType
a.intro1=MethodType(intro,a) # 使用MethodType对intro进行包装,将该函数的第一个参数绑定为a
a.intro1('123456')

class test02:
    def __init__(self):
        foo=0 # foo是构造方法中的局部变量
        self.foo=6 # 会把正在初始化(调用构造方法)的对象的foo实例变量设置为6
    def testtemp(self):
        self.koo=1000

b=test02()
print(b.foo)
b.testtemp()
print(b.koo)

# 以方法调用还是以函数调用的方式执行实例方法, self参数一样可以自动绑定
class test03:
    def fun(self):
        print('test03--',self)
c=test03()
c.fun() # 使用对象.调用实例方法
fun1=c.fun
fun1() # 使用函数方式来调用实例方法

# 程序可以将self作为普通变量来访问,或者可以返回self本身,这样可以一直调用实例方法,如下
class test04:
    value=1
    def returnSelf(self):
        self.value+=1
        return self # 将self返回
d=test04()
d.returnSelf().returnSelf().returnSelf() # 可以使代码更简洁
print(d.value)

# 使用类调用实例方法的两种方式(未绑定方法的方式):1、传入对象的引用变量,等同于使用引用变量调用实例方法 2、给self传入一个别的参数,不要求是对象的引用变量
def foo():
    print('全局foo函数')
name='全局name变量'
class user:
    name='class name变量'
    def foo(self):
        print('class foo方法',self)
foo()
print(name)
# user.foo() # 会报错,因为使用类调用实例方法,不会自动绑定self(事实上也没有self)
f=user()
user.foo(f) # 使用类调用实例方法只能这样,等同于f.foo()(对象调用实例方法)
print(user.name) #类调用变量正常
user.foo('demo')

# 类方法和静态方法:不常用,类方法调用会自动绑定,静态方法调用不会自动绑定
class Bird:
    # classmethod修饰的方法是类方法
    @classmethod
    def fly(cls):
        print('实例方法fly: ', cls)
    # staticmethod修饰的方法是静态方法
    @staticmethod
    def info(p):
        print('静态方法info: ', p)
# 调用类方法,Bird类会自动绑定到第一个参数
Bird.fly()
# 调用静态方法,不会自动绑定,因此程序必须手动绑定第一个参数,和函数相似
Bird.info('crazyit')
# 创建Bird对象
b = Bird()
# 使用对象调用fly()类方法,其实依然还是使用类调用,
# 因此第一个参数依然被自动绑定到Bird类
b.fly()
# 使用对象调用info()静态方法,其实依然还是使用类调用,
# 因此程序必须为第一个参数执行绑定
b.info('fkit')

# 函数装饰器
# 使用@函数A装饰函数B
# 1、将被修饰的函数(函数B)作为参数传给@符号引用的函数(函数A),执行函数A(函数B)
# 2、将函数B替换(装饰)成第1步的返回值。

# 1、将funB作为funA()的参数,@funA相当于执行 funA(funB())
# 2、将funB替换成第1步执行的结果,funA()执行完成后返回demo1,funB就不再是函数,而是被替换成一个字符串
def funA(fn):
    print('funA')
    fn() # 将传入的函数B执行
    return 'demo1'
@funA
def funB(): #此时funB被替换为第一步执行的结果
    print('funB')
print(funB)
print('-----------------')
def foo(fn):
    # 定义一个嵌套函数
    def bar(*args):
        print('1',args)
        print(fn.__name__) # 已经将my_test传给了foo,打印送入foo的参数名,即是my_test函数
        n=args[0]
        return fn(n*(n+1)) # 已经将my_test传给了foo,返回原来的my_test(n*(n+1))的值
    return bar
# 下面的装饰效果相当于foo(my_test),my_test将会被替换(装饰)成该语句的返回值
# 由于foo()函数返回bar函数,因此my_test就是bar
@foo
def my_test(a):
    print('my_test',123,a)
print(my_test) # my_test就是bar
'''
下面等同于@foo,e即是修饰后my_test的效果
e=foo(my_test)
print(e(10))
'''
my_test(10)
my_test(5,6)
print('-----------------')

def auth(fn):
    def auth_fn(*args):
        # 一条模拟权限检查的语句
        print('--模拟权限检查--')
        fn(*args)
    return auth_fn
@auth
def test(a,b):
    print('test,参数a是%s,参数b是%s'%(a,b))
# 调用test()函数,实际上是调用修饰后的auth_fn函数
test(5,6)
print('-----------------')

# 类体中定义的变量属于类变量,必须使用类名来读取、修改类变量(同样允许通过对象类调用)
# 类变量和实例变量:理解为类定义的变量只是一个基础的模板,实例变量复用此模板,如果通过对象改变类变量,就脱离的复用类变量的范畴,而是定义了新的实例变量
# 程序通过对象访问类变量,其本质还是通过类名在访问类变量
# 使用self打印类变量,程序使用self访问record类的类变量,此时self代表info方法的调用者,也就是record对象
# 实际上,程序通过对象访问类变量,其本质还是通过类名在访问类变量,动态修改类变量,对象访问的类变量也会发生改变
class record:
    info=6
    name='info'
    def showInfo(self):
        # print(info) # 类方法中直接打印类变量,会显示function info at 0x000001C25C7F8280
        print('show',record.name) # 使用类打印类变量
        print('show',self.name) # 使用self打印类变量
        print('show',self.info)
    def chaStr(self):
        self.info=123 # 使用对象修改类变量,实际上重新定义了实例变量
a=record()
print(a.info)
print(a.name)
a.showInfo()
record.name='demo1'
record.info='666'
a.showInfo()
a.info='实例变量赋值'
a.showInfo()
print(record.info)
record.info='666'
print(a.info)
print('-----------------')

# 如果为Python类定义了getter等访问器方法,则可使用property()函数将它们定义成属性(相当于实例变量)*****
# 它把方法包装成属性,让方法可以以属性的形式被访问和调用
# property(fget=None,fset=None,fdel=None,doc=None),f指类方法,参数可以0-4个
# 举例:size=property(getsize, setsize, delsize, '用于描述矩形大小的属性')
# 这样定义后,就可以通过size方法对属性(实例变量)访问、修改、删除、以及查看说明
class Rectangle:
    # 定义构造方法
    def __init__(self, width, height):
        self.width = width
        self.height = height
    # 定义setsize()函数
    def setsize (self , size):
        self.width, self.height = size # 元组封包解包
    # 定义getsize()函数
    def getsize (self):
        return self.width, self.height
     # 定义getsize()函数
    def delsize (self):
        self.width, self.height = 0, 0
    # 使用property定义属性
    size = property(getsize, setsize, delsize, '用于描述矩形大小的属性')
# 访问size属性的说明文档
print(Rectangle.size.__doc__)
# 通过内置的help()函数查看Rectangle.size的说明文档
# help(Rectangle.size)
rect = Rectangle(4, 3)
# 访问rect的size属性
print(rect.size) # (4, 3)
# 对rect的size属性赋值
rect.size = 9, 7
# 访问rect的width、height实例变量
print(rect.width) # 9
print(rect.height) # 7
# 删除rect的size属性
del rect.size
# 访问rect的width、height实例变量
print(rect.width) # 0
print(rect.height) # 0
print(dir(Rectangle))
c=Rectangle(5,6)

print('-----------------')

# 使用property()定义一个读写属性:设置属性也用于修改,访问类变量
class rwdemo:
    xing='demoq'
    ming='demoming'
    def getname(self):
        return self.xing,self.ming
    def setname(self,fullname):
        # fenge=fullname.split(',')
        # self.xing=fenge[0]
        # self.ming=fenge[1]
        self.xing,self.ming=fullname # 元组封包解包
    # 使用property()定义fullname属性,只传入两个参数
    fullname=property(getname,setname)
print(rwdemo.fullname)
rwdemo.fullname=1,2
print(rwdemo.fullname)
u=rwdemo()
print('u.fullname',u.fullname)

class Cell:
    # 使用@property修饰方法,相当于为该属性设置getter方法, state属性只是一个只读属性
    # _state = 123
    @property
    def state(self):
        return self._state
    # 为state属性设置setter方法
    @state.setter
    def state(self, value):
        if 'alive' in value.lower():
            self._state = 'alive'
        else:
            self._state = 'dead'
    # 为is_dead属性设置getter方法
    # 只有getter方法属性是只读属性
    @property
    def is_dead(self):
        return not self._state.lower() == 'alive'
c = Cell()
# 修改state属性
c.state = 'Alive'
# 访问state属性
print(c.state)
# 访问is_dead属性
print(c.is_dead)

print('-----------------')
# 封装(Encapsulation)是面向对象的三大特征之一(另外两个是继承和多态),
# 它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问
# 类的成员命名为以双下画线开头,Python会把它们隐藏,只能通过类中的对外的方法调用,如实例方法
class packing:
    def __hide(self):
        print('a hide sample')
    def getname(self):
        return self.__name
    def setname(self,name):
        if len(name)<3 or len(name)>8:
            raise('please limit name in 3-8')
        self.__name=name
    name=property(getname,setname)
    def getage(self):
        return self.__age
    def setage(self,age):
        print('this is setage function')
        for i in range(3):
            print('i is %2i'%i)
        self.__age=age
    age=property(getage,setage)
pa=packing()
pa.name='nameTes'
print(pa.name)
pa.age='9999999' # age属性指向__age实例变量,原方法中的别的代码也会执行
# print(pa.age)
# pa.__hide() # 报错,私有方法无法外部访问

# 继承
# python支持多继承(一个子类可以同时有多个直接父类,不建议使用),如果继承的父类包含相同的方法,先继承的类的方法优先级高(遮蔽后面的)
# 子类重写父类的方法:overwrite
# 在定义类时没有显式指定它的父类,则此类默认的父类是object类
class Bird:
    def fly(self):
        print('鸟会飞行')
class ostrich(Bird):
    def fly(self):
        print('鸵鸟只会奔跑')
a=ostrich()
a.fly()

# 通过未绑定方法即可在子类中调用被重写的父类方法
class baseClass:
    def foo(self):
        print('父类中定义的foo方法')
class subClass(baseClass):
    def foo(self):
        print('子类中定义的foo方法')
    def bar(self):
        print('bar方法')
        # 直接执行foo方法,执行的是子类重写后的方法
        self.foo()
        # 通过父类类名执行foo方法,即可以未被重写调用父类方法
        baseClass.foo(self)
a=subClass()
a.foo()
a.bar()

# 子类会继承父类的构造方法,排在前面的父类的构造方法会被优先使用
class baseClass1:
    def __init__(self,num):
        self.num=num
    def work(self):
        print('工作的数量是%d'%(self.num))
class baseClass2:
    def __init__(self,day):
        self.day=day
    def sleep(self):
        print('休息的日子是%d'%(self.day))
class subClass1(baseClass1,baseClass2):
    pass
a=subClass1(999)
a.work()
# a.sleep() # 会拨错,因为对象优先使用了baseClass1的构造方法,没有初始化baseClass2的day变量

# python规定,如果子类重写了父类的构造方法,那么子类的构造方法必须调用父类的构造方法
# 1、使用super函数
# 2、使用未绑定方法的方式
class subClass1(baseClass1,baseClass2):
    def __init__(self,num,day):
        # 下面两行代码意义一样,通过super()函数调用父类的构造方法
        super(baseClass1, self).__init__(num)
        super().__init__(num)
        # 通过未绑定方法调用父类的构造方法
        baseClass2.__init__(self,day)

s=subClass1(123,456)
s.work()
s.sleep()

# 动态添加类方法:所有new的实例都可以使用,会自动绑定self
class cat:
    def __init__(self,name):
        self.name=name
        print('cat\'s name is %s'%self.name)
def cat_run(self):
    print('run')
c1=cat('karry')
cat.run=cat_run
c1.run()

# __slots__属性限制实例动态添加方法和变量,仅限制实例而不限制类
class dog:
    __slots__ = ('walk','voc','name')
    def __init__(self,name):
        self.name=name
        print('dog\'s name is %s'%name)
    def eat(self):
        print('we can eat')
d1=dog('lisa')
# d1.walk1='walk1'  # 不允许添加__slots__未包含的变量或者方法

# type类的实例就是类,通过type创建类:type('类名',(继承父类的元组),(变量、方法等的词典))
def fn(self):
    print('fn哈书')
t1=type('t1type',(),{'name':123,'value':456})
t2=type('t1type',(),dict(walk=123,key=fn))
t1Object=t1()
print(t1Object.name)
print(t1Object.value)
t2Object=t2()
print(t2Object.walk)
t2Object.key()

# 使用metaclass动态修改程序中的一批类,在开发一些基础性框架时非常有用
# 想要创建某一批类全部具有某种特征,则可通过metaclass来实现 使用metaclass可以在创建类时动态修改类定义
class itemMetaclass(type): # 1、定义metaclass类
    # cls代表被动态修改的类
    # name代表被动态修改的类名
    # bases代表被动态修改的类的所有父类
    # attrs代表被动修改的类的所有属性、方法组成的字典
    def __new__(cls,name,bases,attrs): # 2、重写__new__方法:当程序使用class定义新类时,如果指定了metaclass,\
                                       # 那么metaclass的__new__方法就会被自动执行。
        attrs['calc_price']=lambda self:self.price*self.discount # 3、为该类动态添加一个calc_price方法
        return type.__new__(cls,name,bases,attrs)
# 下面是使用metaclass创建类的展示
# 定义Book类
class Book(metaclass=itemMetaclass):
    __slots__ = ('name', 'price', '_discount')
    def __init__(self, name, price):
        self.name = name
        self.price = price
    @property
    def discount(self):
        return self._discount
    @discount.setter
    def discount(self, discount):
        self._discount = discount
# 定义Book类
class CellPhone(metaclass=itemMetaclass):
    __slots__ = ('price', '_discount' )
    def __init__(self, price):
        self.price = price
    @property
    def discount(self):
        return self._discount
    @discount.setter
    def discount(self, discount):
        self._discount = discount

b = Book("疯狂Python讲义", 89)
b.discount = 0.76
# 创建Book对象的cal_price()方法
print(b.calc_price())
cp = CellPhone(2399)
cp.discount = 0.85
# 创建CellPhone对象的cal_price()方法
print(cp.calc_price())

# 弱类型的语言,变量并没有声明类型,因此同一个变量完全可以在不同的时间引用不同的对象 \
# 当同一个变量在调用同一个方法时,完全可能呈现出多种行为(具体呈现出哪种行为由该变量所引用的对象来决定),这就是所谓的多态
class canvas:
    # canvas的实例可以不同的包含draw方法的对象,来决定绘制什么图像
    def drawPic(self,shape):
        print('绘图')
        shape.draw(self)
class rectangle:
    def draw(self,field):
        print('在%s领域中绘制三角形'%field)
class circle:
    def draw(self,field):
        print('在%s领域中绘制圆形'%field)
# canvas()实例传入不同对象,绘制不同图像
c1=canvas()
c1.drawPic(rectangle())
c1.drawPic(circle())

# 检查类型
# Python提供了如下两个函数来检查类型
# issubclass(cls,class or tuple):检查cls是否为后一个类或元组包含的多个类中任意类的子类
# isinstance(obj,class or tuple):检查obj是否为后一个类或元组包含的多个类中任意类的对象
# __bases__属性,通过该属性可以查看该类的所有直接父类,该属性返回所有直接父类组成的元组
# __subclasses__()方法,通过该方法可以查看该类的所有直接子类,该方法返回该类的所有子类组成的列表

str1='qaz'
print(isinstance(str1,str))
print(isinstance(str1,tuple))
print(issubclass(str,tuple))
print(issubclass(str,object)) # str是object类的子类

class a:
    pass
class b:
    pass
class c(a,b):
    pass
print('a的父类',a.__bases__)
print('b的父类',b.__bases__)
print('c的父类',c.__bases__)
print(a.__subclasses__())
print(b.__subclasses__())
print(object.__subclasses__())

# 枚举类
# 实例有限且固定的类,在Python中被称为枚举类
# 程序有两种方式来定义枚举类:'
# 1、直接使用Enum类列出多个枚举值来创建枚举类
# 2、通过继承Enum基类来派生枚举类
import enum
# 通过方式1:定义season枚举类,Enum()是Enum的构造方法,参数1是枚举类的类名,参数2是元组,用于列举出所有枚举值
# 枚举值都是该枚举的成员,每个成员都有name、 value两个属性
season=enum.Enum('season',('spring','summer','autum','winter'))
print(season.spring.name)
print(season.summer.value)
print(season['spring']) # season.spring
print(season(3)) # season.autum
# 枚举类__members__属性,返回一个词典,包含所有的枚举实例
print(season.__members__)
print(season.__members__.items())
print(type(season.__members__))
for name,member in season.__members__.items():
    print(name,'=>',member,',',member.value)
# 通过方式2:继承Enum来派生枚举类
import enum
class Orientation(enum.Enum):
    # 为序列值指定value值
    EAST = '东'
    SOUTH = '南'
    WEST = '西'
    NORTH = '北'
    def info(self):
        print('这是一个代表方向【%s】的枚举' % self.value)
print(Orientation.SOUTH)
print(Orientation.SOUTH.value)
# 通过枚举变量名访问枚举
print(Orientation['WEST'])
# 通过枚举值来访问枚举
print(Orientation('南'))
# 调用枚举的info()方法
Orientation.EAST.info()
# 遍历Orientation枚举的所有成员
for name, member in Orientation.__members__.items():
    print(name, '=>', member, ',', member.value)

# 枚举也是类,因此枚举也可以定义构造器。为枚举定义构造器之后,在定义枚举实例时必须为构造器参数设置值->可以自定义枚举出的类的属性
import enum
class Gender(enum.Enum):
    MALE = '男', '阳刚之力'
    FEMALE = '女', '柔顺之美'
# 代码为MALE枚举指定的value是’男’和'阳刚之力’这两个字符串,\
# 它们会被自动封装成元组后传给MALE的value 属性;而且此处传入的’男’和’阳刚之力’这两个参数值正好分别传给cn_name和desc两个参数。\
# 简单来说,枚举的构造器需要几个参数,此处就必须指定几个值
    def __init__(self, cn_name, desc): # 构造器
        self._cn_name = cn_name
        self._desc = desc
    @property
    def desc(self):
        return self._desc
    @property
    def cn_name(self):
        return self._cn_name
# 访问FEMALE的name
print('FEMALE的name:', Gender.FEMALE.name)
# 访问FEMALE的value
print('FEMALE的value:', Gender.FEMALE.value)
# 访问自定义的cn_name属性
print('FEMALE的cn_name:', Gender.FEMALE.cn_name)
# 访问自定义的desc属性
print('FEMALE的desc:', Gender.FEMALE.desc)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值