21_python笔记-面向对象3


博客cPen_web

知识点1 静态方法、类方法、实例方法

方法
·普通(实例)方法(使用实例中的数据) => 给实例使用(一定要传递一个实例,由实例调用)
·静态方法(无需使用实例封装的内容@staticmethod)
·类方法(会自动加当前类的类名 @classmethod) => cls表示类本身

示例1:方法

#静态方法与类方法
###属性
#静态属性 --> 类属性
#普通属性 --> 实例属性

###方法
#实例方法
#静态方法
#类方法
#-------------------------------------------------------------------------------------------
class Tst():
    name = "tst"
    data = "this is data"   # 注:静态属性

    def __init__(self):
        self.instance = "instance"  # 注:实例属性

    #普通(实例)方法
    def normal_mathod(self, name):
        print("normal:")
        print(self.data, name)  # 注:实例对象 可以访问类属性data

    # def test(): # 注:直接这样写不属于实例方法
    #     print("test")   # 注:放在类空间里面的普通函数

    #类方法
    @classmethod    # 注:第1个参数cls 代表类本身(可以不用传)
    def class_method(cls, name):    # 注:cls 代表当前类
        print("classmethod:")
        print(type(cls),cls)
        print(cls.data, name)   # 注:可以使用cls.属性名访问类属性,不能访问实例属性

    #静态方法
    @staticmethod   # 注:有几个参数 必须传几个参数
    def static_method(name):
        print("static_method:")
        print(name, Tst.data)

cls1 = Tst()    # 注:实例化对象
print(type(cls1))
#结果为 <class '__main__.Tst'>

###实例调用 类方法,实例方法,静态方法 都能通过实例去调用
cls1.class_method("classmethod")    # 注:实例对象 可以访问类方法
#结果为
# classmethod:
# <class 'type'> <class '__main__.Tst'> # 注:type是所有类的源类
# this is data classmethod
cls1.normal_mathod("normalmethod")    # 注:实例对象 可以访问实例方法
#结果为 normal: # this is data normalmethod
cls1.static_method("static_method") # 注:实例对象 可以访问静态方法
#结果为 static_method: # static_method this is data

###通过类名去调用实例方法的时候,需要把实例对象作为参数传递进去
###类方法和静态方法 可以通过类名去调用
Tst.normal_mathod(cls1,"normal_method")
Tst.class_method("class_method")
Tst.static_method("static_method")

###总结
#1、实例方法
#   只能通过实例对象调用,类对象调用的话,需要传递实例作为参数。
#   实例方法内部通过 self.属性名 去访问实例属性和类属性
#   使用对象调用实例方法时,第1个参数可以不用传,就代表实例本身
#2、类方法
#   可以通过实例调用,也可以通过类去调用,第1个参数代表类本身 可以不用传
#   可以使用 cls.属性名 去访问类属性
#   前面要装饰器#classmethod
#3、静态方法
#   可以通过实例对象、类名去调用,但是每个参数都必须必须传递
#   方法的内部访问属性,通过 类名.属性名 去访问类属性
#   前面要加装饰器@staticmethod

#__init__是实例方法,__new__是静态方法

属性包装(@propert)
·把函数包装成属性,使用的时候用对象名.属性名

示例2:属性包装

###属性包装
#@property
#这个装饰器可以把一个函数封装成普通属性
class A:
    tmp = "tmp"

    @property
    def show(self):
        print("i am show")
        return "show"

a = A()
# a.show()  # 注:报错 函数包装成普通属性
a.show
#结果为 i am show
# a.show = "test" # 注:报错
b = a.show
c = a.show
#结果为 i am show ; i am show
print(b,c)
#结果为 show show

示例3:属性包装

#设置年龄范围在0-150之间
class Person():
    _age = 1
    def get_age(self):
        return self._age
    def set_age(self,age):
        if 0<age<150:
            self._age = age
        else:
            raise ValueError("年龄范围错误")
p = Person()
p.set_age(10)
print(p.get_age())
#结果为 10

p._age = 100    # 原来的方法 不能直接报错
#----------------------------
###属性包装
class Person():
    _age = 100

    #property   本身会创建另外2个装饰器 @age.setter @age.deleter
    @property
    def age(self):
        return self._age

    @age.setter # 注:setter装饰器时age的 去包装下面这个函数
    def age(self,_age):  # 注:函数名必须叫age
        if 0<_age<150:
            self._age = _age
        else:
            raise ValueError("年龄范围错误")

    @age.deleter
    def age(self):
        del self._age
p = Person()
# p.age = 120 # 注:报错  不能通过属性去 设置
print(p.age)
#结果为 100

p.age = 120
print(p.age)
#结果为 120
# p.age = 160   # 注:报错     raise ValueError("年龄范围错误")
# ValueError: 年龄范围错误
#看到24.00
#把它作为属性去使用(属性包装)

