跳转底部

python 面向对象高级编程

#**********使用__slots__限制实例属性**********
class Student(object):
    pass
def set_age(self,age):
    self.age = age
from types import MethodType
s = Student()
s.set_age = MethodType(set_age,s)   #给实例绑定一个方法,只有本实例有这个方法,其他的实例没有
s.set_age(25)
print(s.age)

def set_score(self,score):      #通常情况下,set_score方法是直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现
    self.score = score
Student.set_score = set_score   #给class绑定方法,这样所有由Student创建的实例,都可以使用该方法
s1 = Student()
s.set_score(100)
print(s.score)
# 100
s1.set_score(99)
print(s1.score)
# 99
#为了达到限制的目的,比如,只允许对Student实例添加name和age属性,
# Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
class Student(object):
    __slots__ = ("name","age")      #这样表示由Student创建的实例最多有"name" "age"两个属性
s = Student()
s.name = "perfey"   #绑定属性"name"
s.age = "24"        #绑定属性"age"
s.score = 99    #报错了,AttributeError: 'Student' object has no attribute 'score'

#使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
#除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
class Student(object):
    def __init__(self,name):
        self.name = name
    __slots__ = "name"      #父类只允许name属性 ,如果没有这里的__slot__,后面Student的实例可以通过 s.score = 80 这样的方式来增加属性
class Student_son(Student):
    __slots__ = "age"       #子类这里允许的是 "age" 和 "name"属性,如果没有这里的__slot__,后面的Student_son的实例的属性没有限制

bart = Student_son("bart")
bart.age = 18
print(bart.age)     #18
bart.name = "afly"
print(bart.name)    #afly

 

#**************使用property装饰器检查实例传入参数属性************
class Student(object):
    pass
s1 = Student()
s1.score = 60        #直接使用属性
print(s1.score)


class Student(object):
    def get_score(self):        #通过get_score方法来得到分数这个值
         return self._score
    def set_score(self, value):  #通过set_score方法来检查实例参数,并传参
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value     #在这个位置绑定属性,传递参数
s1 = Student()
s1.set_score(60)    #调用方法
ret = s1.get_score()    #调用方法
print(ret)


class Student(object):

    @property        #通过property装饰器使得可以用类似属性这样的简单方式访问类的变量,这是把一个getter方法变成属性
    def score(self):
        return self._score

    @score.setter   #把一个setter方法变成属性并赋值
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

s1 = Student()
s1.score = 60
print(s1.score)


class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):  #只定义getter方法,不定义setter方法就是一个只读属性
        return 2015 - self._birth

s1 = Student()
s1.birth = 1995
print(s1.age)
#**************************多重继承*************************
class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):  #一般书写习惯是;主线继承的类放在第一个,其他的次要的类以MinIn结尾
    pass
class Student(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):  #通过__str__()方法,返回一个好看的字符串
        return 'Student object (name=%s)' % self.name
    __repr__ = __str__  #直接显示变量(在python自带的shell编辑器中敲变量名会显示变量内容)调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。
                        #解决办法是再定义一个__repr__()。但是通常__str__()和__repr__()代码都是一样的,所以,有个偷懒的写法__repr__ = __str__
s = Student("alex")
print(s)
#Student object (name=alex)



class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化两个计数器a,b

    def __iter__(self):
        return self # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration()
        return self.a # 返回下一个值
for n in Fib():
    print(n)
    

            
            
#*****__getitem__定义迭代器类,可以进行索引************                                                                               
class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
            if a > 100000:  # 退出循环的条件
                raise StopIteration()
        return a
f = Fib()
print(f[0])
for n in Fib():
    print(n)
    
#为了让我们定义的迭代器具有和list一样的可进行切片操作,定义可切片的类 ,这里我们没有对步长和索引为负数进行处理
class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int): # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice): # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L

#*************__getattr__()方法,动态返回一个属性***********
class Student(object):

    def __getattr__(self, attr):
        if attr=='age':
            return lambda: 25
        raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)   # attr 就是动态属性,使用没有定义的属性时,attr保存改属性的名称
    # 当在__getattr__中仍未找到属性时,默认返回None.要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误
s = Student()
ret = s.age()
print(ret)


class Chain(object):
    def __init__(self, path=''):
        self._path = path
    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))  #把实例的参数和未定义的方法作为新的参数传递给Chain类,并根据__str__返回
    def __str__(self):
        return self._path
    __repr__ = __str__


c1 = Chain("/d/s")
c2 = Chain().status.user.timeline.list
c3 = Chain("/d/s").status.user.timeline.list
print(c1)
#/d/s
print(c2)
#/status/user/timeline/list
print(c3)
#/d/s/status/user/timeline/list


class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

s = Student("alex")
s.__call__()    #调用实例方法
#My name is alex
s()         #通过__call__方法,直接对实例本身调用等价于调用__call__方法
#My name is alex.
"""__call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。
如果你把对象看成函数,那么函数本身其实也可以在运行期动态创建出来,因为类的实例都是运行期创建出来的,这么一来,我们就模糊了对象和函数的界限。
那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的类实例
通过callable()函数,我们就可以判断一个对象是否是“可调用”对象"""
print(callable(Student))    #True
print(callable(s))      #True
print(callable(max))      #True
print(callable("abc"))      #False

 

# =============================================
# 网上的分析,挺详细的
# 完全动态调用特性:
# 把一个类的所有属性和方法调用全部动态化处理

# __call__(): 用于实例自身的调用,达到()调用的效果
# 即可以把此类的对象当作函数来使用,相当于重载了括号运算符

# __getattr__(): 当调用不存在的属性时调用此方法来尝试获得属性
class Chain(object):
    def __init__(self, path=''):    # 默认路径参数path为空
        self._path = path

    def __getattr__(self, path):
        print('call __getattr__(%s)' % path)
        return Chain('%s/%s' % (self._path, path))          #注意两个 %s 中间有 /

    def __str__(self):
        return self._path

    def __call__(self, param):
        print('cal __call__(%s)' % param)
        return Chain('%s/%s' % (self._path, param))

    __repr__ = __str__


# /status/user/timeline/list
# Chain().status.user.timeline.list调用分析
# 首先执行Chain()返回一个实例对象C1(path = ''),
# 通过实例对象C1来获取status属性,因为C1中不存在status属性,所以就会调用
# __getattr__()来尝试获取status属性,接着通过__getattr__()方法返回
# 带参数status的实例对象C2(path = '/status'),然后通过实例对象C2来获取user属性,
# C2中不存在user属性,接着调用__getattr__()方法返回带参数user
# 的实例对象C3(path = '/status/user'),然后通过实例对象C3来获取timeline属性,
# 因C3不存在timeline属性,故调用__getattr__()方法返回带参数timeline
# 的实例对象C4(path = '/status/user/timeline'),通过实例对象C4来获取list属性,
# 又因C4中不存在list属性,调用__getattr__()方法返回带参数list
# 的实例对象C5(path = '/status/user/timeline/list'),
# 最后通过调用__str__()方法来打印实例对象C5,即返回/status/user/timeline/list
# 具体参考见下面的测试结果
print(Chain().status.user.timeline.list)
print('--------------------------------------')

# GET /users/:user/repos
# :user替换为实际用户名
# /users/Lollipop/repos
# Chain().users('Lollipop').repos 调用分析
# 首先执行Chain()返回一个实例对象Q1(path = ''),
# 通过实例对象Q1来获取users属性,因为Q1中不存在users属性,
# 所以就会调用__getattr__()方法尝试获取users属性,接着通过
# __getattr__()方法返回带参数users的实例对象Q2(path = '/users'),
# 然后因为通过()直接调用实例对象Q2(实例后边有括号相当于函数调用__call__方法),并带参数'Lollipop',故会调用
# __call__()方法,返回了带参数Lollipop的实例对象Q3(path = '/users/Lollipop'),
# 接着通过实例对象Q3来获取repos属性,又因Q3中不存在repos属性,即会调用
# __getattr__()方法返回带参数repos的实例对象Q4(path = '/users/Lollipop/repos')
# 最后通过调用__str__()方法来打印实例对象Q4,即返回/users/Lollipop/repos
# 具体参考见下面的测试结果
print(Chain().users('Lollipop').repos)

