中企动力 > 头条 > python中object

网站性能检测评分

注:本网站页面html检测工具扫描网站中存在的基本问题,仅供参考。

python中object

Pycharm中pythonConsole无法打开之解决 企业视频课程

img

幼南

关注

文/爱琳玩python

大家好,这是我今天写的第一篇关于我在玩python中时遇到的问题,并最终解决了的文章,文笔很差,还请各位能多多包涵!话不多说,进入主题,在调试python代码中,我先目前使用的是Pycharm这款编辑器,这也是我在选择之前,看了很多入行的小白说的最好新手用Pycharm.因为它能帮你自动补全!当然这是作为小白的我个人的看点!

当然在有时调用代码时,你拿不准代码是否正确,这个时候你就可以调用Pycharm中的pythonConsole,对这个时候的我调用时,就出现报错:

AttributeError: 'PyDevTerminalInteractiveShell' object has no attribute 'has_readline'

这是什么东东啊!作为小白的我看到这个时,心里是非常的不舒服的,于是乎开始了度娘历险记,终于被我给找到了:这个问题源于pycharm version>2016.1与ipython version 5冲突。

怎么解决,成了我这个小白的当务之急,对了这里我的系统是Windows7的系统,python则是python3!

pip uninstall ipython

pip install ipython==4.2.0

然后你重新运行后就可以解决Pycharm中PythonConsole打开问题了!

运行之后的界面

最后,爱琳还是希望能帮到那些与我遇到同样问题的朋友,大家一起快快乐乐的玩python!

Python基础学习之常用六大数据类型 推广视频课程

img

大副

关注

刚开始学习一门编程语言,除了了解运行环境与语言类型之外,最基本还是从该语言的基本数据类型开始学起。

Python六大常用数据类型:

int 整数 float 浮点数 str 字符串 list 列表 tuple 元组 dict 字典

讲解这些先说一下python中的变量与变量名。

变量其实本质上是一个具有特殊格式的内存,变量名则是指向这个内存的别名。python中的变量不需要声明,所有的变量必须赋值了才能使用。赋值的步骤:

a = 100

第一步:准备好值100第二部:准备好变量名a第三部:将值与名字进行关联

一、整数python将其他一些静态语言中的int、long,也就是整型和长整型合并为了一个。python中的int是边长的,也就是说可以存储无限大的整数,但是这是不现实的,因为没有这么多的内存够分配。整型不仅支持十进制,还支持二进制、八进制、十六进制。可以通过下面的方式来互相转换:

print(bin(20)) #转换二进制print(oct(20)) #转换八进制print(hex(20)) #转换十六进制

二、浮点型浮点数也就是小数,如22.1,44.2,也可以使用科学计数法,比如:1.22e8。python支持对整数和浮点数直接进行四则混合运算。整数运算结果仍然是整数,浮点数运算结果仍然是浮点数,但整数和浮点数混合运算的结果就变成浮点数了。

a = 1b = 1.1print(type(a+b)) #

三、字符串字符串在任何编程语言中都是最常用的数据类型。字符串的创建很简单,也是上面所说的三步,但是要加上单引号或者双引号。

a = "hello python"

也可以使用 “”" 创建多行字符串:

a = """ hello python"""

字符串可以通过下面方式进行截取或者连接:

print (str[0:4]) 输出第一个到倒数第四个的所有字符 print (str[0]) 输出单字符 第1个字符print (str[3:]) 输出从第四个开始之后的所有字符print (str * 2) 输出字符串两次print (str + "bbbb") 连接字符串

字符串常用函数:str.strip() 消除字符串s左右两边的空白字符(包括’\t’,’\n’,’\r’,’’)len(str) 获取字符串长度str.upper() 转换为大写str.lower() 转换为小写str.title() 每个单词首字母大写str.capitalize() 首字母大写字符串翻转:

a = 'abcde'print(a[::-1])

字符串分割:

a = 'hello,python'print(a.split(',')) #['hello', 'python'] 返回一个列表

相对应的还有一个将列表元素连接成字符串:

a = ['hello', 'python']str = '-'print(str.join(a)) # hello-python

四、列表列表的写法是一个方括号内的值用逗号分隔。比如上面的[‘hello’, ‘python’]。列表的数据项不需要具有相同的类型,列表中的每个元素都分配一个数字索引,第一个索引是0,第二个索引是1,依此类推。访问列表中的值可以通过下面的方式:

list1 = [1, 2, 3, 4, 5, 6]print(list1[2])

同样可以通过索引截取

print ("list1[2:5]: ", list1[2:5])

列表常用操作:list1.append(‘7’) 追加一个元素在末尾,每次只能添加一个len(list1) 返回列表元素个数max(list1) 返回列表元素最大值min(list1) 返回列表元素最小值list1.count(obj) 统计某个元素在列表中出现的次数list1.index(obj) 从列表中找出某个值第一个匹配项的索引位置list1.reverse() 反向列表中元素list1.clear() 清空列表list1.extend(seq) 在列表末尾一次性追加另一个序列中的多个值,也就是扩充了列表 append与extend的区别:

