Python的面向对象--魔法方法详解

一、面向对象介绍

 

class Student:
    def __init__(self, name, age):
        # 公共成员变量
        self.name = name
        # 私有成员变量
        self.__age = age
 
    def info(self):
        print('姓名:' + self.name)
        print('年龄:' + str(self.__age))
 
# Student类包括了两个成员变量(name和age)和一个成员函数(info())。
# 其中,name是公共成员变量,可以被外部访问;而age被定义成私有成员变量,只能在类内部访问。
# 通过封装,可以保证数据不被外部随意修改,保证代码的安全性。
class 类名:
    类属性 = 值
    def __init__(self, 参数):
        self.属性1 = 参数1
        self.属性2 = 参数2
        self.__私有属性 = 0(或者None)
    def 方法1(self, 参数):
        # 方法代码
    def 方法2(self, 参数):
        # 方法代码

 

1、类属性和实例属性

 实例属性:在__init__方法中定义的,对象级别的

类属性:在类中,方法外定义的属性,类级别的。类名.属性名或者实例对象名.属性名访问

                类属性通过类.属性改,如果对象.类属性 = 属性值:为该对象增加一个对象属性而已。

私有属性:定义在_init__方法中,以__两个下划线开头的属性,对外不开放访问。可以通过get/set方法接口实现外访问:

    def get_money(self):
        return self.__money

    def set_money(self, money):
        self.__money = money

 

2、实例方法

实例方法入参第一个值,默认self指代当前调用的对象,不建议使用其它关键字代替,实例方法只能由实例对象进行调用,个人理解由于需要明确是哪个对象在使用当前方法所以实例方法与静态方法和类方法不同对调用者要求严格

class testFunction():

    classAttribute ='monica'
    def __init__(self,example_name):
        self.example_name = example_name

    def testExample(self):
        print('实例方法')
        print('调用实例属性:',self.example_name)
        print('调用类属性:',testFunction.classAttribute)
if __name__ == '__main__':
    tf = testFunction('example_monica')
    #实例对象调用方法
    tf.testExample()
    #类对象调用实例方法
    testFunction.testExample('test')

 

3、类方法

 类方法由类调用,采用@classmethod装饰,至少传入一个cls(代指类本身,类似self)参数。执行类方法时,自动将调用该方法的类赋值给cls。建议只使用类名.类方法的调用方式。(虽然也可以使用实例名.类方法的方式调用)

 
class gg:
    url = 0
    stat = 0
    # 此处为何要定义变量url和stat
    # 原因1:类gg需要2个属性,url与stat
    # 原因2: 使用@classmethod, data=cls(url,stat),这个是类的实例化,实例需要属性来接收2个变量
    def __init__(self,url=0,stat=0):
        self.url=url
        self.stat = stat
 
    @classmethod
    # 装饰器,立马执行下面的函数
    def split(cls,info):
        # 这个函数,接收2个参数
        # 默认的cls就是这个类的init函数(构造器)
        # info 就是外面出来的
        url,stat=map(str,info.split("-"))
        # 这里转换成类格式化的结构
        data=cls(url,stat)
        # 这里就直接返回了函数结果,实际上就是经过处理后的实例
        return data
    def outer(self):
        print(self.url)
        print(self.stat)
 
if __name__ == '__main__':
    r=gg.split('langzi-200')
    a=gg("langzi",200)
    a.outer()
    r.outer()

gg.split('langzi-200'),一个先经过处理(有一定的逻辑),再实例化,

gg("langzi",200) 直接实例化

其中map函数:

info = 'langzi-200'
“”“
['langzi', '200']
”“”
print(info.split("-"))

a,b = map(str,info.split("-"))
“”“
<class 'str'> 200
”“”
print(type(a),b)

 4、静态方法

静态方法使用的关键字是@staticmethod,通过在方法前追加此装饰器该方法就属于一个静态方法,静态方法个人理解为它既不依赖实例对象也不依赖于类,它只是需要一个载体即可,所以无论是通过类对象直接调用还是实例对象进行调用都是可以的,需要注意的是在静态方法中无法使用实例属性和方法。所以在日常过程中如果有一个方法实现的功能比较独立的时候就可以考虑使用静态方法实现
 

