面向对象的结尾

1 > 反射的实际案例

  编写利用面向对象编写系统终端功能


'''编写不同系统的终端功能'''
class WinCmd(object):
	def ls(self):
        print('windows系统正在执行ls命令')
    def dir(self):
        print('windows系统正在执行dir命令')
    def cd(self):
        print('windows系统正在执行cd命令')
class LinuxCmd(object):
	def ls(self):
        print('windows系统正在执行ls命令')
    def dir(self):
        print('windows系统正在执行dir命令')
    def cd(self):
        print('windows系统正在执行cd命令')
 # 简易版本
	obj = WinCmd()
 	obj1 = LinuxCmd()
 	while True:
 		cmd = input('请输入你想执行的指令 >>>>>:').strip()
 		# 利用反射判断类当中是否有该方法
 		if hasattr(obj, cmd):
 			func_name = getattr(obj, cmd)
 			func_name()
 		else:
 			print('cmd command not found')
 # 函数版本
 	obj = WinCmd()
 	obj1 = LinuxCmd()
 	def run(obj1)
 		while True:
 			cmd = input('请输入你想执行的指令 >>>>>:').strip()
 			# 利用反射判断类当中是否有该方法
 			if hasattr(obj, cmd):
 				func_name = getattr(obj, cmd)
 				func_name()
 			else:
 				print('cmd command not found')
 	run(obj)   # 进入window系统
 	run(obj1)  # 进入Linux系统
 	

2 > 面向对象的双下方法

   面向对象的双下方法被有些人称之为是魔法方法,意思就是有些双下方法不需要刻意调用达到某个条件会自动触发,例如__init__ 就是在对象实例化的时候自动触发。

2.1 > str

   该方法是当对象被执行打印(print 、前端展示)操作的时候自动触发,该方法必须返回字符串类型的数据,很多时候可以用来更加精准的描述对象,操作如下:

class MyClass(object):
	def __init__(self, name):
		self.name = name
	del __str__(self)
		return 'MyClass产生的对象%s'%self.name
obj = MyClass('bob')
print(obj)
# 打印 MyClass产生的对象:bob

2.2 > del

   该方法当对象被执行(被动,主动)删除之后自动触发操作


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __del__(self)
		return '正在执行del方法'

obj = MyClass('bob')
print('打印功能执行中')     # 当程序运行结束obj会被动删除
# 打印 
'''
 打印功能执行中
 正在执行del方法
 
'''

print(obj)    # 主动删除操作
def obj
'''
正在执行del方法
打印功能执行中
'''

2.3 > getattr

  该方法当对象查找时当对象不存在名字的时候自动触发。


class MyClass(object):
	def __init__(self, name):
		self.name = name
	del __getattr__(self, item)
		return 'MyClass类中没有%s 这个名字'%item

obj = MyClass('bob')
print(obj.name)  # bob
print(obj.age)   # MyClass类中没有age 这个名字

2.4 > setattr

  对象在执行添加属性操作的时候自动触发 例如 obj.变量名 = 变量值


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __setattr__(slef, key, value):
		print(key, value)
		# 加入限制
		if key ==  'age':
			print('你不能拥有%s属性'% key)
		super().__setattr__(key, value)

obj = MyClass('bob')
obj.age = 18
print(obj__dict__)
# 打印 
'''
name bob
你不能拥有age属性
{'name': 'bob'}
'''

2.5 > call

  对象被加括号调用的时候自动触发


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __call__(self, *args, **Kwargs):
		print('__call__方法', *args, **kwargs)
		return '开始执行call方法'
obj = MyClass('bob')
obj(123)
print(obj(123))

'''
__call__方法 (123, ) {}
开始执行call方法	

'''


2.6 > enter

  对象被执行with上下文管理语法开始自动触发,一般与__exit__ 一起使用。该方法返回什么as后面的变量名就会得到什么


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __enter__(self):
		print('__enter__方法')
	def __exit__(self, exc_type, exc_val, exc_tb):
		print('__exit__ 方法')
obj = MyClass('bob')
with obj as f:
	print(111)
print(222)

# 打印
'''
__enter__方法
111
__eixt__方法
222

'''

2.7 > exit

  对象被执行with上下文管理语法结束之后自动触发


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __enter__(self):
		print('__enter__方法')
	def __exit__(self, exc_type, exc_val, exc_tb):
		print('__exit__ 方法')
obj = MyClass('bob')
with obj as f:
	print(111)
print(222)

# 打印
'''
__enter__方法
111
__eixt__方法
222

'''

2.8 > getattribute

  只要对象查找名字无论名字是否存在都会执行该方法
  如果类中有__getattribute__方法 那么就不会去执行__getattr__方法


class MyClass(object):
	def __init__(self, name):
		self.name = name
	def __getattr__(self, item):
		print('__getattr__方法')
	def __getattribute__(self, item):
		print('__getattribute__方法')

obj = MyClass('bob')

print(obj.name)
print(obj.age)