A = ['a', 'b', 'c']A.append(['d', 'e'])print(A) # ['a', 'b', 'c', ['d', 'e']]B = ['a', 'b', 'c']B.extend(['d', 'e'])print(B) # ['a', 'b', 'c', 'd', 'e']

extend方法只能接收list类型,它是把这个列表中的每个元素添加到原list中。append可以接收任意类型,追加到原list的末尾。

五、元组元组的创建也很简单,和list类似,只是把’[]‘换成了’()’。

tup1 = ('hello', 'python')

元组中只有一个元素的时候要注意:

tup2 = (10)tup3 = ('a')print(type(tup2)) #print(type(tup3)) #

因为这样会被解释器当做运算符,所以正确的方法是在第一个元素后面添加逗号。

tup4 = ('a',)print(type(tup4)) #

元组同样可以使用下标索引来访问元组中的值:

tup5 = ('hello', 'python', 'hello', 'word')print(tup5[1]) #pythonprint(tup5[1:3]) #('python', 'hello')

注意:元组是不可以被修改的。

tup6 = ('hello', 'python', 'hello', 'word')tup6[2] = 'aaa'

上面会出现一个异常: TypeError: ‘tuple’ object does not support item assignment.但是元组中如果包含了一个列表,那么这个列表是可以被修改的。

tup7 = ('hello', 'python', 'hello', 'word', ['aa', 'bb', 'cc'])tup7[-1][1] = 'ddd'print(tup7) # ('hello', 'python', 'hello', 'word', ['aa', 'ddd', 'cc'])

元组运算符:len(tup) 计算元素个数tup1 + tup2 连接生成新元组tup * 4 元组复制num in tup 元素是否存在,返回True/False

六、字典python中的字典就是key,value的形式。使用大括号包含起来。字典中的成员的键是唯一的,如果出现多个同名的键,那么写在后面覆盖前面的值。形式如下:

dict1 = {'a' : 1, 'b' : 2}

字典的常用操作最基本的也就是增删改查:获取:直接通过键来获取。

dict['b'] # 2

dict.keys() 获取字典中所有的键dict.values() 获取字典中的所有的值增加:

dict1['c'] = 3 #{'a': 1, 'b': 2, 'c': 3} #如果键存在则更新对应的值

修改:直接给键进行再次赋值就可以修改键对应的值了。如果键不存在,则变成添加成员。还可以通过:

dict1.update({"a":"11"})dict1.setdefault("a", "222") # 已存在的键则修改无效dict1.setdefault("d","222") # 不存在的话则创建dict1.setdefault("e") # 没有设置值为None

删除:使用pop删除指定键对应的成员,同时返回该值

print(dict1) # {'a': '11', 'b': 2, 'c': 3, 'd': '222', 'e': None}print(dict1.pop("a")) # aprint(dict1) # {'b': 2, 'c': 3, 'd': '222', 'e': None}#在不设置默认值的情况下,使用pop删除不存在的键,会报错。print(dict1.pop("f")) # 报错 KeyError: 'f'

如果设置了默认值, print(dict1.pop(“f”, None)),则不会报错,返回这个默认值。判断是否删除成功可以通过下面方式来判断:

if dict1.pop("f", None) == None: print('键不存在')else: print('删除成功')

以上则是python中最基本的数据类型以及用法,当然还有其他的数据类型,作者暂时只列举了这些。

更过python文章,关注作者哦!干货多多!!

在Python 2.7即将停止支持时,我们为你准备了一份3.x迁移指南 营销视频课程

img

Santa

关注

机器之心编译

目前,Python 科学栈中的所有主要项目都同时支持 Python 3.x 和 Python 2.7,不过,这种情况很快即将结束。去年 11 月,Numpy 团队的一份声明引发了数据科学社区的关注:这一科学计算库即将放弃对于 Python 2.7 的支持,全面转向 Python 3。Numpy 并不是唯一宣称即将放弃 Python 旧版本支持的工具,pandas 与 Jupyter notebook 等很多产品也在即将放弃支持的名单之中。对于数据科学开发者而言,如何将已有项目从 Python 2 转向 Python 3 成为了正在面临的重大问题。来自莫斯科大学的 Alex Rogozhnikov 博士为我们整理了一份代码迁移指南。

Python 3 功能简介

Python 是机器学习和其他科学领域中的主流语言,我们通常需要使用它处理大量的数据。Python 兼容多种深度学习框架,且具备很多优秀的工具来执行数据预处理和可视化。

但是,Python 2 和 Python 3 长期共存于 Python 生态系统中,很多数据科学家仍然使用 Python 2。2019 年底,Numpy 等很多科学计算工具都将停止支持 Python 2,而 2018 年后 Numpy 的所有新功能版本将只支持 Python 3。

为了使 Python 2 向 Python 3 的转换更加轻松,我收集了一些 Python 3 的功能,希望对大家有用。

使用 pathlib 更好地处理路径

pathlib 是 Python 3 的默认模块,帮助避免使用大量的 os.path.joins:

from pathlib importPath

dataset ='wiki_images'

datasets_root =Path('/path/to/datasets/')

train_path = datasets_root / dataset /'train'

test_path = datasets_root / dataset /'test'

for image_path in train_path.iterdir():

with image_path.open()as f:# note, open is a method of Path object

# do something with an image