'''
# log analysis
call __getattr__(status)
call __getattr__(user)
call __getattr__(timeline)
call __getattr__(list)
/status/user/timeline/list
--------------------------------------
call __getattr__(users)
cal __call__(Lollipop)
call __getattr__(repos)
/users/ollipop/repos
'''

 

#Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较
from enum import Enum
Month1 = Enum("Month",("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"))    # "Month"是类 ,"Jan"."Feb"....这些是由类创建的实例
for name,member in Month1.__members__.items():
    print(name,"=>",member,",",member.value)  #value属性是自动赋值给成员的int常量,默认从1开始计数
#
# Jan => Month.Jan , 1
# Feb => Month.Feb , 2
# Mar => Month.Mar , 3
# Apr => Month.Apr , 4
# May => Month.May , 5
# Jun => Month.Jun , 6
# Jul => Month.Jul , 7
# Aug => Month.Aug , 8
# Sep => Month.Sep , 9
# Oct => Month.Oct , 10
# Nov => Month.Nov , 11
# Dec => Month.Dec , 12

from enum import Enum, unique

@unique     #@unique装饰器可以帮助我们检查,保证没有重复值
class Weekday(Enum):
    Sun = 0 # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6
print(Weekday.Mon)      #Weekday.Mon
print(Weekday["Tue"])   #Weekday.Tue
print(Weekday(2))       #Weekday.Tue
print(Weekday.Mon.value)    #1
for name,member in Weekday.__members__.items():
    print(name,"=>",member)
# Sun => Weekday.Sun
# Mon => Weekday.Mon
# Tue => Weekday.Tue
# Wed => Weekday.Wed
# Thu => Weekday.Thu
# Fri => Weekday.Fri
# Sat => Weekday.Sat

 

#**********************通过type()函数动态创建类****************
def fn(self,name="world"):
    print("Hello,%s" % name)
Hello = type("Hello",(object,),dict(hello=fn))  # type() 传入的三个参数,1.类的名称,2.继承的父类集合,python支持多重继承,只有一个父类时,注意tuple的单元素写法.3.class的方法名称和函数绑定,这里我们把函数fn绑定到方法名hello上
h = Hello()
h.hello()
#Hello,world

 

##*************************metaclass*******************************
#metaclass可以创建或者修改类,可以把类看做是metaclass创建出来的实例
#使用metaclass的顺序是,先定义metaclass,就可以创建类,最后创建实例,metaclass的类名总是以Metaclass结尾,以便清楚地表示这是一个metaclass
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):   # __new__ 是继承 type的方法,可以创建新的类(或者叫做type的对象),返回类名
        attrs['add'] = lambda self, value: self.append(value)
        # print(ListMetaclass.__new__(cls, name, bases, attrs))     # 相当于返回上面语句去执行 def __new__(cls, name, bases, attrs):这样会一直创建新的类,相当于递归,当创建的超过内存允许的最大值时就会报错
        # print(type.__new__(cls, name, bases, attrs))    # <class '__main__.MyList'>  # 这里的 cls =  <class '__main__.ListMetaclass'> type类型     name =  'MyList' str类型     bases = <class 'tuple'>: (<class 'list'>,) tuple类型  attrs = {dict} {'__module__': '__main__', '__qualname__': 'MyList', 'put': <function MyList.put at 0x00000153008D49D8>} dict类型
        return type.__new__(cls, name, bases, attrs)    #这里是通过type返回的类名作为ListMetaclass  __new__ 方法的返回值,不使用ListMetaclass.__new__(cls, name, bases, attrs)是因为在函数内部使用该函数相当于递归调用,会不断调用

class MyList(list, metaclass=ListMetaclass):    #当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义.__new__()方法接收到的参数依次是:1.当前准备创建的类的对象;2.类的名字 3.类继承的父类集合 4.类的方法集合
    def put(self):
        print("我是对象")
    pass
l1 = MyList()

 

#ORM:object relational mapping 对象-关系映射
#把关系数据库的一行映射为一个对象,也就是一个类对应一个表
#ORM框架所有的类只能动态定义
#定义一个User类来操作对应的数据库表User
class Field(object):#保存数据库表的字段名和字段类型
    def __init__(self,name,column_type):
        self.name=name
        self.column_type=column_type
    def __str__(self):
        return '<%s:%s>'%(self.__class__.__name__,self.name)#输出<对象所属的类名:对象的名字>