del p.age   # del删掉的是自己的实例空间对象,找的类空间的对象
print(p.age)    # 能够通过实例去访问类空间的属性,但是实例del只会删除实例空间的,不能删除类空间的
#结果为 100    # 类空间的属性

练习2 属性包装

#设置Person类 对象 设置属性name 这个name必须以数字、字母、下划线组成 长度在6-12位之间 不符合规范报错 给出提示信息

示例

#设置Person类 对象 设置属性name  这个name必须以数字、字母、下划线组成 长度在6-12位之间  不符合规范报错 给出提示信息
#属性包装
import re
class Person():
    _name = "wy123456"    # 注:给它初始值
    # 注:初始值可以给它设置成类属性,也可以给它设置成实例属性(__init__初始化函数)

    #property   属性包装 本身会创建另外2个装饰器 @name.setter设置 ; @name.deleter删除
    @property   # 注:属性包装
    def name(self):
        return self._name   # 注:_name变量随便定,不一定以下划线开头

    @name.setter    # 注:对_name进行设置
    def name(self,_name):
        if re.findall("^\w{6,12}$",_name):
            self._name = _name
        else:
            raise ValueError("name必须以6-12位的数字、字母、下划线组成")

p = Person()
p.name = "abcabc123456"
print(p.name)
#结果为 abcabc123456

知识点3 Python类中的下划线

以单下划线开头的(foo)
·类:这类成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量
·模块:如果你写了代码“from <模块/包名> import *”,那么以“
”开头的模块和包都不会被导入,除非模块或包中的“all”列表显式地包含了模块和包。

以双下划线开头的(__foo) # 注:私有对象/标识/变量
·类:只有类对象自己能访问,连子类对象也不能访问到这个数据。强行访问“对象名._类名__xxx“这样的方式 # 注:Python里面没有绝对的私有,它是一种伪私有
·模块:不能用“from xxx import *“导入包/模块。

以双下划线开头和结尾的(foo)
·代表Python中特殊方法专用的标识。

示例

class Parent:
    '''				# 注:文档注释
    this is test parent
    '''
    tmp = "tmp"
    _min = 1    # 保护属性
    __max = 10  # 私有属性

    def __init__(self):
        self.name = "wen"
        self._sex = "女"
        self.__age = 18

    def __make(self):
        print("这是一个私有方法")
        print(self.__age)

    def _protectmake(self): # 注:以_开头的成员叫做保护成员 自己和子类对象可以访问
        print("这是一个保护方法")

    def show(self):
        print("this is show:", self.__max)  # 注:私有成员 只供类内部自己使用 (外部不可以访问)

class Child(Parent):
    def __init__(self):
        self.name = "wen2"
        self.age = 29

class Child2(Child):
    pass

#类属性       tmp,_min,__max
#实例属性     name,__age
#子类实例属性 name,__age
p = Parent()
c1 = Child()
c2 = Child2()
#访问普通变量
print(p.tmp, c1.tmp, c2.tmp)
#结果为 tmp tmp tmp
#注:它如果没有 会去类空间找 类空间没有去父类空间找 父类空间没有去父父类空间找

#访问保护变量     类对象子类对象都能访问
print(p._min, Parent._min)  # 注:保护变量可以通过类的对象和类访问
#结果为 1 1
print(c1._min, Child._min)  # 注:儿子也可以访问保护变量
#结果为 1 1
print(c2._min, Child2._min) # 注:孙子也可以访问保护变量
#结果为 1 1
c1._protectmake()   # 注:保护方法也是可以访问的
#结果为 这是一个保护方法
c2._protectmake()   # 注:保护方法也是可以访问的
#结果为 这是一个保护方法
#保护成员 在类的使用的时候 和普通成员差不多 只不过不能被from xxx import * 导入

###双下划线开头   私有成员,只供类内部自己使用
#私有成员 无法给外部使用
# print(p.__max)      # 注:报错  实例化对象
# print(Parent.__max) # 注:报错  类
p.show()    # 注:可以执行    --> Parent.show(p) 实际上是类去运行
#结果为 this is show: 10
# p.__make()        # 注:报错 提示没有__make这个属性
#AttributeError: 'Parent' object has no attribute '__make'

#__dict__查看命令空间中有哪些属性	# 注:返回的数据 类型是字典
#Python中没有绝对的私有
print(p.__dict__)   # 注:__dict__ 查看空间属性	# 注:返回的数据 类型是字典
#结果为 {'name': 'wen', '_sex': '女', '_Parent__age': 18}	# 注:使用字典形式存放
#以__定义了后 内部把你定义的变量名改了个名字 存放在命名空间里 前面加了个类 (外部不知道所以不能访问)
print(Parent.__dict__)  # 注:查看Parent 类空间里有那些属性/方法    # 注:返回的数据 类型是字典
#结果为 {'__module__': '__main__', 'tmp': 'tmp', '_min': 1, '_Parent__max': 10, '__init__': <function Parent.__init__ at 0x0000019A01F77AF0>, '_Parent__make': <func……}
#注:使用字典形式存放
#__init__这些实例方法 都在类空间里

