1、不定长位置参数、不定长关键字参数
(tips:这个自己经常忘,记录下来提醒自己)
*args:在定义函数时,不知道要定义多少个 位置参数 ,所以我们可以用*args 来接收参数
**kwargs: 同理在定义函数时,不知道要定义多少个关键字参数,所以我们用 **kwargs来接收函数
def Test(*c, **d):
print(f"c:{
c}")
print(f"d:{
d}")
Test(1, 2, 3, a=1, b=2, e=3)
结果如下:
c:(1, 2, 3)
d:{
'a': 1, 'b': 2, 'e': 3}
2、__getattr__方法
2.1、当没有自定义 __getattr__时
1、getattr((obj,xxx) xxx在类中不存在,报错
2、obj.xxx xxx在类中不存在 报错
2.2 当自定义 __getattr__时
总结,对象中有的成员,不会触发 getattr 方法,对象中无的成员会触发__getattr__
1、getattr(obj,xxx) xxx在类中不存在,不会报错,走__getattr__方法
2、obj.xxx xxx在类中不存在,不会报错,走 __getattr__方法
3、 getattribute 方法
# __getattribute__ 方法
1、当在我们类的时候,自定义__getattribute__ 方法时,通过obj.xxx调用xxx属性时,
无论,xxx是否存在,都会走 __getattribute__ 方法
2、默认情况下,我们创建类时,当不自定义__getattribute__ 方法时,最底层代码也会用
__getattribute__ 方法,但是别人的使用策略是有属性值返回原属性值,没有属性值则报错
3、下面这种情况相当于没有自定义__getattribute__ ,使用的是底层的__getattribute__
如果我们有定制需求,我们可以自定义 __getattribute__方法
class Request(object):
def __init__(self, req, xx):
self._request = req
self.xx = xx
def __getattribute__(self, item):
print("执行__getattribute__", item)
return super().__getattribute__(item)
4、元类
- 对象是通过类实例化出来的。
class Foo(object):
pass
# 第1步:调用Foo的__new__方法创建空对象。
# 第2步:调用Foo的__init__方法对对象进行初始化。
obj = Foo()
- 类是谁创建的?是由type创建出来的(默认)。
class Foo(object):
v1 = 123
def func(self):
return 666
Foo = type("Foo",(object,),{
"v1":123, "func":lambda self:666 })
- 定义类时加入metaclass指定当前类的创造者。
# 由type创建Foo类型
class Foo(object):
pass
# 由`东西` 创建Foo类型
class Foo(object,metaclass=东西):
pass
4.1 指定元类来创建类
代码分析
class Field:
def __new__(cls, *args, **kwargs):
"""
When a field is instantiated, we store the arguments that were used,
so that we can present a helpful representation of the object.
"""
instance = super().__new__(cls)
instance._args = args
instance._kwargs = kwargs
return instance
field1 = Field() 这个时候就会调用__new__方法,先创建一个实例对象
Field 类默认继承 object类
super().__new__() 是指调用object方法
super().__new__(cls) cls是指Field类本身
把cls 传入object__new__方法中,返回一个Field实例对象
其实,在调用__new__方法时,Field本身早已经创建好了,所以创建对象时,cls指代Field自身传到参数中去
class MyType(type):
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs)
print("创建类:", new_cls)
return new_cls
myType继承的是Type 所以 new_cls = super.__new__(cls,*args,**kwargs)
返回的是 类对象
Field 继承的是 Object 返回的是 调用__new__方法时 返回的是实例对象
object的是所有的类基类,所有创建的类默认继承object公共基础功能
type是元类,type的功能是创建类,所有类的创建默认是type创建
1、自定义的元类必须要继承type
2、其实创建类就是元类的实例化过程,被创建的类是元类实例化对象,所以先走元类的__new__
方法,再走__init__ 方法
3、被创建的类,不会继承元类的其他的方法,只是被创建和初始化,其实初始化也是默认的继承object的,可以忽略不计,所以被创建的类不会继承元类的方法
4、一般自定义元类重写 __new__ 方法,主要是对被创建的类属性 进行修改,之所以自定义元类
是如果,很多类的创建之前对自己的属性都需要相同的操作,统一的用元类创建更方便
5、对象加()是调用元类的__call__ 方法,所以Foo是mytype的对象,因为Foo是mytype的实例化。Foo()是创建 Foo的对象,会触发其mytype的__call__方法。
6、obj1 = Foo() 同样的,obj1() 会触发Foo 的__call__方法
7、我们想实例化时,修改一些东西,可以重新写__call__方法
8、在创建类的时候,类里面定义的 类属性 和 方法是要比 类先创造的,因为如果我们用type()
这种方式创建类的时候,类属性和方法是要当作参数传给type的,所以 创建类的时候 类属性
和方法是先有的,然后再创建类
创建Foo其实就是type的实例化
Foo = type("Foo",(object,),{
"v1":123, "func":lambda self:666 })
创建Foo1 其实 就是mytype的实例化
Foo1 = mytype(...)
class MyType(type):
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs)
print("创建类:", new_cls)
return new_cls
將 *args 和 **kwargs 改为具体的参数 如下
class MyType(type):
def __new__(cls,name,bases,attrs):
# 通常创建新类对象时 传入的参数是
# name 名称,
# bases 父类
# attrs 类属性
del attrs[v1] # 删除v1
new_cls = super().__new__(cls, name,bases,attrs)
print("创建类:", new_cls)
return new_cls
class Foo(metaclass=MyType):
v1 = 123
v2 = 156
class MyType(type):
def __init__(self, *args, **kwargs):
print("第2步:初始化类成员:", args, **kwargs)
super().__init__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs