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}