初识面向对象四(装饰器/反射)

常用装饰器

@classmethod
@property
@staticmethod
class A:
__count = 0 # 隐藏了count属性
def __init__(self,name):
self.name = name
self.__add_count() # 每一次实例化的时候调
# 用私有方法来对__count进行累加
@classmethod
def __add_count(cls): # 定义一个私有的方法
# print(cls,A)
cls.__count += 1 # 让这个方法只能在类的内部被使用

@classmethod # 被classmethod装饰器装饰的方法,都有一个默认的参数,这个参数就是当前类
def show_count(cls): # 定义一个普通方法,
# print(cls,A)
return cls.__count # 让用户可以从外部查看__count的值

def eat(self):
print('%s在吃饭'%self.name)
print(A.show_count())
alex = A('alex')
print(alex.show_count())
yuan = A('yuan')
print(A.show_count())
有的时候,
在类中会有一种情况,就是这个方法并不需要使用某一个对象的属性
因此 这个方法中的self参数是一个完全无用的参数
show_count是一个查看类中属性的方法,这样的方法和某一个对象并没有直接联系

本质上 : 一个方法不用对象属性但是使用静态属性 -- 类方法@classmethod
某一个方法被创造出来,就是为了进行对静态变量进行操作
根本不涉及到对象
所以这个方法就应该被定义成 类方法(被@classmethod装饰)
调用这个类方法,可以使用对象调用,也可以使用类调用
但是这个方法的默认参数永远是当前类的命名空间,而不是对象的

如果一个类中的方法不用对象属性也不用静态属性 -- 静态方法@staticmethod
那实际上这个方法就是一个普通的函数
class Student():pass
class Manager():pass
def login(arg1, arg2): # 全局的名字 函数的名字
print(arg1, arg2)

login(1,2)
先登录
在登陆的过程中知道了用户的身份 : Manager Student
之后再进行实例化

纯面向对象编程
class User(object):
@staticmethod
def login(arg1,arg2): # 是User类中的名字 函数的名字 login就是一个类中的静态方法,本质上就是一个函数
print(arg1,arg2)
return (arg1+arg2)
class Student(User):pass
class Manager(User):pass

ret = User.login(1,2)
print(ret)

如果在上面的例子中,没有Student类,只有一个角色,就是Manager类
class Manager(object):
@staticmethod
def login(arg1, arg2): # 是User类中的名字 函数的名字 login就是一个类中的静态方法,本质上就是一个函数
print(arg1, arg2)
return (arg1 + arg2)

ret = Manager.login(1,2)
print(ret)

普通的方法 类方法 静态方法
默认参数 self cls 无
操作的变量 操作对象的属性 操作静态属性 既不操作对象属性,也不操作类的属性
所属的命名空间 类 类 类
调用方式 对象 类/对象 类/对象
对应的装饰器 无 @classmethod @staticmethod

学生选课系统
class Student:
def __init__(self):
# self :属于这个学生自己的一块空间
self.courses = []

@staticmethod
def show_courses(): # 不是查看已选课程,而是查看所有课程 -- 静态方法
# 不是操作学生对象本身空间中的数据,而是所有的学生这个方法的结果都是一样的
print('打开课程文件,一个一个读出来')

def select_courses(self): # 选课 是一个对象方法(普通的方法)
self.courses.append('某一门课程') # 操作的课程一定是属于某一个对象

Student.show_courses()
alex = Student()
alex.show_courses()
一个不需要用到对象命名空间中的变量的方法,就不是一个对象方法,就应该是一个普通的函数


class Student:
文件的路径 = 'student.info'
def __init__(self):
# self :属于这个学生自己的一块空间
self.courses = []

@classmethod
def show_courses(cls): # 由于查看文件需要用到Student类中的一个静态属性 -- 类方法
print('打开课程文件%s,一个一个读出来'%cls.文件的路径)

def select_courses(self): # 选课 是一个对象方法(普通的方法)
self.courses.append('某一门课程') # 操作的课程一定是属于某一个对象

Student.show_courses()
abc = Student()
abc.show_courses()



用哪一个命名空间中的名字,就定义不同的方法
只要用self 就是普通方法,只能用对象调
只要用cls 就是类方法,可以用类,可以用对象
啥也不用 就是静态方法,可以用类,可以用对象

私有的
私有的普通方法
私有的类方法
私有的静态方法

巧用装饰器思想

先定义类
写方法
写具体的方法中的代码
写完之后,发现没有用到self,那么如果用到类,就定义成类方法,如果啥也没用到,静态方法

先定义函数
写函数
写具体函数中的代码
写完之后,发现要挪进类里,如果啥也没用到,静态方法;如果用到类,就定义成类方法


细说@property(重要)
# @property
# 例1 - 1 (某一个属性如果是通过计算得来的,那么计算的过程写在方法里,把这个方法伪装成属性)
# from math import pi
# class Circle:
# def __init__(self,r):
# self.r = r
#
# @property # 把一个方法伪装成属性 源码中有人写
# def area(self): # 被property装饰器装饰的方法不能传递除self以外的参数
# return pi*self.r**2
#
# @property
# def perimeter(self):
# return self.r*pi*2
#
# c1 = Circle(5)
# print(c1.area)
# c1.r = 10
# print(c1.area)
# 圆c1的面积周长
# alex的名字

# class Circle:
# def __init__(self,r):
# self.r = r
# self.area = pi*self.r**2
# self.perimeter = self.r*pi*2
#
# c1 = Circle(5)
# print(c1.area)
# c1.r = 10
# print(c1.area)