Python 2 总是试图使用字符串级联(准确,但不好),现在有了 pathlib,代码安全、准确、可读性强。

此外,pathlib.Path 具备大量方法,这样 Python 新用户就不用每个方法都去搜索了:

p.exists()

p.is_dir()

p.parts()

p.with_name('sibling.png')# only change the name, but keep the folder

p.with_suffix('.jpg')# only change the extension, but keep the folder and the name

p.chmod(mode)

p.rmdir()

pathlib 会节约大量时间,详见:

文档:https://docs.python.org/3/library/pathlib.html;

参考信息:https://pymotw/3/pathlib/。

类型提示(Type hinting)成为语言的一部分

PyCharm 中的类型提示示例:

Python 不只是适合脚本的语言,现在的数据流程还包括大量步骤,每一步都包括不同的框架(有时也包括不同的逻辑)。

类型提示被引入 Python,以帮助处理越来越复杂的项目,使机器可以更好地进行代码验证。而之前需要不同的模块使用自定义方式在文档字符串中指定类型(注意:PyCharm 可以将旧的文档字符串转换成新的类型提示)。

下列代码是一个简单示例,可以处理不同类型的数据(这就是我们喜欢 Python 数据栈之处)。

def repeat_each_entry(data):

""" Each entry in the data is doubled

"""

index = numpy.repeat(numpy.arange(len(data)),2)

return data[index]

上述代码适用于 numpy.array(包括多维)、astropy.Table 和 astropy.Column、bcolz、cupy、mxnet.ndarray 等。

该代码同样可用于 pandas.Series,但是方式是错误的:

repeat_each_entry(pandas.Series(data=[0,1,2], index=[3,4,5]))# returns Series with Nones inside

这是一个两行代码。想象一下复杂系统的行为多么难预测,有时一个函数就可能导致错误的行为。明确了解哪些类型方法适合大型系统很有帮助,它会在函数未得到此类参数时给出提醒。

def repeat_each_entry(data:Union[numpy.ndarray, bcolz.carray]):

如果你有一个很棒的代码库,类型提示工具如 MyPy 可能成为集成流程中的一部分。不幸的是,提示没有强大到足以为 ndarrays/tensors 提供细粒度类型,但是或许我们很快就可以拥有这样的提示工具了,这将是 DS 的伟大功能。

类型提示 → 运行时的类型检查

默认情况下,函数注释不会影响代码的运行,不过它也只能帮你指出代码的意图。

但是,你可以在运行时中使用 enforce 等工具强制进行类型检查,这可以帮助你调试代码(很多情况下类型提示不起作用)。

@enforce.runtime_validation

def foo(text: str)->None:

print(text)

foo('Hi')# ok

foo(5)# fails

@enforce.runtime_validation

def any2(x:List[bool])->bool:

return any(x)

any ([False,False,True,False])# True

any2([False,False,True,False])# True

any (['False'])# True

any2(['False'])# fails

any ([False,None,"",0])# False

any2([False,None,"",0])# fails

函数注释的其他用处

如前所述,注释不会影响代码执行,而且会提供一些元信息,你可以随意使用。

例如,计量单位是科学界的一个普遍难题,astropy 包提供一个简单的装饰器(Decorator)来控制输入量的计量单位,并将输出转换成所需单位。

# Python 3

from astropy import units as u

@u.quantity_input()

def frequency(speed: u.meter / u.s, wavelength: u.m)->u.terahertz:

return speed / wavelength

frequency(speed=300_000 * u.km / u.s, wavelength=555* u.nm)

# output: 540.5405405405404 THz, frequency of green visible light

如果你拥有 Python 表格式科学数据(不必要太多),你应该尝试一下 astropy。你还可以定义针对某个应用的装饰器,用同样的方式来控制/转换输入和输出。

通过 @ 实现矩阵乘法

下面,我们实现一个最简单的机器学习模型,即带 L2 正则化的线性回归:

# l2-regularized linear regression: || AX - b ||^2 + alpha * ||x||^2 ->min

# Python 2

X = np.linalg.inv(np.dot(A.T, A)+ alpha * np.eye(A.shape[1])).dot(A.T.dot(b))

# Python 3

X = np.linalg.inv(A.T @ A + alpha * np.eye(A.shape[1]))@(A.T @ b)

下面 Python 3 带有 @ 作为矩阵乘法的符号更具有可读性,且更容易在深度学习框架中转译:因为一些如 X @ W + b[None, :] 的代码在 numpy、cupy、pytorch 和 tensorflow 等不同库下都表示单层感知机。

使用 ** 作为通配符

递归文件夹的通配符在 Python2 中并不是很方便,因此才存在定制的 glob2 模块来克服这个问题。递归 flag 在 Python 3.6 中得到了支持。

import glob

# Python 2

found_images = \

glob.glob('/path*.jpg') \

+ glob.glob('/path*.jpg') \

+ glob.glob('/path***.jpg')

# Python 3

found_images = glob.glob('/path*.jpg', recursive=True)

python3 中更好的选择是使用 pathlib:

# Python 3

found_images = pathlib.Path('/path/').glob('**/*.jpg')

Print 在 Python3 中是函数

Python 3 中使用 Print 需要加上麻烦的圆括弧,但它还是有一些优点。