class testFunction():

    classAttribute ='monica'
    def __init__(self,example_name):
        self.example_name = example_name
    @staticmethod
    def testStatic():
        print('静态方法使用')
        print('调用类属性',testFunction.classAttribute)
        print('调用实例属性',self.example_name)
if __name__ == '__main__':
    tf = testFunction('example_monica')
    #实例对象调用静态方法
    tf.testStatic()
    #类对象调用静态方法
    testFunction.testStatic()

 

二、魔法方法

所谓魔法函数(Magic Methods),是Python的一种高级语法,允许你在类中自定义函数,并绑定到类的特殊方法中。比如在类A中自定义__str__()函数,则在调用str(A())或者print(a实例对象)时,会自动调用__str__()函数,并返回相应的结果。

1、操作符魔法方法 

+	object.__add__(self, other)
-	object.__sub__(self, other)
*	object.__mul__(self, other)
//	object.__floordiv__(self, other)
/	object.__div__(self, other)
%	object.__mod__(self, other)
**	object.__pow__(self, other[, modulo])
<<	object.__lshift__(self, other)
>>	object.__rshift__(self, other)
&	object.__and__(self, other)
^	object.__xor__(self, other)
|	object.__or__(self, other)

扩展二元操作符:

+=	object.__iadd__(self, other)
-=	object.__isub__(self, other)
*=	object.__imul__(self, other)
/=	object.__idiv__(self, other)
//=	object.__ifloordiv__(self, other)
%=	object.__imod__(self, other)
**=	object.__ipow__(self, other[, modulo])
<<=	object.__ilshift__(self, other)
>>=	object.__irshift__(self, other)
&=	object.__iand__(self, other)
^=	object.__ixor__(self, other)
|=	object.__ior__(self, other)

一元操作符:

-	object.__neg__(self)
+	object.__pos__(self)
abs()	object.__abs__(self)
~	object.__invert__(self)
complex()	object.__complex__(self)
int()	object.__int__(self)
long()	object.__long__(self)
float()	object.__float__(self)
oct()	object.__oct__(self)
hex()	object.__hex__(self)
round()	object.__round__(self, n)
floor()	object__floor__(self)
ceil()	object.__ceil__(self)
trunc()	object.__trunc__(self)

 

2、比较方法

-	object.__neg__(self)
+	object.__pos__(self)
abs()	object.__abs__(self)
~	object.__invert__(self)
complex()	object.__complex__(self)
int()	object.__int__(self)
long()	object.__long__(self)
float()	object.__float__(self)
oct()	object.__oct__(self)
hex()	object.__hex__(self)
round()	object.__round__(self, n)
floor()	object__floor__(self)
ceil()	object.__ceil__(self)
trunc()	object.__trunc__(self)

 

3、类的表示、输出

str()	object.__str__(self) 
repr()	object.__repr__(self)
len()	object.__len__(self)
hash()	object.__hash__(self) 
bool()	object.__nonzero__(self) 
dir()	object.__dir__(self)
sys.getsizeof()	object.__sizeof__(self)

 

4、类容器

len()	object.__len__(self)
self[key]	object.__getitem__(self, key)
self[key] = value	object.__setitem__(self, key, value)
del[key] object.__delitem__(self, key)
iter()	object.__iter__(self)
reversed()	object.__reversed__(self)
in操作	object.__contains__(self, item)
字典key不存在时	object.__missing__(self, key)

 

 三、常用魔术方法

1、__init__

它是一个类初始化器。 每当创建一个类的实例时,都会自动调用其 __init__()方法,也称为构造方法。 例如:

class GetTest(object):
    def __init__(self, name):
        print('Greetings!! {0}'.format(name))
        
    def another_method(self):
        print('I am another method which is not automatically called')

