python魔法方法

定义

类自带双下划线开头和结束的方法
一般不需要主动调用,有特定方法和行为触发
对比备注
单鞋划线开头:单下划线在Python中被约定为一个“弱内部使用”标记。这意味着变量名以单下划线开头,表示该变量是类的内部使用,不建议在类外部直接访问。
双下划线开头或结尾:双下划线在Python中被约定为一个“名称修饰”标记。这意味着变量名以双下划线开头和结尾,表示这是一个特殊的变量,具有特殊的含义。

_str_ 和 _repr_

str将对象转化成为适于人阅读的前端样式文本,而repr()就是原本未处理的用于编译器阅读的后台底层代码。对于如\r,\n, \t, 引号等标识符,str会转意,repr会保留。

>>> a 
'hello, world!\n'     #输出的a本来的模样 
>>> print(a)      #对a经过编译后的样式文本输出,将转义字符进行转义 
hello,world! 
>>> print(str(a))     #可以看到对str返回的值进行print处理,这将与直接print(a)得到相同的结果 
hello,world! 
>>> repr(a)     #获得的是a原始输入的存在于存储器中用于机器底层编译的代码 
"'hello, world!\n'" 
>>> print(repr(a))     #对于repr返回的值进行print处理,可以看到这与直接在终端输入a,得到的是相同的结果 'hello,world!\n'

自定义类中,str和repr都可以作为类的打印输出,两者都定义的情况下str优先。

class student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return "name:{}, age:{}".format(self.name, self.age)
    def __repr__(self):
        return "name is {}, age is {}".format(self.name, self.age)
    
s1 = student("dxm", 20)
print(s1)

结果:

name:dxm, age:20

_del_

在对象生命周期结束的时候自动调用,一般内部书写下需要手动释放的资源(如文件句柄fin.close())
也可以通过del来手动调用

class Student(object):
    def __init__(self, name):
        self.name = name
        self.fin = open('student.txt', 'a+')
    def __del__(self):
        print('A object is deleted')
        self.fin.close()
s1 = Student('Tom')
del s1    
print('done')   
#结果为A object is deleted\n  done;
#如果不调用 del s1, 则结果为 done\nA object is deleted;

_new_

每次实例化一个对象的时候,会先调用new来生成实例,再调用init来初始化实例。
可以通过new方法和类变量来进行类的实例对象统计,也可以编写单实例类。