使用文件描述符的简单句法:

print>>sys.stderr,"critical error"# Python 2

print("critical error", file=sys.stderr)# Python 3

在不使用 str.join 下输出 tab-aligned 表格:

# Python 3

print(*array, sep='\t')

print(batch, epoch, loss, accuracy, time, sep='\t')

修改与重新定义 print 函数的输出:

# Python 3

_print =print# store the original print function

defprint(*args,**kargs):

pass# do something useful, e.g. store output to some file

在 Jupyter 中,非常好的一点是记录每一个输出到独立的文档,并在出现错误的时候追踪出现问题的文档,所以我们现在可以重写 print 函数了。

在下面的代码中,我们可以使用上下文管理器暂时重写 print 函数的行为:

@contextlib.contextmanager

def replace_print():

import builtins

_print =print# saving old print function

# or use some other function here

builtins.print=lambda*args,**kwargs: _print('new printing',*args,**kwargs)

yield

builtins.print= _print

with replace_print():

上面并不是一个推荐的方法,因为它会引起系统的不稳定。

print 函数可以加入列表解析和其它语言构建结构。

# Python 3

result = process(x)if is_valid(x)elseprint('invalid item: ', x)

f-strings 可作为简单和可靠的格式化

默认的格式化系统提供了一些灵活性,且在数据实验中不是必须的。但这样的代码对于任何修改要么太冗长,要么就会变得很零碎。而代表性的数据科学需要以固定的格式迭代地输出一些日志信息,通常需要使用的代码如下:

# Python 2

print('{batch:3} {epoch:3} / {total_epochs:3} accuracy: {acc_mean:0.4f}±{acc_std:0.4f} time: {avg_time:3.2f}'.format(

batch=batch, epoch=epoch, total_epochs=total_epochs,

acc_mean=numpy.mean(accuracies), acc_std=numpy.std(accuracies),

avg_time=time / len(data_batch)

))

# Python 2 (too error-prone during fast modifications, please avoid):

print('{:3} {:3} / {:3} accuracy: {:0.4f}±{:0.4f} time: {:3.2f}'.format(

batch, epoch, total_epochs, numpy.mean(accuracies), numpy.std(accuracies),

time / len(data_batch)

))

样本输出:

12012/300 accuracy:0.8180±0.4649 time:56.60

f-strings 即格式化字符串在 Python 3.6 中被引入:

# Python 3.6+

print(f'{batch:3} {epoch:3} / {total_epochs:3} accuracy: {numpy.mean(accuracies):0.4f}±{numpy.std(accuracies):0.4f} time: {time / len(data_batch):3.2f}')

另外,写查询语句时非常方便:

query = f"INSERT INTO STATION VALUES (13, '{city}', '{state}', {latitude}, {longitude})"

「true pision」和「integer pision」之间的明显区别

对于数据科学来说这种改变带来了便利(但我相信对于系统编程来说不是)。

data = pandas.read_csv('timing.csv')

velocity = data['distance']/ data['time']

Python 2 中的结果依赖于『时间』和『距离』(例如,以米和秒为单位)是否被保存为整数。

在 Python 3 中,结果的表示都是精确的,因为除法的结果是浮点数。

另一个案例是整数除法,现在已经作为明确的运算:

n_gifts = money // gift_price # correct for int and float arguments

注意,该运算可以应用到内建类型和由数据包(例如,numpy 或 pandas)提供的自定义类型。

严格排序

# All these comparisons are illegal in Python 3

3<'3'

2

(3,4)<(3,None)

(4,5)<[4,5]

# False in both Python 2 and Python 3

(4,5)==[4,5]

防止不同类型实例的偶然性的排序。

sorted([2,'1',3])# invalid for Python 3, in Python 2 returns [2, 3, '1']

在处理原始数据时帮助发现存在的问题。

旁注:对 None 的合适检查是(两个版本的 Python 都适用):

if a isnotNone:

pass

if a:# WRONG check for None

pass

自然语言处理的 Unicode

s ='您好'

print(len(s))

print(s[:2])

输出:

Python 2: 6\n

Python 3: 2\n 您好.

x = u'со'

x +='co'# ok

x +='со'# fail

Python 2 在此失败了,而 Python 3 可以如期工作(因为我在字符串中使用了俄文字母)。

在 Python 3 中 strs 是 Unicode 字符串,对非英语文本的 NLP 处理更加方便。

还有其它有趣的方面,例如:

'a'< type < u'a'# Python 2: True

'a'< u'a'# Python 2: False

from collections importCounter

Counter('Mbelstück')

Python 2: Counter({'\xc3': 2, 'b': 1, 'e': 1, 'c': 1, 'k': 1, 'M': 1, 'l': 1, 's': 1, 't': 1, '\xb6': 1, '\xbc': 1})

Python 3: Counter({'M': 1, '': 1, 'b': 1, 'e': 1, 'l': 1, 's': 1, 't': 1, 'ü': 1, 'c': 1, 'k': 1})

这些在 Python 2 里也能正确地工作,但 Python 3 更为友好。

保留词典和**kwargs 的顺序