'''
__getattribute__方法
None
__getattribute__方法
None
'''

3 > 笔试题

3.1 > 字典具备句点符相应功能

  让字典具备句点符查找名字的功能和用句点符添加键值对功能。


class MyDict(dict):
	def __getattr__(self, item):
		return self.item
	def __setattr__(self, key, value)
		self[key] = value

obj = MyDict({'name': 'bob', 'age':18})
print(obj.name)
print(obj.age)
obj.pwd = 123
print(obj.pwd)

# 打印
'''
bob
18
123

'''

3.2 > 补全语法

  补全下列代码语法,使其不报错。


class Context:
	pass

with Context() as ctx:
	ctx.do_something


class Context:
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    def do_something(self):
        pass

with Context() as ctx:
    print(ctx)
    ctx.do_something()
    

4 > 元类

4.1 > 间接

  元类即产生类的类

'''前面我们学过可以用type查看数据的数据类型'''
print(type(123))
print(type([11, 22, 33, 44]))
print(type({'name': 'bob', 'pwd': 123})

'''
<class 'int'>
<class 'list'>
<class 'dict'>
'''

'''其实我们查看到的是当前对象所属的类的名称'''
class MyClass(object):
    pass
obj = MyClass()
print(type(obj))
'''
<class '__main__.MyClass'>
'''
print(type(obj))
'''
<class 'type'>
'''

'''所以type就是所有类默认的元类'''

4.2 > 产生类的两种表现形式(本质是一种)

4.2.1 > class关键字


class C1(object):
	pass
print(C1)  # <class '__main__.C1'>

4.2.2 > type元类


type(类名,父类,类的名称空间)
  	res = type('C1', (), {})
		print(res)

4.3 > 元类的基本使用

  使用元类控制类的一些具体的行为,例如使类名的首字母必须是大写:


class MyTypeClass(type):
    def __init__(cls, cls_name, cls_bases, cls_dict):
    '''现在就限制了类名首字母必须是大写'''
        if not cls_name.istitle():
            raise Exception('类名的首字母必须是大写')
        super().__init__(cls_name, cls_bases, cls_dict)
class C1(metaclass=MyTypeClass):
	school = '清华大学'
''' 创建一个为a的类 '''
class a(metaclass = MyTypeClass):
	pass
'''这时候执行程序就会报错'''

'''
Traceback (most recent call last):
  File "D:/Py Projiect/Day_4.11/元类.py", line 22, in <module>
    class a(metaclass=MyTypeClass):
  File "D:/Py Projiect/Day_4.11/元类.py", line 17, in __init__
    raise Exception('类名的首字母必须是大写')
Exception: 类名的首字母必须是大写

'''

4.4 > 元类进阶操作

   一个对象的产生不仅仅是通过类当中的__init__ 方法 而是先通过元类当中的__call__ 方法再进入类当中的__init__ 方法产生一个对象。


class MyTypeClass(type):
	def __call__(self, *args, **kwargs):
	print('__call__run')
	super().__call__(*args, **kwargs)
	
class MyClass(metaclass=MyTypeClass):
	def __init__(self, name):
		print('__init__ run')
		self.name = name
		
obj = MyClass('bob')

   元类当中的__call__ 方法当中的 args, 与Kwargs,分别是用来接收位置参数和关键字参数的,那么我们想要高度定制这个对象的产生过程,让在实例化产生对象的时候只能通过关键字来传入数据。那么我们就可以通过重新 call 方法。操作如下:


class MyTypeClass(type):
	def __call__(self, *args, **kwargs):
	if args:
		raise Exception('必须全部采用关键字参数')
		return super().__call__(*args, **kwargs)
	
class MyClass(metaclass=MyTypeClass):
	def __init__(self, name):
		self.name = name
		
obj = MyClass('bob')
'''
Traceback (most recent call last):
  File "D:/Py Projiect/Day_4.11/元类进阶.py", line 11, in <module>
    obj = MyClass('bob')
  File "D:/Py Projiect/Day_4.11/元类进阶.py", line 4, in __call__
    raise Exception('必须是关键字参数')
Exception: 必须是关键字参数
'''
obj = MyClass(name = 'bob')
print(obj.name)
'''
bob
'''

   以上我们可以得出一个总结就是:
   如果我们想高度定制类的产生过程:就要编写元类当中的__init__方法
   如果我们想高度定制对象的产生过程:就要编写元类中的__call__方法

5 > 双下new方法

   _ new _ 方法用于产生一个空对象,然后由_ init _ 来进行一个实例化。


注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
	如果是在元类的__new__里面 可以直接调用
		class Meta(type):
      def __new__(cls, *args, **kwargs):
          obj = type.__new__(cls,*args,**kwargs)
          return obj
	如果是在元类的__call__里面 需要间接调用
		class Mate(type):
    	def __call__(self, *args, **kwargs):
         obj = object.__new__(self) # 创建一个空对象
         self.__init__(obj,*args,**kwargs) # 让对象去初始化
         return obj

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值