查看对象的所有属性和方法 — dir
在 Python 中一切皆对象,我们可以通过内置函数 dir() 来获取对象的所有属性和方法。
>>> class Student:
... pass
...
>>> dir(Student)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>>
注意:以双下划线开头和结尾(__方法名__)的格式的方法是 Python 针对对象提供的内置属性或方法。
类中四个常用的内置方法:
__new__ | 创建对象时,被自动调用。 |
__init__ | 对象被初始化时,自动调用。 |
__del__ | 删除对象或对象被从内存中销毁前,自动调用。 |
__str__ | print 打印实例对象时自动调用。返回对象的描述信息。 |
这几个内置函数都不需要手动调用。
__new__() 创建对象时调用
在使用 类名() 创建实例对象时,python 解释器会首先自动调用 __new__() 方法为对象在内存中分配内存空间,然后返回对象的引用。Python 解释器获得对象的引用后,将这个引用作为第一个参数传给 __init__() 方法。
__new__ 是由 object 类提供的内置静态方法,所以在调用的时候要主动给 cls 传递参数。
注意:
class Person(object):
def __new__(cls, *args, **kwargs): # 创建对象时,__new__被自动调用
print('__new__被调用执行了,cls的id值为{0}'.format(id(cls)))
# 为对象分配内存空间
obj = super().__new__(cls) # Person传给了object类,在object中创建一个对象obj
print('创建的对象的id值为{0}'.format(id(obj)))
# 返回对象的引用
return obj # 返回给self
def __init__(self, name, age): # 为创建的对象赋值
print('__init__被调用了,self 的id值为{0}'.format(id(self)))
self.name = name
self.age = age
print('object这个类对象的id为{0}'.format(id(object)))
print('Person这个类对象的id为{0}'.format(id(Person)))
print('-------------------------------------------------------------')
p1 = Person('张三', 20) # 先执行赋值号右侧的代码,自动调用__new__,把Person传给了cls __init__初始化方法执行完成后,再把self赋值给p1
print('-------------------------------------------------------------')
print('p1这个Person的实例对象的id为{0}'.format(id(p1)))
单例设计模式
单例设计模式:类创建的对象,在系统中只有唯一一个实例,也就是每次执行 类名(),返回的对象地址都相同。例如音乐播放器,每次只能播放一首歌。
重写 __new__ 方法是为了对分配空间的方法进行改造,使得我们在使用 类名() 创建对象的时候,无论执行多少次,在内存中只会创建出一个实例对象,以达到单例设计模式的目的。
单例设计模式代码演示:
我们需要达到的目的是:无论使用 类名() 创建多少次,得到的永远是创建的第一个实例对象。所以我们需要这样做:
首先我们需要一个用于记录单例对象的引用的类属性,且初始值为 None;
然后在 __new__() 方法中判断类属性,如果类属性为 None,说明该类在内存中还没有创建实例对象,那么就需要调用父类的 __new__() 方法来分配内存空间;
如果类属性不为 None,说明内存中以及有一个对象了,那么不再调用父类的方法来分配内存空间,直接返回类属性中记录的对象的引用。
class MusicPlayer(object):
# 类属性:记录单例对象的引用
instance = None
def __new__(cls, *args, **kwargs):
# 如果instance=None,说明内存中还没有实例对象,那么就需要调用父类的方法分配内存空间
if cls.instance is None:
cls.instance = super().__new__(cls) # 存储父类方法返回的对象的引用
return cls.instance
def __init__(self, name):
self.name = name
music1 = MusicPlayer('白龙马')
print(music1, music1.name)
music2 = MusicPlayer('拔萝卜')
print(music2, music2.name)
music3 = MusicPlayer('三字经')
print(music3, music3.name)
从上面的结果可以看出:使用 类名() 创建对象时,虽然得到的是第一个对象的引用,但是初始化方法每创建一个实例对象都会被执行。
解决这个问题很简单,设置一个类属性 init_flag 用来判断初始化方法是否被执行过,初始值为 False。
class MusicPlayer(object):
# 类属性:记录单例对象的引用
instance = None
init_flag = False # 用来标记初始化方法是否被执行过
def __new__(cls, *args, **kwargs):
# 如果instance=None,说明内存中还没有实例对象,那么就需要调用父类的方法分配内存空间
if cls.instance is None:
cls.instance = super().__new__(cls) # 存储父类方法返回的对象的引用
return cls.instance
def __init__(self, name):
# 判断初始化方法是否被执行过
if MusicPlayer.init_flag is False:
# 初始化实例属性
self.name = name
# 更改初始化标志
MusicPlayer.init_flag = True
music1 = MusicPlayer('白龙马')
print(music1, music1.name)
music2 = MusicPlayer('拔萝卜')
print(music2, music2.name)
music3 = MusicPlayer('三字经')
print(music3, music3.name)
__init__() 初始化方法(构造方法)
在创建实例对象时,python 解释器会自动为对象在内存中分配内存空间,并通过初始化方法( __init__(),前后都是两个下划线)为对象的属性设置初始值。
也就是创建实例对象时,为对象分配完内存空间后,自动调用 __init__() 方法。
__init__ () 是对象的内置方法,专门用于定义一个类中有哪些属性。它的第一个参数同样是 self,表示实例对象的引用。
只要创建实例对象,就会自动调用 __init__() 方法,我们通过重写这个方法来完成初始化:
class Person:
def __init__(self):
print('我是初始化方法。')
# 使用类名()创建对象的时候,会自动调用__init__()初始化方法。
Tom = Person()
1)如果想要这个类创建的对象默认都拥有这个属性值,可以通过 self.属性名 = 初始化值 来定义属性:
class Person:
def __init__(self):
# print('我是初始化方法。')
self.name = 'Tom' # name的初始值固定了
Tom = Person()
print(Tom.name) # Tom
a = Person()
print(a.name) # Tom
可以看到:使用 Person 类创建出来的对象都有一个实例属性为 name,且属性值都是 ‘Tom’。
我们可以看到,利用这种方法初始化属性,对象的属性值就固定了,要想对象的属性值灵活变化,可以通过参数传递来完成。
注意:
在定义属性时,如果我们不知道该给某一个属性设置什么初始值,可以设置为 None(表示什么都没有)。
None 表示一个空对象,没有方法和属性,是一个特殊的常量。
class Demo:
def __init__(self):
self.test = None
d = Demo()
print(d.test) # None
2)使用参数来设置属性的初始值,让每个对象都自己的属性值:(位置参数)
我们对 __init__() 进行重写,将希望设置的属性值,定义为 __init__() 的参数。然后在方法内部通过 self.属性 = 形参 来接收外部传递的参数。
这样就可以在创建对象时,以参数的形式将对象特有的属性传递到方法内部(语法格式:类名(属性1, 属性2…)),使得创建出来的对象更加灵活多样。
class Person:
def __init__(self, name, age):
self.name = name # self.name是实例属性,将局部变量name的值赋给实例属性,习惯上是实例属性名和局部变量名设置成一样的
self.age = age
Tom = Person('Tom', 21)
Alice = Person('Alice', 19)
print(f'{Tom.name}今年{Tom.age}岁。') # Tom今年21岁。
print(f'{Alice.name}今年{Alice.age}岁。') # Alice今年19岁。
使用 Person 创建对象时,每一个参数都必须要传参(除了 self 参数),否则程序会报错。
class Person:
def __init__(self, name, age):
self.name = name # self.name是实例属性,将局部变量name的值赋给实例属性,习惯上是实例属性名和局部变量名设置成一样的
self.age = age
Bob = Person()
先前学函数的时候,为避免忘记传值而导致的错误,我们给函数设置默认值来避免这个错误。
3)默认值参数
我们可以给形参设置默认值,这样创建对象的时候无论传不传参,都不会报错。
class Person:
def __init__(self, name='张三', age=999):
self.name = name
self.age = age
Tom = Person('Tom', 21)
print(f'{Tom.name}今年{Tom.age}岁。') # Tom今年21岁。
# 不传参的话,程序不会报错,使用默认值
Alice = Person()
print(f'{Alice.name}今年{Alice.age}岁。') # 张三今年999岁。
根据结果可以看到,给形参设置默认值后,在使用 类名() 创建对象时,即使不传参,程序也不会报错,它会使用形参的默认值。
1 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
2 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报。
3 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
暂无评论内容