class Book(object):
    __book_count = 0 #类变量,定义在所有类方法之外,所有对象共享, 双下划线表示私有变量
    def __init__(self, name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        cls.__book_count += 1
        return super(Book, cls).__new__(cls)
    @classmethod
    def get_book_num(cls):
        return cls.__book_count
book1 = Book('三国演义')
book2 = Book('水浒传')
book3 = Book('红楼梦')
print(Book.get_book_num())
#print(Book.__book_count)  #私有变量不让外部访问,直接访问方式会报错

_dir_ 和 _dict_

函数作用对象调用方式结果
dir实例dir(book1)或者book1._dir_()返回列表:该实例所有的实例(类)变量和方法(包括私有变量和方法,会有命名修改)
dir类名dir(Book)或者Book._dir_()返回列表:该实例所有的类变量和方法(包括私有变量和方法,会有命名修改)
dict实例book1._dict_返回字典:返回所有所有实例变量和变量值(包括私有变量,会有命名修改),不包括方法
dict类名Book._dict_返回字典 :返回类变量类方法和对应的值

备注(python变量区分):

变量说明
全局变量在模块内、所有函数外、所有class外
局部变量在函数内、在class的方法(类方法、静态方法、实例方法)内,且变量前面没有修饰
类变量在class内,不在class的任何方法内
实例变量在class的方法内,且使用self修饰的变量

dict可以动态新增实例变量

class Book(object):
    __book_count = 0 #类变量,定义在所有类方法之外,所有对象共享, 双下划线表示私有变量
    def __init__(self, name):
        self.name = name
    def __new__(cls, *args, **kwargs):
        cls.__book_count += 1
        return super(Book, cls).__new__(cls)
    @classmethod
    def get_book_num(cls):
        return cls.__book_count
book1 = Book('三国演义')
book2 = Book('水浒传')
book3 = Book('红楼梦')
print(Book.get_book_num())
print(dir(book1))
print(dir(Book))
print(book1.__dict__)
print(Book.__dict__)

dir和dict打印结果如下:

['_Book__book_count', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_book_num', 'name']
['_Book__book_count', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_book_num']
{'name': '三国演义'}
{'__module__': '__main__', '_Book__book_count': 3, '__init__': <function Book.__init__ at 0x105868f40>, '__new__': <staticmethod(<function Book.__new__ at 0x105868fe0>)>, 'get_book_num': <classmethod(<function Book.get_book_num at 0x105869080>)>, '__dict__': <attribute '__dict__' of 'Book' objects>, '__weakref__': <attribute '__weakref__' of 'Book' objects>, '__doc__': None}

_getattribute_、_getattr_、_setattr_

_getattribute_(self,name) 访问实例任意属性(不管存不存在)时被调用.name为属性名。
_getattr_(self,name) 访问对象不存在的属性时候被调用。name为属性名。
_setattr_(self,name,value). 对实例属性进行赋值操作的时候被调用。name为属性名,value为属性数值。

_getattribute__和_getattr 一般用于处理外部访问到类中未定义的属性。_getattribute__优先调用。
_setattr__一般用于限定属性取值范围。在类初始化的时候的赋值操作同样会调用到__setattr

class Employee(object):
    def __init__(self, name: str, age: int):
        self.name = name
        self.age= age
    def __getattr__(self, name):
        if name == 'name':
            return 'xxx'
    def __getattribute__(self, name: str) -> any:
        try:
            return super().__getattribute__(name)
        except AttributeError as e:
            print('AttributeError: ' + str(e))
            return 'default'
    def __setattr__(self, name: str, value: str) -> None:
        if name == 'age':
            if value < 18:
                raise ValueError('too young')
            else:
                self.__dict__[name] = value
        else:
            self.__dict__[name] = value
e1 = Employee('Tom', 18)  #此处name和age分别调用一次__setattr__
print(e1.name)    #调用__getattribute__
print(e1.xxx)     #调用__getattribute__,由于__getattribute__已经处理了AttributeError异常,所以不会调用__getattr__
e1.age = 17      #触发__setattr__的ValueError异常

反射

通过字符串形式,在运行时动态修改程序变量、方法及属性的操作。

getattr、hasattr和setattr

根据用户输入的字符串来决定调用什么方法。
使用hasattr,getattr。
hasattr 判断类中是否有该名称的属性
getattr 根据名称索引方法或变量。如果是函数,得到函数的引用。如果是变量,得到值。如果没有查询到,则抛出异常。
setattr 动态添加一个方法或变量
delattr 动态删除一个方法或变量

class Dog(object):
    def __init__(self, name: str):
        self.name = name
    def eat(self) -> None:
        print('{} is eating '.format(self.name))
    def sleep(self) -> None:
        print('{} is sleeping '.format(self.name))
dog = Dog('wangcai')
choice = input('请出入要调用的函数名:')
if hasattr(dog, choice):
    func = getattr(dog, choice)
    func()
else:
    print('没有该方法')

# 动态添加变量
setattr(dog, 'age', 18)
print(dog.__dict__)

# 动态添加方法
def run(cls):
    print('{} is running'.format(cls.name))
setattr(Dog, 'run', run)
def run():
    print('is running')
setattr(dog, 'run', run)
getattr(dog, 'run')()
delattr(dog, 'run')

eval和exec

eval(expression, globals=None, locals=None) 使用locals和globals命名空间中的变量,计算表达式eval并输出,不影响表达式外的所有变量和函数,返回结果为表达式执行结果。表达式中变量查找顺序是先locals,后globals,再当前上下文命名空间。
exec(obj,[,globals,[,locals]]) 执行obj内部的代码块,可以对当前命名空间中变量进行新增、修改、删除等操作,无返回值。

x = 10
def fun():
    y = 20
    a =eval('x+y')
    print('a: ',a)
    b = eval('x+y', {'x': 1, 'y': 2})
    print('b: ', b)
    c = eval('x+y', {'x': 1, 'y': 2}, {'x': 3, 'y': 4})
    print('c: ', c)
fun()

结果:

a:  30
b:  3
c:  7

exec示例

b = "mydict = {'name': 'Tom', 'age': 18}"
exec(b)
print(mydict)   #执行结果:{'name': 'Tom', 'age': 18}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值