在 CPython 3.6+ 版本中,字典的默认行为类似于 OrderedDict(在 3.7+版本中已得到保证)。这在字典理解(和其他操作如 json 序列化/反序列化期间)保持顺序。

import json

x ={str(i):i for i in range(5)}

json.loads(json.dumps(x))

# Python 2

{u'1':1, u'0':0, u'3':3, u'2':2, u'4':4}

# Python 3

{'0':0,'1':1,'2':2,'3':3,'4':4}

它同样适用于**kwargs(在 Python 3.6+版本中):它们的顺序就像参数中显示的那样。当设计数据流程时,顺序至关重要,以前,我们必须以这样繁琐的方式来编写:

from torch import nn

# Python 2

model = nn.Sequential(OrderedDict([

('conv1', nn.Conv2d(1,20,5)),

('relu1', nn.ReLU()),

('conv2', nn.Conv2d(20,64,5)),

('relu2', nn.ReLU())

]))

# Python 3.6+, how it *can* be done, not supported right now in pytorch

model = nn.Sequential(

conv1=nn.Conv2d(1,20,5),

relu1=nn.ReLU(),

conv2=nn.Conv2d(20,64,5),

relu2=nn.ReLU())

)

注意到了吗?名称的唯一性也会被自动检查。

迭代地拆封

# handy when amount of additional stored info may vary between experiments, but the same code can be used in all cases

model_paramteres, optimizer_parameters,*other_params = load(checkpoint_name)

# picking two last values from a sequence

*prev, next_to_last, last = values_history

# This also works with any iterables, so if you have a function that yields e.g. qualities,

# below is a simple way to take only last two values from a list

*prev, next_to_last, last = iter_train(args)

默认的 pickle 引擎为数组提供更好的压缩

# Python 2

import cPickle as pickle

import numpy

print len(pickle.dumps(numpy.random.normal(size=[1000,1000])))

# result: 23691675

# Python 3

import pickle

import numpy

len(pickle.dumps(numpy.random.normal(size=[1000,1000])))

# result: 8000162

节省 3 倍空间,而且速度更快。实际上,类似的压缩(不过与速度无关)可以通过 protocol=2 参数来实现,但是用户...

如何在 Python 中正确的代理对象 企业视频课程

img

罗天德

关注

本文基于 Python 3.6

题外话

先来看一个问题: 已知对于一个对象来说,运算符 > 会去调用对象的 __gt__ 方法:

已知对于对象来说,__getattribute__ 在寻找实例属性时被无条件调用:

那么根据亚里士多德的三段论来说,我们可以使用一个 override __getattribute__ 方法的对象去代理对象 t 的所有方法,实现一个简单的对象代理:

好像的确可行,但是

重新整理一下思路,> 对去调用对象的 __gt__ 方法,而 __getattribute__ 会去截获属性寻找的过程,返回 t 对象的 __gt__ 方法,所以这种问题应该是前提出现了偏差

根据错误信息可以知道 __getattribute__ 没起作用,翻阅文档可知

Called unconditionally to implement attribute accesses for instances of the class. If the class also defines __getattr__(), the latter will not be called unless __getattribute__() either calls it explicitly or raises an AttributeError. This method should return the (computed) attribute value or raise an AttributeError exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.__getattribute__(self, name).

正题

那么如何正确地实现一个对象的代理呢?其实 __getattribute__ 也可以,不过要在 Proxy 类中也显示的定义 __gt__ 等 special method。但是 __getattribute__ 在编程时要极为留意,避免 maximum recursion depth exceeded,还是 __getattr__ 更加 friendly

Celery 源代码中有一个现成的实现(她自己声称是 stolen from werkzeug.local.Proxy)

def _default_cls_attr(name, type_, cls_value):

# Proxy uses properties to forward the standard

# class attributes __module__, __name__ and __doc__ to the real

# object, but these needs to be a string when accessed from

# the Proxy class directly. This is a hack to make that work.

# -- See Issue #1087.

def __new__(cls, getter):

instance = type_.__new__(cls, cls_value)

instance.__getter = getter

return instance

def __get__(self, obj, cls=None):

return self.__getter(obj) if obj is not None else self

return type(bytes_if_py2(name), (type_,), {

'__new__': __new__, '__get__': __get__,

})

class Proxy(object):

"""Proxy to another object."""

# Code stolen from werkzeug.local.Proxy.

__slots__ = ('__local', '__args', '__kwargs', '__dict__')

def __init__(self, local,

args=None, kwargs=None, name=None, __doc__=None):

object.__setattr__(self, '_Proxy__local', local)

object.__setattr__(self, '_Proxy__args', args or ())

object.__setattr__(self, '_Proxy__kwargs', kwargs or {})

if name is not None:

object.__setattr__(self, '__custom_name__', name)

if __doc__ is not None:

object.__setattr__(self, '__doc__', __doc__)

@_default_cls_attr('name', str, __name__)

def __name__(self):

try:

return self.__custom_name__

except AttributeError:

return self._get_current_object().__name__

@_default_cls_attr('qualname', str, __name__)

def __qualname__(self):

return self._get_current_object().__qualname__

@_default_cls_attr('module', str, __module__)

def __module__(self):

return self._get_current_object().__module__

@_default_cls_attr('doc', str, __doc__)

def __doc__(self):

