python和ES6来回切换,有时候会把类的写法都搞混了,记录下,方便下次翻一翻记录。
面向对象技术简介:
- 类(Class)
- 类变量(静态属性)
- 数据成员
- 方法重写
- 局部变量
- 实例变量
- 私有属性
Python 中,并没有真正意义的私有属性,方法命名时,实际是对名称做了一些特殊处理,使得外界无法访问到。(伪私有属性和私有方法) - 继承
- 实例化
- 方法(实例方法、类方法、静态方法,私有方法)
静态方法与类方法界限不清晰,都可以访问类,只是不通过cls - 对象
- python的实例可以访问到类方法和静态方法,es6的实例访问不了静态方法
- 似乎只有python才有类方法 @classmethod
>>ES6 类:
class Auth {
constructor(level) {
this.level = level || 1
Auth.USER = 8
Auth.ADMIN = 16
Auth.SUPER_ADMIN = 32
}
get m() {
return async (ctx, next) => {
const userToken = basicAuth(ctx.req)
let errMsg = 'token不合法'
if (!userToken || !userToken.name) {
throw new global.errs.Forbbiden(errMsg)
}
try {
var decode = jwt.verify(userToken.name,
global.config.security.secretKey)
} catch (error) {
if (error.name == 'TokenExpiredError'){
errMsg = 'token已过期'
}
throw new global.errs.Forbbiden(errMsg)
}
if(decode.scope < this.level){
errMsg = '权限不足'
throw new global.errs.Forbbiden(errMsg)
}
// uid,scope
ctx.auth = {
uid:decode.uid,
scope:decode.scope
}
await next()
}
}
static verifyToken(token){
try{
jwt.verify(token,
global.config.security.secretKey)
return true
}
catch (error){
return false
}
}
}
取值函数(getter)和存值函数(setter)
类的方法内部如果含有this,它默认指向类的实例
静态方法:
静态方法包含this关键字,这个this指的是类,而不是实例
父类的静态方法,可以被子类继承
静态方法也是可以从super对象上调用的
静态属性
静态属性:
静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性
Class.propName = '这是静态属性的命名方法一'
class Class{
static propName = "这是静态属性的命名方法二"
}
// 它们都是声明在原形链上prototype
私有方法 和 私有属性:
私有方法和私有属性,是只能在类的内部访问的方法和属性,外部不能访问
私有方法的约定方法有三种:
第一种为在方法名前加下划线 "_" (私有属性也可以这么约定)
第二种将私有方法移除模块内外,模块内通过call调用
第三种为利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值 (私有属性也可以这么约定)
(新提案,在属性名和方法名之前,加#表示,如下)
觉得这个方法还是试行阶段。未做到统一,复制阮老师的代码,在node12还会报错
class a1 {
//私有属性
#a;
constructor() {
this.#a = 'private field';
this.c = 'c';
}
b() {
console.log(`hello ${this.#a} ${this.c}`);
this.#c();
// this.#d();
}
// 私有方法
#c = function(){
console.log('### c');
}
// 语法不正确
// #d() {
// console.log('### d');
// }
}
let cl_a = new a1();
cl_a.b();
// console.log(cl_a.#a);
// console.log(cl_a.#c());
super 关键字:
super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
- 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
- super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
>>python 类:
class User(Base):
id = Column(Integer, primary_key=True)
email = Column(String(24), unique=True, nullable=False)
nickname = Column(String(24), unique=True)
# 权限等级 普通用户默认为 1
auth = Column(SmallInteger, default=1)
_password = Column('password', String(100))
# 重写模型keys方法
# dict(对象) 只能拿到对象的实例变量 拿不到类变量 需要通过上述方法该找
# dict(o) 如果dict传入对象 其会调用对象的keys方法获取key值 然后通过中括号形式o['name']访问变量
# 默认对象是不可以中括号的形式访问变量 o['name'] 所以要在__getitem__方法通过getattr() 方法获取对象和类的变量
# 见app/models/user.py
def keys(self):
# 一个元素的元组定义需要加逗号 ('name',)
# 使用列表就不用加逗号 ['name']
return ['id', 'email', 'nickname', 'auth']
@property
def password(self):
return self._password
# 用户密码加密
@password.setter
def password(self, raw):
self._password = generate_password_hash(raw)
# 注册方法
# 为什么要用静态方法声明?
@staticmethod
def register_by_email(nickname, account, secret):
with db.auto_commit():
# 因为这里已经实例化了,所以上述要用静态方法,为了符合面向对象写法 ??
user = User()
user.nickname = nickname
user.email = account
user.password = secret
db.session.add(user)
@staticmethod
def verify(email,password):
# TODO 这么写好像不能重定义msg内容
# TOTO 这里如果不传email=email 会默认返回表第一个数据 ?
user = User.query.filter_by(email=email).first_or_404()
# user = User.query.filter_by(email=email).first()
# if not user:
# raise NotFound(msg = '没找到该用户')
if not user.check_password(password):
raise AuthFailed(msg='没找到该用户,请检查账号密码')
# return {'uid': user.id}
scope = 'AdminScope' if user.auth == 2 else 'UserScope'
return {'uid': user.id, 'scope': scope}
# raw 是用户传过来的原始密码
def check_password(self, raw):
if not self._password:
return False
return check_password_hash(self._password, raw)
class APIException(HTTPException):
code = 500
msg = 'sorry, we made a mistake (* ̄︶ ̄)!'
error_code = 999
def __init__(self, msg=None, code=None, error_code=None,
headers=None):
if code:
self.code = code
if error_code:
self.error_code = error_code
if msg:
self.msg = msg
super(APIException, self).__init__(msg, None)
# 自定义更改模块内容,默认是 text/html
# 下面更改为json内容
# 参照:C:/Users/roy/.virtualenvs/govtool_api-NTdE09zx/Lib/site-packages/werkzeug/exceptions.py
def get_body(self, environ=None):
body = dict(
msg=self.msg,
error_code=self.error_code,
request=request.method + ' ' + self.get_url_no_param() # 方法里面调用静态方法
)
text = json.dumps(body)
return text
def get_headers(self, environ=None):
"""Get a list of headers."""
return [('Content-Type', 'application/json')]
@staticmethod
def get_url_no_param():
full_path = str(request.full_path)
main_path = full_path.split('?')
return main_path[0]
class A:
# 静态属性
total = 0
_phone = '暂未设置号码'
def __init__(self, name):
A.total += 1
self.__private_attr = '这是一个私有属性'
self.name = name
# 私有方法
def __privateFuc(self):
print('私有方法')
print('私有属性: ', self.__private_attr)
variable = self.getTotal()
print(variable)
def set_name(self, name):
self.__privateFuc()
self.name = name
@property
def phoneNumber(self):
return self._phone
# 用户密码加密
@phoneNumber.setter
def phoneNumber(self, raw):
self._phone = raw
# 静态方法,不用加 self
# 其他都要
@staticmethod
def getTotal():
print('getTotal 这是静态方法, 静态属性total:', A.total)
return '方法里面调用静态方法'
# 类方法
@classmethod
def getTotalCls(cls):
print('getTotal 这是类方法法, 静态属性total:', cls.total)
man = A('roy')
man2 = A('jazz')
print('----get set方法:电话号码-----')
print(man.phoneNumber) # 暂未设置号码
man.phoneNumber = '8831684'
print(man.phoneNumber) # 8831684
print('----类静态属性、方法-----')
man.set_name('roben')
# 私有方法
# 私有属性: 这是一个私有属性
# getTotal 这是静态方法, 静态属性total: 2
# 方法里面调用静态方法
man.getTotal() # getTotal 这是静态方法, 静态属性total: 2
A.getTotal() # getTotal 这是静态方法, 静态属性total: 2
man.getTotalCls() # getTotal 这是类方法法, 静态属性total: 2
A.getTotalCls() # getTotal 这是类方法法, 静态属性total: 2
print(A.total) # 2