08-27-周三_17-09-29
This commit is contained in:
345
Python/Python面向对象/反射与双下方法.md
Normal file
345
Python/Python面向对象/反射与双下方法.md
Normal file
@@ -0,0 +1,345 @@
|
||||
# 反射
|
||||
|
||||
Python 中,反射(Reflection)是一种能力,使得程序能够在运行时查看和修改自身的结构和行为。通过反射,您可以动态地访问和操作类的属性和方法,而无需在编写代码时确定它们的确切名称。这在某些情况下非常有用,例如在框架、库或插件系统中。
|
||||
|
||||
## 对对象的反射
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
f = "类的静态变量"
|
||||
|
||||
def __init__(self, name, age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
|
||||
def say_hi(self):
|
||||
print("Hi %s" % self.name)
|
||||
|
||||
|
||||
obj = Foo("EaglesLab", 18)
|
||||
|
||||
# 检测是否含有某属性
|
||||
print(hasattr(obj, "name"))
|
||||
print(hasattr(obj, "say_hi"))
|
||||
|
||||
# 获取属性
|
||||
print(getattr(obj, "name"))
|
||||
func = getattr(obj, "say_hi")
|
||||
func()
|
||||
|
||||
print(getattr(obj, "job", "不存在啊")) # 报错
|
||||
|
||||
|
||||
# 设置属性
|
||||
setattr(obj, "job", "teacher")
|
||||
setattr(obj, "show_name", lambda self: self.name + " 真帅")
|
||||
print(obj.__dict__)
|
||||
print(obj.show_name(obj))
|
||||
|
||||
# 删除属性
|
||||
delattr(obj, "age")
|
||||
delattr(obj, "show_name")
|
||||
# delattr(obj,'show_name111') # 不存在,则报错
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
## 对类的反射
|
||||
|
||||
```python
|
||||
class Foo(object):
|
||||
staticField = "test"
|
||||
|
||||
def __init__(self):
|
||||
self.name = "陈松"
|
||||
|
||||
def func(self):
|
||||
return "func"
|
||||
|
||||
@staticmethod
|
||||
def bar():
|
||||
return "bar"
|
||||
|
||||
|
||||
print(getattr(Foo, "staticField"))
|
||||
print(getattr(Foo, "func"))
|
||||
print(getattr(Foo, "bar"))
|
||||
```
|
||||
|
||||
## 案例:基于反射的用户管理
|
||||
|
||||
使用反射前
|
||||
|
||||
```python
|
||||
class User:
|
||||
def login(self):
|
||||
print('欢迎来到登录页面')
|
||||
|
||||
def register(self):
|
||||
print('欢迎来到注册页面')
|
||||
|
||||
def save(self):
|
||||
print('欢迎来到存储页面')
|
||||
|
||||
user = User()
|
||||
while 1:
|
||||
choose = input('>>>').strip()
|
||||
if choose == 'login':
|
||||
user.login()
|
||||
|
||||
elif choose == 'register':
|
||||
user.register()
|
||||
|
||||
elif choose == 'save':
|
||||
user.save()
|
||||
```
|
||||
|
||||
用了反射之后
|
||||
|
||||
```python
|
||||
class User:
|
||||
def login(self):
|
||||
print('欢迎来到登录页面')
|
||||
|
||||
def register(self):
|
||||
print('欢迎来到注册页面')
|
||||
|
||||
def save(self):
|
||||
print('欢迎来到存储页面')
|
||||
|
||||
user = User()
|
||||
while 1:
|
||||
choose = input('>>>').strip()
|
||||
if hasattr(user, choose):
|
||||
func = getattr(user, choose)
|
||||
func()
|
||||
else:
|
||||
print('输入错误...')
|
||||
```
|
||||
|
||||
# 函数 vs 方法
|
||||
|
||||
## 通过打印函数(方法)名确定
|
||||
|
||||
```python
|
||||
def func():
|
||||
pass
|
||||
|
||||
print(func)
|
||||
|
||||
class A:
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
print(A.func)
|
||||
obj = A()
|
||||
print(obj.func)
|
||||
```
|
||||
|
||||
## 通过 types 模块验证
|
||||
|
||||
```python
|
||||
from types import FunctionType
|
||||
from types import MethodType
|
||||
|
||||
def func():
|
||||
pass
|
||||
|
||||
class A:
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
obj = A()
|
||||
|
||||
print(isinstance(func,FunctionType))
|
||||
print(isinstance(A.func,FunctionType))
|
||||
print(isinstance(obj.func,FunctionType))
|
||||
print(isinstance(obj.func,MethodType))
|
||||
```
|
||||
|
||||
## 静态方法是函数
|
||||
|
||||
```python
|
||||
from types import FunctionType
|
||||
from types import MethodType
|
||||
|
||||
|
||||
class A:
|
||||
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def func1(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def func2(self):
|
||||
pass
|
||||
|
||||
|
||||
obj = A()
|
||||
|
||||
# 静态方法其实是函数
|
||||
print(isinstance(A.func2,FunctionType))
|
||||
print(isinstance(obj.func2,FunctionType))
|
||||
```
|
||||
|
||||
## 函数与方法的区别
|
||||
|
||||
那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。
|
||||
|
||||
1. 函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。
|
||||
2. 函数则跟对象无关。
|
||||
3. 方法中的数据则是隐式传递的。
|
||||
4. 方法可以操作类内部的数据。
|
||||
5. 方法跟对象是关联的。如我们在用 strip() 方法是,是不是都是要通过 str 对象调用,比如我们有字符串 s,然后 s.strip() 这样调用。是的,strip()方法属于str对象。
|
||||
|
||||
我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
|
||||
|
||||
在其他语言中,如 Java 中只有方法,C 中只有函数,C++ 则取决于是否在类中。
|
||||
|
||||
# 双下方法
|
||||
|
||||
## `__init__`
|
||||
|
||||
用于初始化类的实例,接收参数并设置实例属性。
|
||||
|
||||
```python
|
||||
class Person:
|
||||
def __init__(self, name, age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
```
|
||||
|
||||
## `__len__`
|
||||
|
||||
```python
|
||||
class B:
|
||||
def __len__(self):
|
||||
return 666
|
||||
|
||||
b = B()
|
||||
print(len(b)) # len一个对象就会触发 __len__方法。
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__dict__)
|
||||
a = A()
|
||||
print(len(a))
|
||||
```
|
||||
|
||||
## `__hash__`
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self.a)+str(self.b))
|
||||
a = A()
|
||||
print(hash(a))
|
||||
```
|
||||
|
||||
## `__str__`
|
||||
|
||||
如果一个类中定义了 `__str__` 方法,那么在 `print(obj)` 时,默认输出该方法的返回值。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __str__(self):
|
||||
return '陈松'
|
||||
a = A()
|
||||
print(a)
|
||||
print('%s' % a)
|
||||
```
|
||||
|
||||
## `__repr__`
|
||||
|
||||
如果一个类中定义了 `__repr__` 方法,那么在` repr(obj)` 时,默认输出该方法的返回值。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return '陈松'
|
||||
a = A()
|
||||
print(repr(a))
|
||||
print('%r'%a)
|
||||
```
|
||||
|
||||
## `__call__`
|
||||
|
||||
通过 ` obj() ` 触发执行。
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
|
||||
def __init__(self):
|
||||
print('__init__')
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
print('__call__')
|
||||
|
||||
|
||||
obj = Foo() # 执行 __init__
|
||||
obj() # 执行 __call__
|
||||
```
|
||||
|
||||
## `__eq__`
|
||||
|
||||
通过 `==` 触发类中的 `__eq__` 方法
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __eq__(self,obj):
|
||||
if self.a == obj.a and self.b == obj.b:
|
||||
return True
|
||||
a = A()
|
||||
b = A()
|
||||
print(a == b)
|
||||
```
|
||||
|
||||
## `__del__`
|
||||
|
||||
析构方法,当对象在内存中被释放时,自动触发执行。
|
||||
|
||||
注:此方法一般无须定义,因为 Python 是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给 Python 解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
|
||||
|
||||
## `__new__`
|
||||
|
||||
在 Python 中,`__new__` 是一个控制对象创建过程的魔术方法,它比 `__init__` 更早执行。
|
||||
|
||||
- 优先级:`__new__` 是对象创建的第一步,负责生成实例;`__init__` 是第二步,负责初始化实例。
|
||||
- 返回值:`__new__` 必须返回实例对象(否则 `__init__` 不会执行),而 `__init__` 无返回值。
|
||||
- 静态方法:`__new__` 隐式作为静态方法存在,第一个参数是类本身 `cls`,而非实例 `self`
|
||||
- 继承链:若未重写 `__new__`,Python 会沿继承链调用父类的 `__new__`,直至 `object.__new__`
|
||||
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print("in new function")
|
||||
return object.__new__(A, *args, **kwargs) # 调用父类的 __new__ 创建实例并返回实例
|
||||
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
print("in init function")
|
||||
|
||||
|
||||
a = A()
|
||||
print(a.x)
|
||||
|
||||
```
|
Reference in New Issue
Block a user