class StringField(Field):
    def __init__(self,name):
        super(StringField,self).__init__(name,'varchar(100)')      # 规定StringField的数据类型是varchar(100)

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, 'bigint')

# 上面这三个函数相当于定义了一种新的数据类型,和 int float一样,可以使用StringField() 或者IntegerField()来创造这种数据类型的实例

class ModelMetaclass(type):
    def __new__(cls,name,bases,attrs):#当前metaclass方法准备创建的类的对象,类的名字,类继承的父类集合,类的方法集合.以下的操作都是对新创建的类的操作
        if name=='Model':
            return type.__new__(cls,name,bases,attrs)#封锁对Model的修改,类名是Model就只能返回
        print('Found model:%s'%name)
        mappings=dict()#新建一个字典
        print(attrs.items())
        #dict_items([('__module__', '__main__'), ('__qualname__', 'User'), ('id', <__main__.IntegerField object at 0x000001B5042CE860>), ('name', <__main__.StringField object at 0x000001B5042CE898>), ('email', <__main__.StringField object at 0x000001B5042CE8D0>), ('password', <__main__.StringField object at 0x000001B5042CE908>)])

        for k,v in attrs.items():
            print(k,v)
            #__module__ __main__
            #__qualname__ User
            #id <IntegerField:id>
            #name <StringField:username>
            #email <StringField:email>
            #password <StringField:password>
            if isinstance(v, Field):
                print('Found mapping: %s ==> %s' % (k, v))
        #v是属于Field类的,因此v遇到print会自动调用Field中的方法__str__    attr是无序的字典,因此打印输出的时候也是无序的
                mappings[k] = v
        # 在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__的dict中,
        # 同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
        for k in mappings.keys():
            attrs.pop(k)
        attrs['__mappings__'] = mappings  # 保存属性和列的映射关系,这属于User标的属性
        attrs['__table__'] = name  # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)#属性修改完毕后返回

class Model(dict,metaclass=ModelMetaclass):
    def __init__(self,**kw):
        super(Model,self).__init__(**kw)
    def __getattr__(self,key):#实例.属性的时候自动调用
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute'%s'"%key)
    def __setattr__(self,key,value):
        self[key]=value
    def save(self):
        fields=[]
        params=[]
        args=[]
        for k,v in self.__mappings__.items():
            fields.append(v.name)       #k 是列名,v是列名对应的Field数据,实际上是从id=IntegerField('id')出来的,v.name这里用的是Field的属性name
            params.append('?')
            args.append(getattr(self,k,None))   # 通过getattr方法使用字典找到 列名(id)的值 12345
        sql='insert into %s(%s) values(%s)'%(self.__table__,','.join(fields),','.join(params))
        print('SQL:%s'%sql)
        print('ARGS:%s'%str(args))
class User(Model):
    # 定义类的属性到列的映射
    id=IntegerField('id')#用IntegerField初始化User类的属性,调用setattr自动赋值,和User继承的其他方法作为字典保存到ModelMetaclass中的attrs方法集合中
    name=StringField('username')
    email=StringField('email')
    password=StringField('password')
#创建一个实例
u=User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # 这些是对User类的属性的赋值
# User 继承了Model,Model继承了dict,所以可以把User具有dict的方法
#保存到数据库
u.save()
#创建实例的时候调用Model的方法->调用ModelMetaclass的方法

 

 

 

 

 

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#********通过继承实现接口***********
#声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethod
    def pay(self):pass  # 抽象方法

class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元'%money)

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付了%s元'%money)

class Wechatpay(Payment):
    # def pay(self,money):
    #     print('使用微信支付了%s元'%money)
    def recharge(self):pass

def pay(a,money):
    a.pay(money)    # 如果Wechatpay类中没有pay方法时,会调用父类Payment中的pay方法,但是Payment中的pay是抽象的不能实例化,所以会报错

a = Alipay()
a.pay(100)
pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
q = QQpay()
q.pay(100)
pay(q,100)
w = Wechatpay()
pay(w,100)   # 到用的时候才会报错,不能用抽象的方法实例化一个抽象的类Wechatpay()

 