#print(p.__age) --> _Parent__age    # 注:实际上是把__age改名为_Parent__age
#定义__max --> 转成了 _类名__max   (以此达到私有的目的)
print(p._Parent__age)   # 注:这样访问
#结果为 18
p._Parent__make()       # 注:这样访问
#结果为 这是一个私有方法
###Python 私有变量是一个伪私有

###总结
##以单下划线_开头的变量叫保护属性,保护属性 类对象及子类对象都可以访问
#使用方式和普通属性没区别,但作为模块from xxx import * 不会被导入
##以__开头的叫 私有属性 只有类的内部自己使用的 外部不能被访问
#查看实例的命名空间p.__dict__
#查看类的命名空间  Parent.__dict__
#返回的数据 类型是字典,使用字典形式存放
#===========================================================================================
#示例:查看类属性和方法
#-------------------------------------------------------------------------------------------
###查看类属性和方法
#·dir(Person):了解Person类里的变量和方法
#·Person.__dict__:可以了解哪些是变量哪些是方法

###内置属性及其功能
#·__dict__:类的属性(包含一个字典,由类的数据属性组成)
#·__doc__:类的文档字符串
#·__name__:类名
#·__module__:类定义所在的模块
#·__bases__:类的所有父类构成元素

#注:继承object 这些属性都会有的
print(Parent.__dict__)      # 注:查看命令空间里的属性(内置属性)
#结果为 {…… '__dict__': <attribute '__dict__' of 'Parent' objects> ……}
#注:空间里有__dict__属性
print(Parent.__doc__)       # 注:查看文档注释
#结果为     this is test parent    # 注:第一个三引号引起来的就是它的文档注释 (说明信息)
#help查看的信息其实就是它的__doc__信息
print(Parent.__name__)      # 注:返回类名
#结果为 Parent
print(Parent.__module__)    # 注:定义所在的模块
#结果为 __main__
#类似于 if __name__ == "__main__"  作为主程序运行
print(Child2.__bases__)     # 注:返回父类元素
#结果为 (<class '__main__.Child'>,)    # 注:没有返回Child 没有返回所有的父类元素
print(p.__class__)          # 注:返回的是它的类
#结果为 <class '__main__.Parent'>
#注:继承objetc后 这些属性都会有的

知识点4 常用魔术方法和属性