return self._get_current_object().__doc__

def _get_class(self):

return self._get_current_object().__class__

@property

def __class__(self):

return self._get_class()

def _get_current_object(self):

"""Get current object.

This is useful if you want the real

object behind the proxy at a time for performance reasons or because

you want to pass the object into a different context.

"""

loc = object.__getattribute__(self, '_Proxy__local')

if not hasattr(loc, '__release_local__'):

return loc(*self.__args, **self.__kwargs)

try: # pragma: no cover

# not sure what this is about

return getattr(loc, self.__name__)

except AttributeError: # pragma: no cover

raise RuntimeError('no object bound to {0.__name__}'.format(self))

def __dict__(self):

return self._get_current_object().__dict__

except RuntimeError: # pragma: no cover

raise AttributeError('__dict__')

def __repr__(self):

obj = self._get_current_object()

return '<{0} unbound>'.format(self.__class__.__name__)

return repr(obj)

def __bool__(self):

return bool(self._get_current_object())

return False

__nonzero__ = __bool__ # Py2

def __dir__(self):

return dir(self._get_current_object())

return []

def __getattr__(self, name):

if name == '__members__':

return getattr(self._get_current_object(), name)

def __setitem__(self, key, value):

self._get_current_object()[key] = value

def __delitem__(self, key):

del self._get_current_object()[key]

def __setslice__(self, i, j, seq):

self._get_current_object()[i:j] = seq

def __delslice__(self, i, j):

del self._get_current_object()[i:j]

def __setattr__(self, name, value):

setattr(self._get_current_object(), name, value)

def __delattr__(self, name):

delattr(self._get_current_object(), name)

def __str__(self):

return str(self._get_current_object())

def __lt__(self, other):

return self._get_current_object() < other

def __le__(self, other):

return self._get_current_object() <= other

# omit some special method

另外说一点,使用 _default_cls_attr 而不用 property 装饰器 可以参考 issue 1087

从 class 访问 property 会返回 property 的实例

原因貌似好像是这个 (依据等价实现)

所以 Celery 自己搞了一个 descriptor

喜欢的话关注收藏评论转发比心么么哒!Python学习交流群330637182内有大量的项目开发和新手教学视频五千人大群等着你来加入

Python程序员最常犯的10个错误,你中招了吗? 营销视频课程

img

街角

关注

大数据文摘作品

编译:什锦甜、Gao Ning、小鱼

Python简介

Python是一种具有动态语义的、面向对象的解释型高级编程语言。因其内置了高级数据结构,并支持动态类型和动态绑定,使用Python进行快速应用程序开发十分便利。同时作为一门脚本语言,它兼容部分现有的组件和服务。Python还支持模块和各种库的扩展,有助于实现模块化编程和提高代码复用率。

关于本文

刚接触这门语言的新手可能会对Python简洁灵活的语法有些不适应,或是低估了Python强大的性能。鉴于此,本文列出了Python开发人员常犯的10个小错误,资深程序猿也难免会中招哦。

本文供Python高级开发人员参考,Python小白可以参考下面这篇文章:

http://onlamp/pub/a/python/2004/02/05/learn_python.html

常见错误1:滥用表达式作为函数参数的默认值

Python允许开发者指定函数参数的默认值,这也是Python的一大特色,但当默认值可变时,可能会给开发者带来一些困扰。例如下面定义的函数:

>>> def foo(bar=[]): # bar is optional and defaults to [] if not specified... bar.append("baz") # but this line could be problematic, as we'll see...... return bar

看出bug了吗?那就是在每次调用函数前没有对可变参数进行赋值,而认为该参数就是默认值。比如上面的代码,有人可能期望在反复调用foo()时返回'baz',以为每次调用foo()时,bar的值都为[],即一个空列表。

但是,让我们来看看代码运行结果:

>>> foo()["baz"]>>> foo()["baz", "baz"]>>> foo()["baz", "baz", "baz"]

嗯?为什么每次调用foo()后会不断把"baz"添加到已有的列表,而不是新建一个新列表呢?答案就是,函数参数的默认值仅在定义函数时执行一次。因此,仅在第一次定义foo()时,bar初始化为默认值(即空列表),此后,每次调用foo()函数时,参数bar都是第一次初始化时生成的列表。

常见的解决方案:

>>> def foo(bar=None):... if bar is None: # or if not bar:... bar = []... bar.append("baz")... return bar...>>> foo()["baz"]>>> foo()["baz"]>>>foo()["baz"]

常见错误2:错误地使用类变量

代码示例:

>>> class A(object):... x = 1...>>> class B(A):... pass...>>> class C(A):... pass...>>> print A.x, B.x, C.x1 1 1

运行结果没问题。

>>> B.x = 2>>> print A.x, B.x, C.x1 2 1

结果也正确。

>>> A.x = 3>>> print A.x, B.x, C.x3 2 3

什么鬼?我们只改变了A.x.,为什么C.x 也变了?

在Python中,类变量是以字典形式进行内部处理,遵循方法解析顺序(Method Resolution Order ,MRO)。因此,在上述代码中,因为在类C中没有找到属性x,它就会从父类中查找x的值(尽管Python支持多重继承,但上述代码只存在一个父类A)。换句话说,C没有独立于类A的属于自己的x。因此,C.x实际上指的是A.x。除非处理得当,否则就会导致Python出现错误。