它的主要作用是初始化实例的属性,在实例被创建后,你可以通过这些属性对实例进行操作。每个类可以定义多个不同的 __init__ 方法,但通常情况下,在类中只有一个,在这种情况下,在创建类的实例时,必须提供所需的参数。

self 参数是必须的,它代表创建的对象本身,在方法内部可以通过 self 来引用对象的属性和方法。除了 self 以外的其他参数是可选的,根据实际需求定义。

初始化语句就是在创建对象时需要执行的语句,可以是赋值语句、函数调用等。通过 __init__ 方法,可以在创建对象时为对象的属性设置初始值,从而使得代码更加简洁,也方便维护。
 

(1)、__init__和super的用法

__init__ 方法是 Python 中类的构造方法,在创建类的实例时被调用,用于初始化类的实例的属性。

super 是 Python 的内置函数,它可以在继承关系中访问父类的属性。在父类和子类中都有定义了 __init__ 方法的情况下,子类的 __init__ 方法可以通过调用 super 函数来继承父类的 __init__ 方法,并在其中添加额外的初始化代码。
 

class ParentClass:
    def __init__(self, value1, value2):
        self.value1 = value1
        self.value2 = value2
 
class ChildClass(ParentClass):
    def __init__(self, value1, value2, value3):
        super().__init__(value1, value2)
        self.value3 = value3

在这个例子中,ChildClass 继承了 ParentClass 的所有属性,并且在其中添加了额外的 value3 属性。调用 super().__init__(value1, value2) 可以访问父类的 __init__ 方法,并将其初始化为 value1 和 value2。
 

 (2)、__init__方法的注意事项

  • __init__方法在对象创建时自动调用,无需手动调用。
  • __init__方法可以接收任意数量的参数,但必须遵循特定的参数签名。
  • 在__init__方法中,必须给对象的每一个属性赋值,否则该对象将不完整,不能正常工作。
  • 可以在__init__方法中调用其他方法,但请注意不要在初始化的过程中产生太多的计算,因为这可能会影响程序的性能。
  • 一个类可以没有__init__方法,在这种情况下,程序将以默认方式创建该类的对象。

2、__getitem__

在类中实现 __getitem__ 允许其实例使用[](索引器)运算符。类对象可以像字典对象那样根据key取值(dict['key']),如类对象Object['key']。系统会自动调用__getitem__方法。

形式一: __getitem__(self, index) 一般用来迭代序列(常见序列如:列表、元组、字符串),或者求序列中的索引为 index 处的值。
形式二: __getitem__(self, key) 或者__getitem__(self, item)一般用来迭代映射(常见映射如:字典),或者求映射中的键为 key 出的值。
该方法返回与指定索引(针对序列)或键(针对映射)相关联的值,使用 对象[index] 或者 对象[key] 将自动调用该方法。

如果在类中定义了__getitem__()方法,那么它的实例对象(假设为P)就可以这样P[index]取值或者这样P[key]取值。当实例对象做P[index/key]运算时,就会调用类中的__getitem__()方法。


# -*- coding:utf-8 -*-
class DataTest:
    def __init__(self,id,address):
        self.id=id
        self.address=address
        self.d={self.id:1,
                self.address:"192.168.1.1"
                }
        
    def __getitem__(self,key):
        return "hello"
    
 
data=DataTest(1,"192.168.2.11")
print data[2]	# 会自动调用 __getitem__方法
#输出 hello
class Tag:
    def __init__(self):
        self.change={'python' : 'This is python',
                     'java' : 'This is java'
                    }
 
    def __getitem__(self, item):
        print('这个方法被调用')
        return self.change[item]
 
a=Tag()
print(a['python'])
print(a['java'])
class Animal:
    def __init__(self, animal_list):
        self.animals_name = animal_list
        self.other = 'hello, world'
 
    def __getitem__(self, index):
        return self.animals_name[index]
 
animals = Animal(["dog","cat","fish"])
for animal in animals:
    print(animal)
结果:
dog
cat
fish


 

3、__call_ 

__call__()方法可以让类的实例具有类似于函数的行为,这进一步模糊了函数和对象之间的概念。

  • 触发时机:把对象当作函数调用的时候自动触发
  • 功能:模拟函数化操作
  • 参数:参数不固定,至少一个self参数
  • 返回值:看需求

其使用方式为:对象后面加括号,触发执行。即:对象() 或者 类()()

class A(object):
    def __call__(self, *args, **kwargs):
        print('call....')


a = A()
a()  # 自动调用__call__()

4、__slots__ 魔法属性

Python是一门动态语言,这使得我们可以在程序运行的时候给对象绑定新的属性或方法,这就是动态语言的灵活性。

__slots__是python类的魔法属性,可接收一个iterable对象作为属性。定义后,该类实例只能创建__slots__中声明的属性,否则报错。

class Test(object):
    __slots__ = ['a']

if __name__ == '__main__':
    t = Test()
    t.a = 1
    Test.c = 3  # 类属性仍然可以自由添加
    print(t.c)  # 输出:3
    t.b = 2  # AttributeError: 'Test' object has no attribute 'b'

从上面的例子能看出__slots__的具体功能,它的作用就是用来约束类实例的属性,不允许类实例调用方向实例随意添加属性。

限制只是针对实例类本身并不会被限制。怎么理解能?就是我们仍然可以通过类去添加属性或方法

5、__str__ 

__str__()方法可以改变对象的字符串显示。在打印某个对象的时候,会调用这个对象的__str__方法,打印这个方法的返回值。

  • 触发时机:使用print(对象)str(对象)时触发。
class Cat:
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex

    def __str__(self):
        return f"我是一只可爱的小{self.sex}猫咪,我的名字是{self.name}"


>>> cat = Cat("小白", "公")
>>> print(cat)
我是一只可爱的小公猫咪,我的名字是小白

6、__repr__

__repr__()方法可以改变对象的字符串显示。__repr__魔术方法是用来表述某个对象在内存中的展示形式。如果在终端直接输入一个对象,然后按回车,那么将会执行这个对象的__repr__方法。

  • 此方法是__str__()的“备胎”,如果找不到__str__()就会找__repr__()方法。
  • %r默认调用的是__repr__()方法,%s调用__str__()方法
  • repr()方法默认调用__repr__()方法

 

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

    def __str__(self):
        msg = 'name:{},age:{}'.format(self.name, self.age)
        return msg

    def __repr__(self):
        msg = 'name--->{},age--->{}'.format(self.name, self.age)
        return msg


>>> a = A('za', 34)

>>> print('%s' % a) 
name:za, age:34
>>> print('%r' % a)  # 用 %r,默认调用__repr__()方法
name-->za, age-->34
>>> print(a)  # 有__str__()方法就会调用__str__()方法,没有就调用__repr__()方法
name:za, age:34
>>> print(repr(a))  # repr()方法默认调用__repr__()方法
name-->za, age-->34

 

7、__new__ 

__new__()是实例化魔术方法。创建对象时,先触发__new__才会触发__init__

  • 触发时机: 在实例化对时触发
  • 参数:至少一个cls 接收当前类
  • 返回值:必须返回一个对象实例
  • 作用:实例化对象

注意:实例化对象是Object类底层实现,其他类继承了Object__new__才能够实现实例化对象。

执行时机:先触发__new__才会触发__init__:

class Person(object):
    def __init__(self):
        print('__init__(): 我也被调用啦~')

    def __new__(cls, *args, **kwargs):  # 重写后,不再创建对象
        print('__new__(): 哈哈我被调用啦~')


>>> per = Person()
__new__(): 哈哈我被调用啦~
>>> print(per)
None

None说明没有创建对象,因为我们重写了__new__方法,__new__方法不再具有创建对象的功能,只有打印的功能。

调用父类的__new__方法,创建当前对象:

class Person(object):
    def __init__(self):
        print('__init__(): 我也被调用啦~')

    def __new__(cls, *args, **kwargs): 
        print('__new__(): 哈哈我被调用啦~')
        ret = super().__new__(cls)  # 调用父类object的__new__方法创建对象
        return ret