#******普通方法.类方法和静态方法********
class Foo:

    def __init__(self, name):
        self.name = name

    def ord_func(self):
        """ 定义普通方法,至少有一个self参数 """

        # print self.name
        print('普通方法')

    @classmethod
    def class_func(cls): # cls传入当前方法的类名,与self作用差不多,self传入对象名
        """ 定义类方法,至少有一个cls参数 """
        cls.name = "sylar"
        print('类方法')

    @staticmethod
    def static_func():
        """ 定义静态方法 ,无默认参数"""

        print('静态方法')


# 调用普通方法
f = Foo("alex")
f.ord_func()    # 普通方法

# 调用类方法
Foo.class_func()
# 类方法
print(Foo.name)
# sylar

# 调用静态方法
Foo.static_func()
# 静态方法

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height
    @property
    def bmi(self):
        return self.weight / (self.height**2)

p1=People('egon',75,1.85)
print(p1.bmi)   # 使用了@property后可以把 bmi方法当做一个属性 bmi = self.weight / (self.height**2) 不必再使用 bmi() 执行函数
# print(p1.bmi()) # 如果没有@property 调用 bmi方法必须加括号 p1.bmi() 打印返回值


class Goods(object):

    def __init__(self):
        # 原价
        self.original_price = 100
        # 折扣
        self.discount = 0.8

    @property
    def price(self):
        # 实际价格 = 原价 * 折扣
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self, value):
        del self.original_price

obj = Goods()
print(obj.price)         # 获取商品价格
obj.price = 200   # 修改商品原价
print(obj.price)
del obj.price     # 删除商品原价
print(obj.price)    # 这时会报错,因为已经删除了original_price 属性    price() missing 1 required positional argument: 'value'

import sys


def s1():
    print(s1)


def s2():
    print(s2)


this_module = sys.modules[__name__]

ret1 = hasattr(this_module, 's1')
print(ret1)
ret2 = getattr(this_module, 's2')
print(ret2)




class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)



object将__new__()方法定义为静态方法,并且至少需要传递一个参数cls,\
cls表示需要实例化的类,此参数在实例化时由Python解释器自动提供

class Demo(object):
    def __init__(self):
        print( '__init__() called...')

    def __new__(cls, *args, **kwargs):
        print( '__new__() - {cls}'.format(cls=cls))
        return object.__new__(cls, *args, **kwargs)


if __name__ == '__main__':
    de = Demo()
print(de)   # <__main__.Demo object at 0x000002252EFA8B70>
print(Demo) # <class '__main__.Demo'>
# __new__() - <class '__main__.Demo'>
# __init__() called...
"""
发现实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法
__new__()必须要有返回值,返回实例化出来的实例,\
需要注意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回。
__init__()有一个参数self,该self参数就是__new__()返回的实例,\
__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。
若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。
我们可以将类比作制造商,__new__()方法就是前期的原材料购买环节,\
__init__()方法就是在有原材料的基础上,加工,初始化商品环节。
"""


class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance
        # return object.__new__(cls,*args,**kwargs)
s = Singleton()     
print(s._instance)  # <__main__.Singleton object at 0x000001C737868978>
print(s)            # <__main__.Singleton object at 0x000001C737868978>
print(s.__dict__)   # {}
print(Singleton.__dict__)   #{'__module__': '__main__', '__new__': <staticmethod object at 0x000001C737868940>, \
# '__dict__': <attribute '__dict__' of 'Singleton' objects>, '__weakref__': <attribute '__weakref__' of 'Singleton' objects>,\
#  '__doc__': None, '_instance': <__main__.Singleton object at 0x000001C737868978>}

 

class A:
    def __init__(self):
        self.x = 1
    def __new__(cls, *args, **kwargs):
        print(cls)
        print("in new function")
        # return super().__new__(cls)
        return object.__new__(cls)
a1 = A()    # 在实例化的时候首先找类的__new__方法(没有时往上找object里有)\
# 执行__new__方法,如果__new__方法中没有创建对象空间则必须再执行父类中能创建\
# 对象空间的__new__方法(object的new方法就是专门创建对象的方法),索引通常在类的\
# __new__方法中返回 object.__new__(cls) 的值

 

posted on 2018-06-20 20:04  afly666  阅读(194)  评论(0编辑  收藏  举报

导航

回到顶部