如果想更深入了解Python的类特性,请戳:

https://toptal/python/python-class-attributes-an-overly-thorough-guide

常见错误3:错误指定异常代码块的参数

假设你有如下代码:

>>> try:... l = ["a", "b"]... int(l[2])... except ValueError, IndexError: # To catch both exceptions, right?... pass...Traceback (most recent call last):File "", line 3, in IndexError: list index out of range

这里的问题是except语句不接受以这种方式指定的异常列表。在Python2.x中,except Exception语句中变量e可用来把异常信息绑定到第二个可选参数上,以便进一步查看异常的情况。因此,在上述代码中,except语句并没有捕捉到IndexError异常;而是将出现的异常绑定到了参数IndexError中。

想在一个except语句同时捕捉到多个异常的正确方式是,将第一个参数指定为元组,并将要捕捉的异常类型都写入该元组中。为了方便起见,可以使用as关键字,Python 2 和Python 3都支持这种语法格式:

>>> try:... l = ["a", "b"]... int(l[2])... except (ValueError, IndexError) as e: ... pass...>>>

常见错误4:错误理解Python中变量的作用域

Python变量作用域遵循LEGB规则,LEGB是Local,Enclosing,Global,Builtin的缩写,分别代表本地作用域、封闭作用域、全局作用域和内置作用域,这个规则看起来一目了然。事实上,Python的这种工作方式较为独特,会导致一些编程错误,例如:

>>> x = 10>>> def foo():... x += 1... print x...>>> foo()Traceback (most recent call last):File "", line 1, in File "", line 2, in fooUnboundLocalError: local variable 'x' referenced before assignment

问题出在哪?

上面的错误是因为在作用域内对变量赋值时,Python自动将该变量视为该作用域的本地变量,并对外部定义的同名变量进行了屏蔽。因此,原本正确的代码,在某个函数内部添加了一个赋值语句后,却意外收到了UnboundLocalError的报错信息。

关于UnboundLocalError更多内容请戳:

https://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value

在使用列表时,Python程序员更容易掉入此类陷阱,例如:

>>> lst = [1, 2, 3]>>> def foo1():... lst.append(5) # This works ok......>>> foo1()>>> lst[1, 2, 3, 5]>>> lst = [1, 2, 3]>>> def foo2():... lst += [5] # ... but this bombs!...>>> foo2()Traceback (most recent call last):File "", line 1, in File "", line 2, in fooUnboundLocalError: local variable 'lst' referenced before assignment

奇怪,为什么foo1正常运行,而foo2崩溃了呢?

原因和上一个案例中出现的问题相似,但这里的错误更加细微。函数foo1没有对变量lst进行赋值操作,而函数foo2有赋值操作。

首先, lst += [5]是lst = lst + [5]的缩写形式,在函数foo2中试图对变量lst进行赋值操作(Python将变量lst默认为本地作用域的变量)。但是,lst += [5]语句是对lst变量自身进行的赋值操作(此时变量lst的作用域是函数foo2),但是在函数foo2中还未声明该变量,所以就报错啦!

常见错误5:在遍历列表时修改列表

下面代码中的错误很明显:

>>> odd = lambda x : bool(x % 2)>>> numbers = [n for n in range(10)]>>> for i in range(len(numbers)):... if odd(numbers[i]):... del numbers[i] # BAD: Deleting item from a list while iterating over it...Traceback (most recent call last):File "", line 2, in IndexError: list index out of range

有经验的程序员都知道,在Python中遍历列表或数组时不应该删除该列表(数组)中的元素。虽然上面代码的错误很明显,但是在编写复杂代码时,资深程序员也难免会犯此类错误。

幸好Python集成了大量经典的编程范式,如果运用得当,可以大大简化代码并提高编程效率。简单的代码会降低出现上述bug的几率。列表解析式(list comprehensions)就是利器之一,它将完美避开上述bug,解决方案如下:

>>> odd = lambda x : bool(x % 2)>>> numbers = [n for n in range(10)]>>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all>>> numbers[0, 2, 4, 6, 8]

更多有关列表解析式的详细内容,请戳:https://docs.python.org/2/tutorial/datastructures.html#tut-listcomps

常见错误6:不理解Python闭包中的变量绑定

代码示例:

>>> def create_multipliers():... return [lambda x : i * x for i in range(5)]>>> for multiplier in create_multipliers():... print multiplier(2)...

你以为运行结果会是:

02468

但实际输出结果是:8

8888

惊不惊喜!

这种情况是由于Python延迟绑定(late binding)机制造成的,也就是说只有在内部函数被调用时才会搜索闭包中变量的值。所以在上述代码中,每次调用create_multipliers()函数中的return函数时,会在附近作用域中查询变量i的值。(此时,return中循环已结束,所以i值为4)。

常见解决方案:

>>> def create_multipliers():... return [lambda x, i=i : i * x for i in range(5)]...>>> for multiplier in create_multipliers():... print multiplier(2)...02468