>>> per = Person()
__new__(): 哈哈我被调用啦~
__init__(): 我也被调用啦~
>>> print(per)
<__main__.Person object at 0x0000020FA3892848>

 

8、__eq__ 

说到__eq__()魔法方法,就必须提到Python中的is==。先来看看这两者的区别:

  • is 比较两个对象的 id值(内存地址)是否相等,是否指向同一个内存地址;
  • == 比较的是两个对象的内容是否相等,即内存地址可以不一样,内容一样就可以了。

==在比较类时,会默认调用object.__eq__方法,默认比较两个对象的地址(id)。

>>> list1 = [1, 2, 3]
>>> list2 = [1, 2, 3]

>>> print(id(list1)) 
1759352803720
>>> print(id(list2))
1759352804232

>>> print(list1 == list2)  
True
>>> print(list1 is list2)  
False
class Cat:
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex


>>> c1 = Cat('小白', 2)
>>> c2 = Cat('小白', 2)
>>> print(c1.__dict__)  
{'name': '小白', 'sex': 2}
>>> print(c2.__dict__) 
{'name': '小白', 'sex': 2}

>>> print(c1 == c2)  # ==比较时默认调用object.__eq__方法,默认比较两个对象的地址
False
>>> print(c1 is c2) 
False

c1==c2,会调用父类object的__eq__方法,默认比较地址。我们需要重写__eq__方法来自定义比较规则:

class Cat:
    def __init__(self, name, sex):
        self.name = name
        self.sex = sex

    def __eq__(self, other):
        return self.__dict__ == other.__dict__


>>> c1 = Cat('小白', 2)
>>> c2 = Cat('小白', 2)
>>> print(c1.__dict__)  
{'name': '小白', 'sex': 2}
>>> print(c2.__dict__) 
{'name': '小白', 'sex': 2}
>>> print(c1 == c2)  # ==比较时调用重写的__eq__方法,相等。
True
>>> print(c1 is c2) 
False

自定义对象添加到集合中,我们一般认为两个对象的属性值相同就是同一个对象。因此需要我们手动复写__eq__方法和__hash__方法。