构造函数(new/init
析构函数(del
调用方法(call
获取数据(getitem
删除数据(delitem
设置数据(setitem
获取可迭代(iter

示例1:del call

class A(object):
    def __del__(self):  # 析构函数  再销毁之前需要做的事情
        print("delete myself")  # 销毁之前先执行这个
        del self

    def __call__(self, name, age):  # 调用方法
        print(f"my name is {name}, my age is {age}")

a = A() # 实例化对象
a("wen",10) # 把实例当做函数去调用(需要的参数是call函数定义的参数)
#结果为 my name is wen, my age is 10
# delete myself     # 注:程序执行完了 对象自动销毁

#注:这2个魔术方法不能改它的名字

示例2:str repr

# __str__  __repr__ 都是对象实例的描述信息
# __str__默认情况下调用的就是__repr__
# __str__给用户看的
# __repr__更加官方一点,给程序员看的
>>> class A:
...     def __str__(self):			# 注:返回str里面的说明 (给用户看的)
...         return "ok"
...     def __repr__(self):			
...         return "repr ok"		# 注:表示对于类的官方申明
... 
>>> a = A()
>>> a							# 注:返回repr里面的官方声明 (给程序员看的)
repr ok
>>> print(a)						# 注:返回str里面的说明 (给用户看的)
ok

示例3:没有定义__repr__ 返回的是16进制地址

>>> class A:
...     def __str__(self):			# 注:没有定义__repr__的话返回的是16进制地址
...         return "ok"
... 
>>> a = A()
>>> a
<__main__.A object at 0x7fb5b61e24e0>
>>> print(a)
ok
>>> class A:
...     pass
... 
>>> a = A()
>>> a							# 注:没有定义__repr__的话返回的是16进制地址
<__main__.A object at 0x7fb5b61e2588>

示例4:没有定义__str__返回的就是__repr__

>>> class A:
...     def __repr__(self):				# 注:没有定义str返回的就是repr
...         return "repr ok"
... 
>>> a = A()
>>> a
repr ok
>>> print(a)
repr ok

示例5:getitem setitem delitem

#__getitem__
#__setitem__
#__delitem__

#以字典形式去获取/设置参数
class A:
    def __init__(self):
        self.data = {}

    def __getitem__(self, key): # 注:获取字典的值
        print("get data:")
        return self.data.get(key, 0)
    def __setitem__(self, key, value):  # 注:设置字典的值
        print("set data:", key, value)
        self.data[key] = value
    def __delitem__(self, key):
        print("delete data")
        del(self.data[key])     # 注:交给del函数去处理
    def show(self):
        print(self.data)

a = A()
# a.data["key"] = "123"     # 注:以前
a["key"] = "123"
a["key2"] = "1234"
#结果为 set data: key 123
# set data: key2 1234
print(a["key"])
#结果为 get data:
# 123
a.show()
#结果为 {'key': '123', 'key2': '1234'}
del a["key"]    # 注:删除里面某一个key  传1个参数进来 识别它是字典
a.show()
#结果为 {'key2': '1234'}

#-------------------------------------------------------------------------------------------
#发邮件
#smtplib emial 模块
#smtplib 发邮件
#emial   构造邮件内容
import smtplib
from email.mime.multipart import MIMEMultipart
message = MIMEMultipart()
message["From"] = "1533431376@qq.com"
message["To"] = "xx"    # 注:为什么内这么写? 因为重写了__getitem__ __setitem__ __delitem__

其他魔术方法
·eq(self, other) 定义了等号的行为, ==
·ne(self, other) 定义了不等号的行为, !=
·lt(self, other) 定义了小于号的行为, <
·gt(self, other) 定义了大于等于号的行为, >=
·add(self, other) +运算
·mul(self, other) *运算
·len(self, other) 获得长度

示例6:add 定义加法的行为

#__add__  定义加法的行为
class A:
    def __init__(self,num):
        self.num = num
    def __add__(self, x):   # add 后面要接参数
        print("this is add")
        return self.num + x
class B(A):
    pass

a = A(1)
b = a + 2
print(b)
#结果为 None   # 注:没有任何返回
#结果为 3      # 注:return后 return self.num + x

知识点5 Python自省

·在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。

自省有4个方法
·getattr(obj, ‘name’): 获取成员
·根据字符串去获取obj对象里的对应的方法的内存地址
·hasattr(obj, ‘name’): 检查是否含有成员
·判断一个对象obj里是否有对应的name_str字符串的方法
·setattr(obj, ‘age’, 18): 设置成员
·delattr(obj, ‘name’): 删除成员

示例1:判断\获取\设置\删除 成员

class A:
    name = "wen"
    def __init__(self):
        self.age = 18
    def talk(self):
        print("i am talk")

a = A()
#检查是否有成员属性
print(hasattr(a, "xx")) # 内置函数 判断a对象 有没有 "xx" 属性
#结果为 False
print(hasattr(a, "name"))
#结果为 True

#访问成员属性
#获取成员属性
if hasattr(a, "xx"):    # 注:校验有没有这个属性
    print(getattr(a, "xx"))

if hasattr(a, "name"):
    print(getattr(a, "name"))   # getattr 获取成员属性
    #结果为 wen

if hasattr(a, "talk"):  # 检查是否有 成员方法
    b = getattr(a, "talk")  # 注:调用函数方法
    b() # 通过括号运行
    #结果为 i am talk
    getattr(a, "talk")()    # 注:调用函数方法
    #结果为 i am talk
    print(getattr(a, "talk"))   # 注:可以获取函数对象
    #结果为 <bound method A.talk of <__main__.A object at 0x000001E464C0C5E0>>
    #注:显示出一串内存地址 (__repr__属性)

#设置成员属性
if not hasattr(a, "tmp"):
    setattr(a, "tmp", "hello world")    # 注:设置成员属性
    print(getattr(a, "tmp"))    # 注:获取成员属性 结果为 hello world

#设置方法
def talk_1():
    print("i am talk_1")
if not hasattr(a, "talk2"):
    setattr(a, "talk2", talk_1) # 不能写成talk_1() 这是运行函数 把函数运行的返回值传递给它 为None
a.talk2()
#结果为 i am talk_1

#删除
if hasattr(a, "talk2"): # 注:查看有没有这个属性/方法
    delattr(a, "talk2") # 有的话就删除这个属性/方法

示例2:模块中使用自省功能

#这是Python的自省,不是类的自省
#模块中使用自省功能
[root@cPen_python lianxi]# vim mod1.py 
a = 3
b = 4

def  func1():
    print("func1")
#-------------------------------------------------------------------------------------------
[root@cPen_python lianxi]# python3
>>> import mod1
>>> hasattr(mod1,"a")		# 注:判断是否有a成员
True
>>> getattr(mod1,"a")		# 注:有的话就获取它
3
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mycpen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值