没错!我们利用了匿名函数lambda的默认参数来生成结果序列。有人觉得这种用法很简洁,有人会说它很巧妙,还有人会觉得晦涩难懂。如果你是Python开发人员,那么深刻理解上述语法对你而言非常重要。

常见错误7:模块之间出现循环依赖

假设你有两个文件,分别是a.py和b.py,两者相互导入,如下所示:

a.py模块中的代码:

import bdef f():return b.xprint f()

b.py模块中的代码:

import ax = 1def g():print a.f()

首先,我们尝试导入a.py:

>>> import a1

运行结果正确!这似乎有点出人意料,因为我们在这里进行循环导入,应该会报错呀!

答案是,在Python中如果仅存在一个循环导入,程序不会报错。如果一个模块已经被导入,Python会自动识别而不会再次导入。但是如果每个模块试图访问其他模块不同位置的函数或变量时,那么Error又双叒叕出现了。

回到上面的示例中,当导入a.py模块时,程序可以正常导入b.py模块,因为此时b.py模块未访问a.py中定义任何的变量或函数。b.py模块仅引用了a.py模中的a.f()函数。调用的a.f()函数隶属于g()函数,而a.py或b.py模块中并没有调用g()函数。所以程序没有报错。

但是,如果我们在未导入a.py模块之前先导入b.py模块,结果会怎样?

>>> import bTraceback (most recent call last):File "", line 1, in File "b.py", line 1, in import a File "a.py", line 6, in print f() File "a.py", line 4, in f return b.xAttributeError: 'module' object has no attribute 'x'

报错了!问题在于,在导入b.py的过程中,它试图导入a.py模块,而a.py模块会调用f()函数,f()函数又试图访问b.x变量。但此时,还未对变量b.x进行定义,所以出现了AttributeError异常。

稍微修改下b.py,即在g()函数内部导入a.py就可以解决上述问题。

修改后的b.py:

x = 1def g():

import a # This will be evaluated only when g() is calledprint a.f()

现在我们再导入b.py模块,就不会报错啦!

>>> import b>>> b.g()1 # Printed a first time since module 'a' calls 'print f()' at the end1 # Printed a second time, this one is our call to 'g'

常见错误8:文件命名与Python标准库模块的名称冲突

Python的优势之一就是其集成了丰富的标准库。正因为如此,稍不留神就会在为自己的文件命名时与Python自带标准库模块重名。例如,如果你的代码中有一个名为email.py的模块,恰好就和Python标准库中email.py模块重名了。)

上述问题比较复杂。举个例子,在导入模块A的时候,假如该模块A试图导入Python标准库中的模块B,但你已经定义了一个同名模块B,模块A会错误导入你自定义的模块B,而不是Python标准库中的模块B。这种错误很糟糕,因为程序员很难察觉到是因为命名冲突而导致的。

因此,Python程序员要注意避免与Python标准库模块的命名冲突。毕竟,修改自己模块的名称比修改标准库的名称要容易的多!当然你也可以写一份Python改善建议书(Python Enhancement Proposal,PEP)提议修改标准库的名称。

常见错误9:不熟悉Python2和Python3之间的差异

先来看看foo.py文件中的代码:

import sysdef bar(i):if i == 1: raise KeyError(1) if i == 2: raise ValueError(2)def bad(): e = None try: bar(int(sys.argv[1])) except KeyError as e: print('key error') except ValueError as e: print('value error') print(e)bad()

在Python 2中,上述代码运行正常

$ python foo.py 1key error1$ python foo.py 2value error2

但是在Python 3中运行时:

$ python3 foo.py 1key errorTraceback (most recent call last):File "foo.py", line 19, in bad() File "foo.py", line 17, in bad print(e)UnboundLocalError: local variable 'e' referenced before assignment

什么情况?原来,在Python 3中,在except代码块作用域外无法访问异常对象。(原因是,Python 3会将内存堆栈中的循环引用进行保留,直到垃圾回收...

Pycharm中pythonConsole无法打开之解决 公司视频课程

img

蝶音

关注

文/爱琳玩python

大家好,这是我今天写的第一篇关于我在玩python中时遇到的问题,并最终解决了的文章,文笔很差,还请各位能多多包涵!话不多说,进入主题,在调试python代码中,我先目前使用的是Pycharm这款编辑器,这也是我在选择之前,看了很多入行的小白说的最好新手用Pycharm.因为它能帮你自动补全!当然这是作为小白的我个人的看点!

当然在有时调用代码时,你拿不准代码是否正确,这个时候你就可以调用Pycharm中的pythonConsole,对这个时候的我调用时,就出现报错:

AttributeError: 'PyDevTerminalInteractiveShell' object has no attribute 'has_readline'

这是什么东东啊!作为小白的我看到这个时,心里是非常的不舒服的,于是乎开始了度娘历险记,终于被我给找到了:这个问题源于pycharm version>2016.1与ipython version 5冲突。

怎么解决,成了我这个小白的当务之急,对了这里我的系统是Windows7的系统,python则是python3!

pip uninstall ipython

pip install ipython==4.2.0

然后你重新运行后就可以解决Pycharm中PythonConsole打开问题了!

运行之后的界面

最后,爱琳还是希望能帮到那些与我遇到同样问题的朋友,大家一起快快乐乐的玩python!

img

TOP