class People(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __eq__(self, other):
        return self.__dict__ == other.__dict__
    def __hash__(self):
        return hash(self.name) + hash(self.age)
    
    
>>> person1 = People('zz', 23)
>>> person2 = People('zz', 23)
>>> set1 = {person1}
>>> set1.add(person2)
>>> print(set1)
{<__main__.People object at 0x00000261C7A8C7C8>}

 

9、__add__ 

__add____radd__都是做加法,只是加法的顺序不一样,会调用不同的魔法函数。

  • 触发时机:使用对象进行运算相加的时候自动触发
  • 功能:对象运算
  • 参数:两个对象参数
  • 返回值:运算后的值

对象在加号的左侧时,自动调用__add__()函数:

class Sum:
    def __init__(self, num):
        self.num = num

    def __add__(self, other):  # 对象在加号+的左侧时,自动触发
        return self.num + other


>>> value = Sum(7)
>>> res = value + 8
>>> print(res)
15

对象在加号的右侧时,自动调用__radd__()函数:

class Sum():
    def __init__(self, num):
        self.num = num

    def __radd__(self, other):  
        return self.num + other


>>> value = Sum(7)
>>> res = 10 + value
>>> print(res)
17

思考一哈,下面的程序的结果是多少?

class Sum1:
    def __init__(self, num):
        self.num = num

    def __add__(self, other):
        return self.num + other


class Sum2:
    def __init__(self, num):
        self.num = num

    def __radd__(self, other):
        return self.num * 2 + other


>>> value1 = Sum1(10)
>>> value2 = Sum2(7)
>>> res = value1 + value2
>>> print(res)

分析:首先将res=value1+value2传入Sum1中,得出值res=10+value2,再将res=10+value2传入Sum2中,所以res=14+10=24

10、__len__ 

  • 触发时机:使用len(对象)的时候自动触发
  • 功能:用于检测对象中或者类中成员个数
  • 参数:一个self接收当前对象
  • 返回值:必须是整型
class List:
    def __init__(self):
        self.num = []

    def add(self, x):
        self.num.append(x)

    def __len__(self):
        return len(self.num)


>>> l = List()
>>> l.add(2)
>>> print(len(l))

 

11、__dict__ 

获取类或对象的的内部成员结构。主要用来获取用户自定义的属性,以及这个属性对应的值。返回的是一个字典

class MyClass():
    name1 = "Lsir"
    name2 = "Wsir"
    name3 = "Zsir"

    def task1(self):
        print("task1")

    def task2(self):
        print("tesk2")

    def task3(self):
        print("task3")


>>> print(MyClass.__dict__)
{'__module__': '__main__', 
'name1': 'Lsir', 
'name2': 'Wsir', 
'name3': 'Zsir', 
'task1': <function MyClass.task1 at 0x0000020C16385558>,
 'task2': <function MyClass.task2 at 0x0000020C16385D38>, 
'task3': <function MyClass.task3 at 0x0000020C16385708>, 
'__dict__': <attribute '__dict__' of 'MyClass' objects>,
 '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 
'__doc__': None}

和dir函数做一个区分。dir函数返回的是这个对象上拥有的所有属性,包括Python内置的属性和用户自己添加的,并且只是获取属性名字,不会获取这个属性对应的值。
 

12、__doc__ 

获取类或对象内部文档。

class MyClass():
    """
        我是一个类,这里说明一些有用的信息
    """

    def __init__(self):
        pass


print(MyClass.__doc__)

        我是一个类,这里说明一些有用的信息
    

 

13、__name__ 
 

获取类名或函数名

class Class1:
    pass


class MyClass:
    def task1(self, func1):
        print(func1.__name__)


def func():
    print("我是func1函数")


>>> obj = MyClass()
>>> obj.task1(func)
func
>>> obj.task1(Class1)
Class1

 

14、__class__ 

获取当前对象获取的类

class Class1:
    pass


>>> obj = Class1()
>>> print(obj.__class__)
<class '__main__.Class1'>
>>> print(obj.__class__.__name__)
Class1

 

15、__getattr__ 

如果访问属性存在(包含对象属性和类属性,会按照继承关系找),就不会调用__getattr__方法。当访问的属性不存在的时候,就会调用该方法。


class MyClass(object):

    c = "c"

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

    def __getattr__(self, item):
        print("---getattr方法执行")
        return "getattr"


if __name__ == "__main__":
    obj = MyClass("a")

    # 1.获取到对象属性不会调用getattr方法
    print(obj.a)
    # 2.获取不到对象属性不会调用getattr方法
    print(obj.b)
”“”
a
---getattr方法执行
getattr
“”“

 

16、__getattribute__ 

实例的所有的属性访问,第一个都会调用__getattribute__方法,它阻止了属性的查找,该方法应该返回值或者抛出一个AttributeError异常。

  • 该方法的返回值将作为属性查找的结果。
  • 如果抛出AttributeError异常,则会直接调用__getattr__方法,因为属性没有找到,__getattribute__方法中为了避免在该方法中无限递归,它的实现应该永远调用基类的同名方法以访问需要的任何属性。

需要注意的是,除非明确知道__getattrtbute__方法用来做什么,否则不要使用。

17、__setattr__ 

实例通过.点号设置属性,例如self.x=x,就会调用__setattr__(),属性要加到实例的__dict__中,就需要自己完成。

即:在__init__()方法中设置属性时,如elf.x=x就会自动调用__setattr__()方法,在__setattr__()方法中,应该把属性以键值对形式添加到__dict__字典中。

setattr()方法,可以拦截堆实例属性的增加,修改操作,如果要设置生效,需要自己操作实例的__dict__

 

class Base:
    n = 200
    
class A(Base):
    z = 100
    d = {}
    
    def __init__(self, x, y):
        self.x = x
        setattr(self, 'y', y)
        self.__dict__['a'] = 5
        
    def __getattr__(self, item):
        print(item)
        return self.d[item]
    
    def __setattr__(self, key, value):
        print(key, value)
        self.d[key] = value
        
>>> a = A(4, 5)
x 4
y 5
>>> print(a.__dict__)
{'a': 5}
>>> print(A.__dict__)
A.__dict__
mappingproxy({'__module__': '__main__',
              'z': 100,
              'd': {'x': 4, 'y': 5},
              '__init__': <function __main__.A.__init__(self, x, y)>,
              '__getattr__': <function __main__.A.__getattr__(self, item)>,
              '__setattr__': <function __main__.A.__setattr__(self, key, value)>,
              '__doc__': None})
>>> print(a.x, a.y)
x
y
4 5
>>> print(a.a)
5
class Fun:
    def __init__(self):
        self.name = "Liu"
        self.age = 12
        self.male = True
        
    def __setattr__(self, key, value):
        print("*"*50)
        print("setting:{},  with:{}".format(key[], value))
        print("current __dict__ : {}".format(self.__dict__))
        # 属性注册
        self.__dict__[key] = value
fun = Fun()    

通过在__setattr__()中将属性名作为key,并将属性值作为value,添加到了__dict__中,得到的结果如下:

**************************************************
setting:name,  with:Liu
current __dict__ : {}
**************************************************
setting:age,  with:12
current __dict__ : {'name': 'Liu'}
**************************************************
setting:male,  with:True
current __dict__ : {'name': 'Liu', 'age': 12}

由于__setattr__()负责在__dict__中对属性进行注册,即在__setattr__()方法中把属性以键值对形式加入到__dict__字典中。所以自己在重载时必须进行属性注册过程,下面是__setattr__()不进行属性注册的例子:

三、其他

1、==和is与isinstance()和type()区别

一、==和is

  •  ==:变量名的value值是否相等
  •  is:变量名的id(地址)是否相等(数字类型的value值相等则id相等)

比如:a=[1],b=[1]

     a,b的value值相等都是[1],所以a==b为True

    a,b的id(内存地址)不相等,所以a is b为False

二、isinstance()和type()

  •  isinstance(变量名,类型):判断该变量是否是该类型,或者是否是该类和该类的父类类型
  •  type(变量名):获取该变量名的类型,结合==判断该变量的类型是否等于目标类型(等号右边value值)

比如:a类继承b类,实例c=a()

    isinstance(c,a)和isinstance(c,b)都是True

    type(c)的value值是a,a是不等于b的,所以a==b为False即:type(c)==b为False

2、单例模式 
 

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

单例模式的实现方式

1、模块实现方式

python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

mysingleton.py
Class Mysingleton:
	def foo(self):
		pass

singleton_obj=Mysingleton()

保存文件,需要使用时,直接在其他文件导入此文件中的对象 ,这个对象即是单例模式的对象:

from mysingleton import singleton_obj

2 装饰器实现方式

def Singleton(cls):
	_instance={}
	def _singleton(*args,**kwagrs):
		if cls not in  _instance:
			_instance[cls]=cls(*args,**kwagrs)
		return _instance[cls]
	return _singleton

@Singleton
class A:
	a=1
	def  __init__(self,x=0):
		self.x=x
	
a1=A(2)
a2=A(4)

3 类方法实现

class Player(object):
    # 静态变量
    _instanc=None
    _flag=False
    def __new__(cls, *args, **kwargs):
        print('new 执行')

        if cls._instanc is None:
            cls._instanc=super().__new__(cls)
        return cls._instanc
    def __init__(self):
        if not Player._flag:
            print('init')
            Player._flag=True


if __name__=='__main__':
	video=Player()
    print(video)
    music=Player()
    print(music)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 魔术方法Python中的特殊方法,它们以双下划线开头和结尾,例如__init__、__str__、__add__等。这些方法可以在类的实例化、运算符重载、属性访问等方面提供特殊的行为。 __init__方法是一个特殊的构造函数,用于初始化类的实例。__str__方法用于返回对象的字符串表示形式,可以通过print函数输出。__add__方法用于重载加法运算符,可以实现自定义的加法操作。其他常用的魔术方法还包括__eq__、__lt__、__gt__等,用于比较运算符的重载。 学习魔术方法可以让我们更好地理解Python面向对象编程的特性,提高代码的可读性和可维护性。 ### 回答2: 魔术方法Python中最有趣且也是最强大的概念之一。魔术方法(也称为特殊方法或双下划线方法)是一些特殊的方法,它们以双下划线(__)开头和结尾,并具有特定的名称。 这些特殊方法可以为我们提供许多有用的功能,例如重载操作符,处理类的属性,实现自定义迭代器,使用描述符等。 下面是一些常见的魔术方法: __init__:这是最常见的魔术方法。当创建一个实例时,它会被自动调用。它用于初始化对象的属性。 __str__:当你想要将一个对象转换成字符串时,这个方法会被调用。如果你不指定__str__方法Python默认会使用对象的类名和内存地址来表示对象。 __repr__:这个方法和__str__方法类似,也是用于将对象转换成字符串。但是__repr__方法在调试时有很大的作用,因为它返回的字符串可以用来唯一地标识对象。 __len__:这个方法可以返回对象的长度。例如,如果你想获取一个字符串的长度,你可以使用len("hello"),在底层,它实际上是调用了字符串对象的__len__方法。 __getattr__和__setattr__:这些方法允许你动态地获取和设置对象的属性。当你访问一个不存在的属性时,__getattr__方法会被调用。当你设置一个属性时,__setattr__方法会被调用。 __call__:这个方法允许你将对象作为函数调用。当你调用一个对象时,Python实际上是在调用对象的__call__方法。 除了上面列举的方法,还有许多其他的魔术方法,例如__cmp__,__hash__,__iter__等等。学习这些魔术方法将使你能够更好地理解Python面向对象编程模型。 总之,学习和理解魔术方法Python面向对象编程中的一个关键概念,因为它们可以帮助你实现更加灵活和强大的代码。如果你想成为一名Python高手,那么深入学习魔术方法是不可避免的。 ### 回答3: Python中的“魔术方法”指的是每个类中定义的特殊方法,它们以双下划线(__)开头和结尾,并且有着特定的用途。通过使用这些魔法方法,我们可以自定义类的行为,并为程序提供更高级别的功能。 以下是Python中常用的一些魔术方法: 1. __init__:这是最常用的魔术方法之一,它用于初始化一个类的对象,以及定义类的属性和方法。 2. __str__:此方法用于返回对象的字符串表示形式,类似于Java中的toString()方法。 3. __repr__:与__str__类似,但是返回的是对象的“官方”字符串表示形式,通常用于调试和开发。 4. __getattr__:当试图访问一个不存在的属性时,此方法被调用。 5. __setattr__:当尝试设置类的属性时,此方法被调用。 6. __delattr__:当尝试删除类的属性时,此方法被调用。 7. __call__:将对象作为函数调用时,此方法被调用。 8. __len__:返回对象的长度。 9. __getitem__:允许通过索引访问对象的元素。 10. __setitem__:允许通过索引设置对象的元素。 11. __delitem__:允许通过索引删除对象的元素。 通过了解和使用这些魔术方法,我们可以编写出更高效、更灵活、更具可读性的Python代码,并且实现类似于内置类型一样的功能。例如,我们可以实现一个自定义列表,类似于Python的list类型,然后使用上述魔术方法来访问、设置和删除元素。同时,我们还可以自定义变量和函数的行为,使我们的Python代码变得更具有表现力和弹性。 总之,了解和掌握Python的魔术方法Python编程中必不可少的一部分,对于理解和编写实际应用程序非常有价值。在实践中,我们可以根据实际情况选择恰当的魔术方法,从而创建更灵活、更高效的Python类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值