博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python3-类与对象
阅读量:6171 次
发布时间:2019-06-21

本文共 14271 字,大约阅读时间需要 47 分钟。

Python的hasattr() getattr() setattr() 函数

# 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

Python属性的get/set 方法

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

python3 中的format

在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()函数:将字符串str当成有效的表达式来求值并返回计算结果

语法: 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函数

你想通过 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))

了让一个对象兼容 with 语句,你需要实现 enter() 和 exit() 方法

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()则打印属性与属性的值(属性:属性值……)

创建可管理的属性,给某个实例attribute增加除访问与修改之外的其他处理逻辑,比如类型检查或合法性验证

自定义某个属性的一种简单方法是将它定义为一个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)

Supper

调用父类方法 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__) # (
,
,
,
)#一样

在子类中,扩展定义在父类中的property的功能

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/

你可能感兴趣的文章
涨姿势:工业物联网与大数据融合的四个重点
查看>>
社会学视角下的大数据方法论及其困境
查看>>
《云计算:原理与范式》一1.7 平台即服务供应商
查看>>
百度成立“百度搜索公司”:固本拓新驱动生态裂变
查看>>
宇宙风暴?才怪!瑞典暗指俄罗斯黑客攻击航空控制系统
查看>>
系统进程管理工具Process Explorer
查看>>
富士通仍执着SPARC架构芯片 将坚持推新
查看>>
易宪容:企业要利用大数据挖掘潜在需求
查看>>
微软声称Win10周年更新为Edge浏览器带来更好电池寿命
查看>>
混合云是企业IT的未来吗?
查看>>
LINE在日本取得成功 但全球化之路还很长
查看>>
红帽云套件新增QuickStart Cloud Installer,加快私有云部署
查看>>
MapXtreme 2005 学习心得 一些问题(八)
查看>>
流量精细化运营时代,营销SaaS之使命——流量掘金
查看>>
雅虎同意出售核心资产
查看>>
Win10大丰收的节奏 微软收编iOS全部150万应用
查看>>
智慧城市要除“城市病” 中兴通讯开辟新增长极
查看>>
Opera已确认解散iOS开发团队
查看>>
DevOps:新的业务浪潮
查看>>
CERT:启用EMET的Windows 7比Windows 10更加安全
查看>>