# 例2-1 某一个属性需要被私有化,又需要能被外部查看,这种情况,把这个属性通过方法返回,方法伪装成属性
# class Person:
# def __init__(self,name):
# self.__name = name # 不让外面随便修改
# def get_name(self):
# return self.__name
#
# alex = Person('alex')
# print(alex.get_name())

# 例2-2
# class Person:
# def __init__(self,name):
# self.__name = name # 不让外面随便修改
#
# @property
# def name(self):
# return self.__name
#
# alex = Person('alex')
# print(alex.name)

# 例2-3 修改属性值
class Person:
def __init__(self,name):
self.__name = name # 不让外面随便修改

@property
def name(self):
return self.__name

@name.setter # 之前必须有一个同名的方法被property装饰过
def name(self,new_name):
if type(new_name) is str:
self.__name = new_name

@name.deleter
def name(self):
del self.__name

def set_name(self,new_name):
if type(new_name) is str:
self.__name = new_name

abc = Person('abc')
print(abc.name)
# alex.set_name(123)
# print(abc.name)
abc.name = 'abc123'
print(abc.name)
del abc.name # 只是相当于调用被deleter装饰的方法,并不相当于删除name属性
print(abc.name)


反射
某个命名空间中的某个"变量名",获取这个变量名对应的值
你有没有什么时候
能拿到 字符串
你就希望能够通过这个字符串 --> 程序中的变量名(类名函数名变量名方法名对象名)

class Manager:pass
class Student:pass
class Teacher:pass
identify = 'Student'
print(eval(identify)())
if 'identify' == 'Manager':
Manager()
elif 'identify' == 'Student':
Student()
elif 'identify' == 'Teacher':
Teacher()

class Person:
role = '人类'
Country = '中国'

attr = input('>>>') # role 人类
# # Country 中国
# print(getattr(Person,'role'))
# print(getattr(Person,'Country'))
if hasattr(Person,attr):
print(getattr(Person,attr))

if attr == 'role':
print(Person.role)
elif attr == 'Country':
print(Person.Country)


getattr(命名空间,'key') == 命名空间.key
所有的a.b都可以被反射成getattr(a,'b')

反射类中的方法
class Person:
role = '人类'
@staticmethod
def show_courses():
print('所有课程')
Person.role == getattr(Person,'role')
Person.show_courses() == getattr(Person,'show_courses')()
ret = getattr(Person,'show_courses')
ret()

类名.静态属性/类名.类方法/类名.静态方法
list /[1,2,3].append()
对象.对象属性/对象.普通方法/对象.类方法/对象.静态方法

模块名.方法名
import time
import math
print(time.time()) #'time'
print(getattr(time,'time')())
print(getattr(math,'pi'))


getattr(类名,"静态属性")
getattr(类名,"类方法")()
getattr(类名,"静态方法")()

getattr(对象名,"对象属性")
getattr(对象名,"方法")()
getattr(对象名,"类方法")()
getattr(对象名,"静态方法")()

getattr(模块,"全局变量")
getattr(模块,"函数名")

类对象模块 实际上都是有自己的命名空间,从这个命名空间中获取某个值或者函数...名字
如果这个名字是字符串数据类型
值 = getattr(命名空间,字符串类型名字)
如果getattr的值是一个属性或者普通的变量 那么直接得到结果
如果getattr的值是函数或者方法 那么只能得到地址,需要我们手动加括号来调用

4. 反射全局变量的值(反射本文件中的名字)
from sys import modules
a = 1
b = 2
lst = [1,2,3]

class Manager:pass
class Student:pass
class Teacher:pass
getattr(modules[__name__],'Student')
identify = input('>>>').strip()
类 = getattr(modules[__name__],identify)
print(类)
对象 = 类()
print(对象)


if 'identify' == 'Manager':
Manager()
elif 'identify' == 'Student':
Student()
elif 'identify' == 'Teacher':
Teacher()


归纳总结
什么是封装?
广义上
狭义上
类的命名空间(类的对象共享的资源) :
静态属性
类方法
静态方法
普通方法
property方法
对象的命名空间(对象独有的资源):
对象的属性
对象的方法

狭义上
私有成员
在类的内部 __成员名
在类的外部 不能用
在存储的空间中 _类名__成员名

1.私有成员不能在类的外部使用,也不能被继承
无论在哪个类中调用私有成员,一定是在哪个类调,就用哪个类的
经典的面试题
class Foo(object):
def __init__(self):
self.__func() # _Foo__func
# self.func()
def __func(self):print('in Foo __func') # _Foo__func
def func(self):print('in Foo func')

class Son(Foo):
def __func(self):print('in Son __func') # _Son__func
def func(self):print('in Son func')

2.类中的三个装饰器方法
先实现功能
某个方法如果用到self 传self
某个方法如果没用到self,用到类 传cls ,加@classmethod装饰器 *****
某个方法如果没用到self,没用到类 啥也不传,加@staticmethod装饰器
但凡是不需要传self参数的,都不需要实例化,直接使用类调用就可以了
@property : 伪装一个方法成为一个属性,调用的时候不需要加()

3.反射 非常重要
a.b这样的情况
如果由于某种原因,b变成了 'b'
那么就是用getattr(a,'b')的形式获取b对应的值
如果b是一个值 那么getattr的结果就是值
如果b是一个地址 那么getattr的结果就是地址,地址()就是执行
from sys import modules
getattr(modules[__name__],'全局变量名')
从当前文件中寻找全局变量对应的值/地址


from sys import modules
a = 2
b = 4
print(getattr(modules[__name__],'b'))
 


 


原文地址:https://www.cnblogs.com/Godisgirl/p/10022662.html