文章目录
博客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