本文共 14271 字,大约阅读时间需要 47 分钟。
# hasattr(object, name)# 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。class test1(): def __init__(self): self.name='xiaohua' def run_test(self): print('hello {}'.format(self.name))test=test1()test.run_test() # hello xiaohuaprint(vars(test)) # {'name': 'xiaohua'}print(vars(test1)) # {'__module__': '__main__', '__doc__': None, '__dict__':, '__weakref__': , '__init__': , 'run_test': }print(hasattr(test,'name')) # Trueprint(hasattr(test1, 'run_test')) # True,但是如果换成了name 就是false# setattr(object, name, values)# 给对象的属性赋值,若属性不存在,先创建再赋值。setattr(test, "age", "18") #为属相赋值,并没有返回值print(hasattr(test, "age"))print(getattr(test,'age'))# True# 18
class Critter(object): '''A virtual pet''' def __init__(self, name): print ('A new critter has been born!') self.__name = name def get_name(self): return self.__name def set_name(self, new_name): if new_name == '': print ('A critter name can not be the empty string.') else: self.__name = new_name print ('Name change successful.') name = property(get_name, set_name) def talk(self): print('Hi, I am %s' % self.name)crit = Critter('Poochie')# A new critter has been born!crit.talk() # Hi, I am Poochieprint(crit.name) #Poochie
在Python 3.0中,%操作符通过一个更强的格式化方法format()进行了增强,这个用来格式化的模版使用大括号({,})作为特殊字符
print('User ID: {0}'.format('root')) # positional argument# Use the named keyword argumentsprint('User ID: {uid} Last seen: {last_login}'.format( uid='root', last_login = '5 Mar 2008 07:20'))# outputs:# User ID: root# User ID: root Last seen: 5 Mar 2008 07:20
语法: eval(source[, globals[, locals]]) -> value
参数:
source:一个Python表达式或函数compile()返回的代码对象
globals:可选。必须是dictionary
locals:可选。任意map对象
可以把list,tuple,dict和string相互转化。
# 字符串转换成列表a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"print(isinstance(a,str)) # Trueprint(type(a)) #b = eval(a)print(b) # [[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]print(type(b)) # # 字符串转换成字典a1 = "{1: 'a', 2: 'b'}"b1 = eval(a1)print(b1) # { 1: 'a', 2: 'b'}print(type(b1)) # # 字符串转换成元组a2 = "([1,2], [3,4], [5,6], [7,8], (9,0))"b2 = eval(a2)print(b2) # ([1, 2], [3, 4], [5, 6], [7, 8], (9, 0))print(type(b2)) #
从我的理解就是将其转化成双引号内最外层的字符
repr函数,对应repr(object)这个函数,返回一个可以用来表示对象的可打印字符串.
class Pair: def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return 'Pair({0.x!r}, {0.y!r})'.format(self) def __str__(self): return '({0.x!s}, {0.y!s})'.format(self)pair=Pair(3,5)print(pair) # 调用__str__, 因为使用了printprint(Pair(3,5)) # 调用__str__# >>> p = Pair(3, 4)# >>> p# Pair(3, 4) # __repr__() output# __repr__() 方法返回一个实例的代码表示形式,通常用来重新构造这个实例。# 内置的 repr() 函数返回这个字符串,跟我们使用交互式解释器显示的值是一样的。# __str__() 方法将实例转换为一个字符串,使用 str() 或 print() 函数会输出这个字符串。# 我们在这里还演示了在格式化的时候怎样使用不同的字符串表现形式。# 特别来讲,!r 格式化代码指明输出使用 __repr__() 来代替默认的 __str__() 。print('p is {0!r}'.format(pair)) # p is Pair(3, 5)print('p is {0}'.format(pair)) # p is (3, 5)# 上面的 format() 方法的使用看上去很有趣,格式化代码 {0.x} 对应的是第1个参数的x属性。# 因此,在下面的函数中,0实际上指的就是 self 本身# 作为这种实现的一个替代,你也可以使用 % 操作符,就像下面这样# def __repr__(self):# return 'Pair(%r, %r)' % (self.x, self.y)
你想通过 format() 函数和字符串方法使得一个对象能支持自定义的格式化
_formats = { 'ymd' : '{d.year}-{d.month}-{d.day}', 'mdy' : '{d.month}/{d.day}/{d.year}', 'dmy' : '{d.day}/{d.month}/{d.year}' }class Date: def __init__(self, year, month, day): self.year = year self.month = month self.day = day def __format__(self, code): if code == '': code = 'ymd' fmt = _formats[code] return fmt.format(d=self) # '{d.year}-{d.month}-{d.day}'.format(d)d = Date(2012, 12, 21)print(d) # <__main__.Date object at 0x0000000002D00048>print(format(d)) # 2012-12-21print(format(d,'mdy')) # 12/21/2012# 直接用于date模块from datetime import dated = date(2012, 12, 21)print(format(d,'%A, %B %d, %Y'))print('The end is {:%d %b %Y}. Goodbye'.format(d))
from socket import socket, AF_INET, SOCK_STREAMclass LazyConnection: def __init__(self, address, family=AF_INET, type=SOCK_STREAM): self.address = address self.family = family self.type = type self.sock = None def __enter__(self): if self.sock is not None: raise RuntimeError('Already connected') self.sock = socket(self.family, self.type) self.sock.connect(self.address) return self.sock def __exit__(self, exc_ty, exc_val, tb): self.sock.close() self.sock = None# 这个类的关键特点在于它表示了一个网络连接,但是初始化的时候并不会做任何事情(比如它并没有建立一个连接)。# 连接的建立和关闭是使用 with 语句自动完成的from functools import partialconn = LazyConnection(('www.python.org', 80))# Connection closedwith conn as s: # conn.__enter__() executes: connection open s.send(b'GET /index.html HTTP/1.0\r\n') s.send(b'Host: www.python.org\r\n') s.send(b'\r\n') resp = b''.join(iter(partial(s.recv, 8192), b'')) # conn.__exit__() executes: connection closed# 当出现 with 语句的时候,对象的 __enter__() 方法被触发, 它返回的值(如果有的话)会被赋值给 as 声明的变量。# 然后,with 语句块里面的代码开始执行。 最后,__exit__() 方法被触发进行清理工作。# 不管 with 代码块中发生什么,上面的控制流都会执行完,就算代码块中发生了异常也是一样的。# 事实上,__exit__() 方法的第三个参数包含了异常类型、异常值和追溯信息(如果有的话)。# __exit__() 方法能自己决定怎样利用这个异常信息,或者忽略它并返回一个None值。# 如果 __exit__() 返回 True ,那么异常会被清空,就好像什么都没发生一样, with 语句后面的程序继续在正常执行。
# Python程序员不去依赖语言特性去封装数据,而是通过遵循一定的属性和方法命名规约来达到这个效果。# 第一个约定是任何以单下划线_开头的名字都应该是内部实现。class A: def __init__(self): self._internal = 0 # An internal attribute self.publicP = 1 # A public attribute def public_method(self): ''' A public method ''' pass def _internal_method(self): passaObj=A()print(aObj.publicP) # 1print(aObj.public_method()) # None# 提示中看不到_开头的函数和属性# 使用下划线开头的约定同样适用于模块名和模块级别函数class B: def __init__(self): self.__private = 0 def __private_method(self): pass def public_method(self): pass self.__private_method()# dir 列出指定对象或类的的所有可用方法print(dir(B))# ['_B__private_method', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',# '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__',# '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',# '__str__', '__subclasshook__', '__weakref__', 'public_method']print(B._B__private) # Error 可以看出上面的可用方法中没有_B__private这个变量print(dir(bobj))# ['_B__private', '_B__private_method', '__class__', '__delattr__', '__dict__',# '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',# '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',# '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',# 'public_method']print(bobj._B__private) # 0# 使用双下划线开始会导致访问名称变成其他形式。# 比如,在前面的类B中,私有属性会被分别重命名为 _B__private 和 _B__private_method 。# 这时候你可能会问这样重命名的目的是什么,答案就是继承——这种属性通过继承是无法被覆盖的class C(B): def __init__(self): super().__init__() self.__private = 1 # Does not override B.__private # Does not override B.__private_method() def __private_method(self): pass# __private 和 __private_method 被重命名为 _C__private 和 _C__private_methodprint(vars(C))print(vars(B))# {'__module__': '__main__', '__doc__': None, '_C__private_method':, '__init__': }# {'_B__private_method': , '__dict__': , '__module__': '__main__', '__weakref__': , '__doc__': None, 'public_method': , '__init__': }
那么dir和vars的区别是什么:
dir():默认打印当前模块的所有属性,如果传一个对象参数则打印当前对象的属性
vars():默认打印当前模块的所有属性,如果传一个对象参数则打印当前对象的属性 dir()和vars()的区别就是dir()只打印属性(属性,属性……)而vars()则打印属性与属性的值(属性:属性值……)自定义某个属性的一种简单方法是将它定义为一个property
class Person: def __init__(self, first_name): self.first_name = first_name # Getter function @property def first_name(self): # 必须和属性名一样 # return self._first_name # 此方法对应的是setter方法中定义的_first_name和上面的是两码事 return self.name # 将其换成了name也okay只要setter中定义了 # Setter function @first_name.setter def first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') # self._first_name = value self.name=value # Deleter function (optional) @first_name.deleter def first_name(self): raise AttributeError("Can't delete attribute")# 这三个方法的名字都必须一样,和属性名一样# 第一个方法是一个 getter 函数,它使得 first_name 成为一个属性。# 其他两个方法给 first_name 属性添加了 setter 和 deleter 函数。# 需要强调的是只有在 first_name 属性被创建后,# 后面的两个装饰器 @first_name.setter 和 @first_name.deleter 才能被定义。# property的一个关键特征是它看上去跟普通的attribute没什么两样, 但是访问它的时候会自动触发 getter 、setter 和 deleter 方法# p=Person(100)# print(p.first_name) TypeError: Expected a stringp=Person('Young')print(p.first_name) # Youngp.first_name = 'Alvin'print(p.first_name) # Alvin# p.first_name = 42 TypeError: Expected a string# 在实现一个property的时候,底层数据(如果有的话)仍然需要存储在某个地方。# 因此,在get和set方法中,你会看到对 _first_name 属性的操作,这也是实际数据保存的地方。# 另外,你可能还会问为什么 __init__() 方法中设置了 self.first_name 而不是 self._first_name 。# 在这个例子中,我们创建一个property的目的就是在设置attribute的时候进行检查。# 因此,你可能想在初始化的时候也进行这种类型检查。通过设置 self.first_name ,自动调用 setter 方法, 这个方法里面会进行参数的检查,# 否则就是直接访问 self._first_name 了。
注意是先setter后getter
还能在已存在的get和set方法基础上定义property, 同上class Person: def __init__(self, first_name): self.set_first_name(first_name) # Getter function def get_first_name(self): return self._first_name # Setter function def set_first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value # Deleter function (optional) def del_first_name(self): raise AttributeError("Can't delete attribute") # Make a property from existing get/set methods name = property(get_first_name, set_first_name, del_first_name)
# 一个property属性其实就是一系列相关绑定方法的集合。# 如果你去查看拥有property的类, 就会发现property本身的fget、fset和fdel属性就是类里面的普通方法。# 通常来讲,你不会直接取调用fget或者fset,它们会在访问property的时候自动被触发print(dir(Person))print(Person.first_name.fget)print(Person.first_name.getter)## print(Person.__dict__)print(vars(Person))# 二者一样# { 'first_name': , '__dict__': , '__init__': , '__doc__': None, '__weakref__': , '__module__': '__main__'}# { 'first_name': , '__dict__': , '__init__': , '__doc__': None, '__weakref__': , '__module__': '__main__'}
Properties还是一种定义动态计算attribute的方法。 这种类型的attributes并不会被实际的存储,而是在需要的时候计算出来。
import mathclass Circle: def __init__(self, radius): self.radius = radius @property def area(self): return math.pi * self.radius ** 2 @property def diameter(self): return self.radius ** 2 @property def perimeter(self): return 2 * math.pi * self.radiusc = Circle(4.0)print(c.radius)print(c.area)print(c.diameter)print(c.perimeter)
调用父类方法 super() 函数
super([type [,object-or-type]]) 返回一个代理对象, 这个对象负责将方法调用分配给第一个参数的一个父类或者同辈的类去完成. super()和getattr() 都使用mro属性来解析搜索顺序, mro实际上是一个只读的元组. 如果提供了第二个参数, 则找到的父类对象的self就绑定到这个参数上, 后面调用这个对象的方法时, 可以自动地隐式传递self. 如果第二个参数是一个对象, 则isinstance(obj, type)必须为True. 如果第二个参数为一个类型, 则issubclass(type2, type)必须为True 不带参数的super()只能用在类定义中(因为依赖于caller的第二个参数), 编译器会自动根据当前定义的类填充参数. 也就是说, 后面所有调用super返回对象的方法时, 第一个参数self都是super()的第二个参数. 因为Python中所谓的方法, 就是一个第一个参数为self的函数, 一般在调用方法的时候a.b()会隐式的将a赋给b()的第一个参数.class A: def spam(self): print('A.spam')class B(A): def spam(self): print('B.spam') super().spam() # Call parent spam()b=B()print(b.spam())# outputs:# B.spam# A.spam# None
super() 函数的一个常见用法是在 init() 方法中确保父类被正确的初始化了
class A: def __init__(self): self.x = 0class B(A): def __init__(self): super().__init__() # 如果注释掉这句,AttributeError: 'B' object has no attribute 'x' self.y = 1 def output(self): print(self.x, self,y)b=B()print(b.x)print(b.y)# outputs:# 0# 1# >>> C.__mro__# (, , ,# )# >>>
子类会先于父类被检查
多个父类会根据它们在列表中的顺序被检查 如果对下一个类存在两个合法的选择,选择第一个父类class d1: def __init__(self): print('In d1...')class d2: def __init__(self): print('In d2...')class d3(d1,d2): def __init__(self): print('In d3...')print(d1.__mro__)print(d2.__mro__)# (, )# ( , )print(d3.mro()) # [ , , , ]print(d3.__mro__) # ( , , , )#一样
class Person: def __init__(self, name): self.name = name # Getter function @property def name(self): return self._name # Setter function @name.setter def name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._name = value # Deleter function @name.deleter def name(self): raise AttributeError("Can't delete attribute")class SubPerson(Person): @property def name(self): print('Getting name') return super().name @name.setter def name(self, value): #首先调用setter,其次调用getter print('Setting name to', value) super(SubPerson, SubPerson).name.__set__(self, value) @name.deleter def name(self): print('Deleting name') super(SubPerson, SubPerson).name.__delete__(self)
s = SubPerson('Guido') # Setting name to Guidoprint(s.name) # 调用了name属性# Getting name# Guidos.name = 'Larry' # Setting name to Larrys.name = 42 # TypeError: Expected a string
如果你仅仅只想扩展property的某一个方法,那么可以像下面这样写:
class SubPerson(Person): @Person.name.getter def name(self): print('Getting name') return super().name
或者,你只想修改setter方法,就这么写:
class SubPerson(Person): @Person.name.setter def name(self, value): print('Setting name to', value) super(SubPerson, SubPerson).name.__set__(self, value)
转载地址:http://hixba.baihongyu.com/