面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
优点和应用场景:
# 定义一个类,Account
class Account:
# 方法, 哪个对象调用方法,其就是self
def login(self,name):
print(123)
return 666
def logout(self):
pass
# 调用类中的方法
x = Account()
# 实例化(创建)Account类的对象,开辟一块内存
val = x.login('henry') # 使用对象调用class中的方法
print(val)
_类名__名字
:命名class File:
def read(self):
with open(self.path, mode='r', encoding='utf-8') as f:
data = f.read()
def write(self, content):
with open(self.path, mode='a', encoding='utf-8') as f:
data = f.write()
obj = File() # 创建对象,并使用
obj.path = 'test.txt' # 往obj对象中写入一个私有对象
obj.write(content)
# 定义私有属性,私有属性在类外部无法直接进行访问
obj2 = File('info.txt')
obj2.write(content)
class Person:
# __init__初始化方法(构造方法),给对象内部做初始化
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def show(self):
temp = 'i am %s, age:%s, gender:%s ' % (self.name, self.age, self.gender)
print(temp)
# 类(),会执行__init__
obj = Person('henry', 19, 'male')
obj.show()
obj2 = Person('echo', 19, 'female')
obj2.show()
# 类有一个名为 __init__() 的构造方法,该方法在类实例化时会自动调用,一般通过object类进行格式化
# 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
# self.__class__:查看实例所在的类
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
类的私有方法**__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods**。
# 循环让用户输入:用户名,密码,邮箱,输入完成后在打印
class Person():
def __init__(self, user, pwd, email):
self.username = user
self.password = pwd
self.email = email
def info(self):
return temp = 'i am %s, pwd:%s, email:%s ' % (self.username, self.password, self.email,)
USER_LIST = []
while 1:
user = input('please input user name: ')
pwd = input('please input user pwd: ')
email = input('please input user email: ')
p = Person(user, pwd, email)
USER_LIST.append(p)
for i in USER_LIST:
data = i.info()
print(i)
场景:多个类中,如果有公共的方法可以放到基类中,增加代码的重用性。
继承:可以对基类中的方法进行覆写
# 父类(基类)
class Base:
def f1(self):
pass
# 单继承,子类,Foo类继承Base类 (派生类)
class Foo(Base):
def f2(self):
pass
# 创建了一个子类对象
obj = Foo()
# 执行对象.方法时,优先在自己类中找,没有则找其父类
obj.f2()
obj.f1()
# 创建了一个父类对象
obj = Base()
obj.f1()
obj.f2() # 会报错
继承关系中的查找方法:
__mro__
方法
__mro__
, 它是一个tuple
, 装着方法解析时的对象查找顺序: 越靠前的优先级越高。class D(object):
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
多态:一个类变现出来的多种状态—>多个类表现出相似的状态。
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,Python崇尚“鸭子类型”。list,tuple,python的多态是通过鸭子类型实现的
# 多态,鸭子模型
def func(arg): # 多种类型,很多事物
v = arg[-1] # 必须具有此方法,呱呱叫
print(v)
# 对于一个函数,python对参数类型不会限制,传入参数时可以是各种类型,在函数中如果有例如:arg.append方法,就会对传入类型进行限制。
# 这就是鸭子模型,类似于上述的函数,我们认为只要能呱呱叫的就是鸭子,只要有append方法,就是我们想要的类型
Python同样支持运算符重载,我们可以对类的专有方法进行重载
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
对象成员:实例变量(字段)
Note:属于谁的只允许谁去取,python允许对象去其类中取变量
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
# python内部装饰器
@staticmethod
def f():
print(1,2)
Foo.f()
obj = Foo()
obj.func(1, 2)
obj.f()
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
# python内部装饰器
@classmethod
def f(cls, a, b):
print(a, b)
Foo.f(1, 2)
obj.f(1, 2) # 不推荐
class Foo:
@property
def func(self):
print(123)
print(666)
obj = Foo()
ret = obj.func
print(ret)
# 示例:属性
class Page:
def __init__(self, total_count, current_page, per_page = 10):
self.total_count = total_count
self.current_page = current_page
self.per_page = per_page
@proporty
def start_index(self):
return(self.current_page -1 ) * self.per_page
@property
def end_index(self):
returno self.current_page * self.per_page_count
USER_LIST = []
for i in range(321):
USER_LIST.append('henry-%s' % (i,))
# 请实现分页
current_page = int(input('请输入要查看的页码:'))
p = Page(321, current_page)
data_list = USER_LIST[p.start_index:p.end_index]
for i in data_list:
print(i)
class Foo:
def __init__(self, name):
self.__name = name
def func(self):
print(self.name)
obj = Foo('alex')
print(obj.__name) # 会报错
obj.func() # 可以访问
class Foo:
__x = 1
@staticmethod
def func():
print(Foo.__x)
obj = Foo()
print(Foo.__x) # 会报错
print(obj._Foo__x) # 强制访问私有成员
以双下划线开头的 **__foo** 代表类的私有成员,以双下划线开头和结尾的 **__foo__** 代表 Python 里特殊方法专用的标识,如 __init__()
代表类的构造函数。
异常处理
class School(object):
def __init__(self,title):
self.title = title
def rename(self):
pass
class Course(object):
def __init__(self, name, school_obj):
self.name = name
self.school = school_obj
def reset_price(self):
pass
class Classes(object):
def __init__(self,cname, course_obj):
self.cname = cname
self.course = course_obj
def sk(self):
pass
s1 = School('北京')
c1 = Course('Python', s1)
cl1 = Classes('全栈1期', c1)
# 示例1
class StarkConfig(object):
pass
class AdminSite(object):
def __init__(self):
self.data_list = []
def register(self, arg):
self.data_list.append(arg)
site = AdminSite()
obj = StarkConfig()
site.regisetr(obj)
# 示例2
class StarkConfig(object):
def __init__(self, name, age):
self.name = name
self.age = aeg
class AdminSite(object):
def __init__(self):
self.data_list = []
self.sk = None
def set_sk(self, arg=StarkConfig):
self.sk =arg
site = AdminSite()
site.set_sk(StarkConfig)
site.sk('henry', 19)
# 示例3
class StarkConfig(object):
list_display = 'henry'
def changelist(self):
print(self.list_display)
class UserConfig(StarkConfig):
list_display = 'echo'
class AdminSite(object):
def __init__(self):
self._register = {}
def registry(self, key, arg=StarkConfig):
self._register[key] = arg
def run(self):
for key, val in self._register.items():
obj = val()
obj.changelist()
site = AdminSite()
site.registry(1)
site.registry(2, StackConfig)
site.registry(3, UserConfig) # 易错点 echo
site.run()
特殊成员:为了能够给快速实现某些方法而生。
# 填充数据,一般称为初始化
class Foo:
"""
此类的作用
"""
def __init__(self):
"""
初始化方法
"""
pass
Note
# __new__ 创建一个空对象
# 通过 __init__ 初始化对像
class Foo(object):
def __new__(cls, *args, **kwargs): # 在 __init__ 之前
return 'henry'/ object.__new__(cls)
obj = Foo()
print(obj)
# 对象() 会执行类中的 __call__ 方法
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('哈哈,你变成我了吧')
Foo()()
# 第三方模块。写一个网站,用户只要来访问,就自动找到第三个参数并执行
make_server('ip', port, Foo())
obj = dict()
obj['k1'] = 123
class Foo(object):
def __setitem__(self, key, values):
print(key, value)
def __getitem__(self, item):
return item + 'uuu'
def __delitem__(self, key):
print(key)
obj1 = Foo()
obj1['k1'] = 123 # 内部会自动调用__setitem__方法
obj1['xxx'] # 内部会自动调用__getitem__方法
del obj1['ttt'] # 内部会自动调用__delitem__方法
# 只有在打印时,会自动调用此方法,并将返回值显示出来
# type 查看
class Foo:
def __str__(self):
print('变样是不是不认识我了')
return 'henry'
obj = Foo()
print(obj)
作用: 查看对象中有哪些变量
class Foo(object):
def __init__(self, name, age, email):
self.name = name
self.age = age
self.email = emial
obj = Foo('henry', 19, '123@qq.com')
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val)
作用:使用with语法时,需要
class Foo(object):
def __enter__(self):
self.x = open('a.txt', mode='a', encoding='utf-8')
return self.x
def __exit__(self, exe_type, exc_val, exc_tb):
self.x.close()
with Foo() as f: # 需要 __enter__ 和 __exit__ 方法
f.write('henry')
f.write('echo')
class Foo(object):
def __init__(self, v):
self.v = v
def __add__(self, other):
return self.v + other.v
obj1 = Foo()
obj2 = Foo()
val = obj1 + obj2 # obj1触发,把obj1传给self
# 可迭代对象
class Foo:
def __iter__(self):
return iter([1, 2, 3, 4])
obj = Foo()
# 示例2
class Foo:
def __iter__(self):
yield 1
yield 2
...
obj = Foo()
class Studnet:
def __init__(self, name):
self.name = name
# 面向用户
def __str__(self):
return self.name
# 内部程序
def __repr__(self):
return '<{}>'.format(self.name)
class Classes:
def __init__(self):
self.students = []
s1 = Studnet('henry')
s2 = Studnet('echo')
# henry echo,优先调用str方法,
print(s1,s2)
c = Classes()
c.students.append(s1)
c.students.append(s2)
# [<henry>, <echo>],调用__repr__方法
print(c.students)
# henry echo,调用__str__方法
for i in c.students:
print(i)
# 类的
cls.__dict__??? # 打印出 cls 类的所有属性和方法,结果为一个字典??
cls.__bases__?? # 类的基类??
cls.__doc__???? # 类的docstring??
cls.__name__??? # 类的名字??
cls.__module__? # 类所在模块,如果是主文件,就是__main__??
# 对象的
obj.__class__???? # 类的类型<class?'__main__.类名'>??
obj.__module__??? # 实例类型所在模块??
obj.__dict__????? # 对象的字典,存储所有实例成员信息??
class Foo(object):
pass
obj = Foo()
print('obj是Foo的对象,开心吧') if type(obj) == Foo else print('哪凉快呆哪去')
# 可以多级继承
class Base(object):
pass
class Bar(Base):
pass
class Foo(Bar):
pass
print(issubclass(Foo, Base))
# 判断某个对象是否时 某个类 或 基类 的实例(对象)
class Base(object):
pass
class Foo(Base):
pass
obj = Foo()
print(isinstance(obj, Foo))
print(isinstance(obj, Base))
# super().func(),根据 self所属类的继承关系进行查找,默认找到第一个就停止
class Bar(object):
def func(self):
print('bar.func')
return 123
class Base(Bar):
def func(self):
super().func()
print('bar.func')
return 123
class Foo(Base):
def func(self):
v = super().func()
print('foo.func', v)
obj = Foo()
obj.func()
# 会打印 hello
# 类里的成员会加载,代码会执行
# 函数只有在调用时执行
class Foo(object):
print('hello')
def func(self):
pass
# 类的嵌套
class Foo(object):
x = 1
def func(self):
pass
class Meta(object):
y = 123
print('hello')
def show(self):
print(y.self)
# 可迭代对象示例1
class Foo:
def __iter__(self):
return iter([1, 2, 3, 4])
obj = Foo()
# 示例2
class Foo:
def __iter__(self):
yield 1
yield 2
...''
obj = Foo()
# python的约束,易错点
# 约束子类中必须要有send方法,如果没有则会抛出:NotImplementedError
class Interface(object):
def send(self):
raise NotImplementedError()
class Foo(Interface):
def send(self):
pass
class Base(Interface):
def func(arg):
arg.send(arg)
# 应用场景示例
class BaseMassage(object):
def send(self):
raise NotImplementedError('子类中必须有send方法')
class Msg(BaseMassage):
def send(self):
print('发送短信')
class Email(BaseMassage):
def send(self):
print('发送邮件')
class Wechat(BaseMassage):
def send(self):
print('发送微信')
class DingDing(BaseMassage):
def send(self):
pass
obj = Email()
obj.send()
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
# getattr示例
class Foo(object):
def __init__(self, name):
self.name = name
obj = Foo('alex')
obj.name
v1 = getattr(obj, 'name')
# setattr示例
obj.name = 'eric'
setattr(obj, 'name', 'eric')
# 反射当前文件内容
import sys
getattr(sys.modules[__name__], 'ab')
# 通过对象获取、示例变量、绑定方法
# 通过类来获取类变量、类方法、静态方法
# 通过模块名获取模块中的任意变量(普通变量、函数、类)
# 通过本文件反射任意变量
# 应用示例
class Foo(object):
def login(self):
pass
def regiseter(self):
pass
obj = Foo()
func_name = input('please input method name: ')
# 获取方法
getattr(obj, func_name)()
# setattr 示例
class Foo(object):
pass
obj = Foo()
setattr(obj, 'k1', 123)
print(obj.k1)
# delattr 示例
class Foo(object):
pass
obj = Foo()
obj.k1 = 999
delattr(obj, 'k1')
print(obj.k1)
import x
v = x.NUM
# 等价于
v = getattr(x, 'NUM')
print(v)
v = getattr(x, 'func')
v()
v = getattr(x, 'Foo')
val = v()
val.x
示例:
# 浏览器两类行为
# way1: 输入地址+回车
get....
# way2: 表单(输入框+按键)
post....
# 浏览器都会有get,post,dispatch方法
class View(object):
def get(self):
pass
def Post(self):
pass
def Dispatch(self): # 请求第一步来这,在进行分发
pass
# 推荐使用性能较好
class Foo(object):
def post(self):
pass
# 方式1
if hasattr(obj, 'get'):
getattr(obj, 'get')
# 方式2:推荐使用
v = getattr(obj, 'get', None)
print(v)
getattr(obj, 'args')()
# 高级用法
flask 上下文管理:LocalProxy对象
场景:数据库连接和数据库连接池(数据一致时)
设计模式:23种设计模式
class Foo(object):
pass
# 每实例化一次,就创建一个新对象,内存地址 不一样
obj1 = Foo()
obj2 = Foo()
# 单例(Singleton)模式,无论是实例化多少次,都用第一次创建的那个对象,内存地址一样
class Singleton(object):
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = Singleton() # 内存地址一致
obj2 = Singleton()
# 需要加锁,多线程,并发
class FileHelper(object):
instance = None
def __init__(self, path):
self.file_object = open(path, mode='r', encoding='utf-8')
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj1 = FileHelper('x') # 内存地址一致
obj2 = FileHelper('x')
# 导入模块,只是保留模块内存
# 思考角度:函数名不能重复、内存溢出
from jd import n1
# 多次导入,模块只会加载一次,即使模块中包含其他模块
import jd
import jd
print(456)
# 多次导入,模块只会加载一次,即使模块中包含其他模块
import importlib
import jd
# 手动加载,会覆盖第一次导入
importlib.reload(jd)
print(456)
# jd.py
class Foo(object):
pass
obj = Foo()
# app.py
import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj
print(jd.obj)
import os
import re
import datetime
import xlrd
import requests
# app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置)
app.py 越简单越好,少于10行
# app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置)
# bin(多个可执行文件例如:student.py,teacher.py,admin.py)
# log (存储日志文件)
# seetings(BASE_PATH,LOG_FILE_NAME...)
path = sys.path.os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
from types import MethodType, FunctionType
def fun():
pass
print(isinstance(func, FunctionType)) # True
print(isinstance(list.append(), MethodType)) # True
class Foo:
def fun(self):
pass
obj = Foo()
obj.fun() # 方法
Foo.fun(123) # 函数
# 通过对象调用是方法,通过类调用时函数
原文:https://www.cnblogs.com/henryw/p/11681388.html