用python计算折扣率 python商品打折问题

您所在的位置:网站首页 python计算折扣 用python计算折扣率 python商品打折问题

用python计算折扣率 python商品打折问题

2024-06-23 18:22| 来源: 网络整理| 查看: 265

下面是python特性笔记,废话不多说了,加油!!!!

python中的断言

Python中的断言是一种调试工具,用来测试某个断言条件,若断言条件为真,继续继续正常执行,若条件为假,则引发AssertionError异常并显示相关错误消息

#商品打折代码 def apply_discount(product, discount): price = int(product['price'] * (1.0 - discount)) assert 0 >> from my_module import * >>> external_func() 23 >>> _internal_func() NameError: "name '_internal_func' is not defined" #出错,无法是被该函数,应为带有前置下划线

应该避免通配符导入,会导致名称空间的混淆,最好使用常规导入方法,不会受到前置单下划线的命名约定影响

后置单下划线:var_:变量名可能是python中的关键词,这是使用后置单下划线可以避免逻辑冲突def make_object(name, class): SyntaxError: "invalid syntax" def make_object(name, class_): pass

前置双下划线:__var:双下划线可重写属性名称,避免子类的命名冲突,成为名称改写(name mangling)class Test(): def __init__(self): self.foo=11 self._bar=23 self.__baz=42 class ExtendedTest(Test): def __init__(self): super.__init__() self.foo=220 self._bar=330 self.__baz=1 '''此时查看ExtendedTest时,会发现,foo,和_bar变量被修改了,但是__baz变量没有被修改,为了防止以外的变动,__baz变成了_ExtendedTest__baz,但是_Test__baz依然存在,相当于定义了两个不同的变量属性 '''class ManglingTest: def __init__(self): self.__mangled = 'hello' def get_mangled(self): return self.__mangled ManglingTest().get_mangled() 'hello' ManglingTest().__mangled AttributeError: "'ManglingTest' object has no attribute '__mangled'" #---------------------------------------------------------------------- _Var__ible=42 '''此处定义了全局变量,在使用时__ible被扩展成_Var__ible,调用时,变成调用了全局变量''' class Var(): def test(self): return __ible print(Var().test())

前后双下划线:var

双下划线称为魔法方法,最好在命名时避免以双下划线开头与结束

单下划线:_

单下划线有时用作名称,来表示变量时临时的或无关紧要的,单下划线知识一个有效的变量名,有时用作占位符

color=('red','yellow','green','pink') a,_,_,d=color print(a) print(d)

除了用作临时变量外,大多数表示解释器计算的上一个表达式的结果

#实时构建对象 list() _.append(1) _.append(2)

关键要点前置单下划线_var:命名约定,用来表示该名称仅在内部使用,一般对python解释器没有特殊含义(通配符导入除外)只作为程序员的提示后置单下划线:命名约定,用于避免与python关键字发生冲突前置双下划线:在环境中使用时会引发名称改写,对python解释器有特殊含义前后双下划线:表示python语言定义的特殊方法单下划线:有时用作临时或无意义变量名称,还可以表示上一个会话的结果字符串格式化新式格式化在字符串对象上调用format()函数 name='bob' age=18 print("my name is {name},my age is {age:x}".format(name='bob',age=18)) python3.6增加了格式化字符串字面值的新式格式化方法 name='bob' age=18 print(f"my name is {name}") python还有一种方法叫做模板字符串(template string) 此方法不太常用,涉及到用户输入格式化字符串时,设计安全问题可使用

如何选择字符串格式化方法:

如果格式字符串时用户提供的,使用模板字符串避免安全问题考虑python版本,3.6+使用字符串字面值插入值,老版本使用新是字符串格式化方法即可关键要点python格式化字符串不止一种方法选择时取决具体情况难以选择时,看上方总结python之禅import this '''The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those''' '''美丽好过丑陋, 浅显好过隐晦, 简单好过复合, 复合好过复杂, 扁平好过嵌套, 稀疏好过密集, 可读性最重要, 即使祭出实用性为理由,特例也不可违背这些规则。 不应默认包容所有错误,得由人明确地让它闭嘴! 面对太多的可能,不要尝试猜测,应该有一个(而且是唯一)直白 的解决方法。 当然,找到这个方法不是件容易的事,谁叫你不是荷兰人呢! 但是,现在就做永远比不做要好。 若实现方案很难解释,那么它就不是一个好方案;反之也成立! 名称空间是个绝妙想法——现在就来共同体验和增进这些吧'''函数def yell(context): return context.upper()+"!" yell("hello")

由于yell函数是python的一个对象,因此可以分配给另一个变量

bark=yell

即便删除yell函数,bark照样运行

del yell bark("wolf")

python在创建函数时,为每一个函数附加一个用于调试的字符串标识符,使用__name__属性可以访问这个内部标识符

def yell(context): return context.upper()+"!" yell("hello") bark=yell print(bark.__name__)

返回的结果为yell

指向函数的变量和函数本身是彼此独立的

函数存放在数据结构中funcs=[yell,str.upper,str.capitalize] for f in funcs: print(f,f("hello world")) ''' HELLO WORLD! HELLO WORLD Hello world'''

存储在列表中的函数对象可以直接调用,无需实现分配变量

函数可传递给其他函数def greeting(function): words=function("hellO") return words greeting(yell)

能够接受函数作为参数的函数叫做高阶函数

map函数时python内置高阶函数,map接受一个函数对象和一个可迭代对象,然后在每个可迭代对象中的每个元素上调用该函数

list(map(yell,['hello','dog']))

函数可以嵌套def speak(contents): def low(t): return t.upper()+"!" return low(contents) speak('hello') def get_speak_func(num): def low(contents): print(contents.lower()+"!") def up(contents): print(contents.upper()+"!") if num > 1: return low if num 0.5: return yell else: return whisper

yell与whisper函数并没有参数,但是还可以访问外部函数的参数,捕捉并记住了参数的值

拥有这种行为的函数称为词法闭包(lexical closure),简称闭包

def add_func(x1): def inner_func(x2): return x1+x2 return inner_func p1=add_func(2) p1(2)

add_func作为工厂函数来创建和配置各种inner_func,内部函数可访问外部函数种位于封闭作用域的参数

对象可作为函数使用class Adder(): def __init__(self,x1): self.x1=x1 def __call__(self,x2): return self.x1+x2 add1=Adder(2) add1(2)

如果一个对象可调用,意味着可使用圆括号调用语法,可传参数,在类种都是由__call__双下划线方法实现的, 像函数一样调用一个对象实例实际上是尝试执行该对象的__call__方法

关键要点python中的一切皆为对象,函数也不例外,可将函数分配给变量或存储在数据结构中,作为头灯对象,函数可以传递给其他函数或作为其他函数的返回值头等函数的特性可以用来抽象并传递程序中的行为对象可以被设置为可调用的,可将其视为函数对待lambda单表达式函数

语法 lambda 参数 :表达式

a=lambda x,y : x+y a(2,3) (lambda c,d : c**d)(2,3)

lambda函数不必将函数对象与名称绑定,只需在lambda中创建一个想要执行的表达式,像普通函数一样调用即可

lambda函数执行时会计算其中的表达式,然后自动返回表达式的结果,所以其中有一个隐式的返回表达式

关键要点lambda函数是单表达式函数,不必与名称绑定(匿名函数)lambda函数不能使用普通的python语句,其中lambda函数总是隐式的包含一个return语句使用lambda函数时不要过于频繁的使用,避免代码的繁琐性装饰器

python装饰器可临时扩展或修改可调用对象的行为,同事不会永久修改可调用对象本身

装饰器可定义可重用的代码块,改变或扩展其他函数行为,函数的行为只有在装饰后才会改变

在函数定义之前放上@语法糖等于先定义函数,再运行这个装饰器

使用@语法时,会在定义是立即修饰函数

#装饰器函数 def up(func): def inner_func(): old=func() new=old.upper() print("inner_func running.....") return new return inner_func @up #被装饰函数 def strIng(): return "hello" strIng()

调研被修饰函数时会被装饰函数中的新函数所包装,进而改变被修饰函数的行为,而不必再被修饰函数中添加任何功能

装饰器通过闭包来修改可调用对象的行为,因此无需永久性的修改原对象,元可调用对象的行为仅在装饰时才会改变

将多个装饰器应用于一个函数#装饰器函数 def strong(func): def wrapper(): return ""+func()+"" return wrapper def emp(func): def wrapper(): return ""+func()+"" return wrapper @strong @emp def greet(): return "hello" greet()

装饰含参函数def proxy(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper

wrapper闭包中定义使用了*和**操作符受极所有位置参数和关键字参数,并存储在args与kwargs中然后wrapper闭包使用*和**参数解包操作符将收集的的参数转发到原输入函数(被修饰函数中)def trace(func): def wrapper(*args,**kwargs): print(f'Tracing:Calling {func.__name__}()' f'with {args},{kwargs}') original_result=func(*args,**kwargs) print(f'Tracing :{func.__name__}() is working ' f'Tracing returned {original_result}') return wrapper @trace def say(name,word): return f'{name} is saying {word}' say("Namcy","HEllo")

编写可调式的装饰器

import functools

使用functools.wrap(被装饰函数)的方法可将原函数中的文档字符串和其他元数据复制到装饰器中

必须在装饰器函数的新函数之前使用@functools.wraps(func)的方式定义

#追踪函数参数的装饰器 import functools def trace(func): @functools.wraps(func) def wrapper(*args,**kwargs): print(f'Tracing:Calling {func.__name__}()' f'with {args},{kwargs}') original_result=func(*args,**kwargs) print(f'Tracing :{func.__name__}() is working ' f'Tracing returned {original_result}') return wrapper @trace def say(name,word): return f'{name} is saying {word}' say("Namcy","HEllo") print(say.__name__)关键要点装饰器定义可重用的组件,可以将其应用于可调用对象修改其行为,同时无需永久修改被修饰函数本身的行为@语法在输入函数上调用装饰器的简写,在单个函数上使用时,注意装饰器的顺序为了方便调试,在自己的装饰器中使用functools.wraps将被装饰对象中的元数据转移到装饰后的对象中*args和**kwargs

非常重要的一点是args和kwargs知识一个标识而已,换成其他名称也是可以

关键要点*args和**kwargs用于在python中编写变长参数的函数*args收集额外的位置参数组成元组,**kwargs收集额外的关键字参数组成字典实际起作用的语法是*和**,*args和kwargs只是一种约定俗成函数参数解包lst=[1,2,3] tup=(4,5,6) dct={'x':1,'y':5,'z':9} def print_thredim(x,y,z): print(""%(x,y,z)) print_thredim(1,2,3) print_thredim(*lst) print_thredim(*tup) print_thredim(**dct)

参数解包,使得在数据结构中的元素称为一个独立的位置参数,传递到函数之中

关键要点两个星号操作符可用于从序列和字典中解包函数参数高效的使用参数解包有助于为模块和函数编写更灵活的接口返回空值

python在所有函数的末尾添加了return None语句,即如果没有指定函数返回值,则返回None

关键要点如果函数没有指定返回值,则返回None,否则明确的返回None是分格问题返回值是python的核心功能,显式的return None语句能更清晰的表达代码的意图is和==的区别当两个变量指向同一个变量时,is表达式的结果是True当各变量指向的对象含有相同的内容时,==表达式的结果为True字符串转换class Car(): def __init__(self,color,brand): self.color=color self.brand=brand def __str__(self): return f'a {self.color} car with brand is {self.brand}' car=Car('red','baishijie') print(car)

字符串函数__str__方法相当于print功能

python解释器会话中查看对象得到的是对象的__repr__结果

import datetime today=datetime.datetime.today() print(today) str(today) repr(today)

repr函数更多是帮助开发人员调试程序

自定义异常类自定义的异常类一般继承Exception或是某个具体的异常def validate(name): if len(name) < 10: raise NameTooShortError(name) class BaseValidationError(ValueError): pass class NameTooShortError(BaseValidationError): pass class NameTooLongError(BaseValidationError): pass class NameTooCuteError(BaseValidationError): pass try: validate(name) except BaseValidationError as err: handle_validation_error(err)

自定义异常类结构化异常结构可以优化代码问题的解决

=关键要点定义自己的异常类型让代码清晰表达自己的意图,易于调试要从【python内置的Exception类或特定的异常类派生处自定义异常可以使用继承来根据逻辑对异常分组,组成层次结构克隆对象浅复制:是指构建一个新的容器对象,然后填充原对象中子对象的引用,浅堵制只执行一层,复制过程不会递归,因此不会创建子对象的副本深复制:递归复制,首先构造一个新的容器对象,然后递归填充原始对象中的子对象的副本,遍历整个对象树,以此来创建原对象以及所有子项的完全独立副本制作浅对象:lst=[['x','y','z',],['a','b','c'],['w','r','t']] n_lst=list(lst) print(lst) print(n_lst) lst.append(['new element']) print(lst) print(n_lst) lst[1]=['a','y','u'] print(lst) print(n_lst) lst[1][1]=23 print(lst) print(n_lst) '''显示结果如下: [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't'], ['new element']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 23, 'c'], ['w', 'r', 't'], ['new element']] [['x', 'y', 'z'], ['a', 23, 'c'], ['w', 'r', 't']] '''

可以看出,浅复制只复制了原对象的一层,对于原对象的子对象并没有复制,当要获得子对象时,还是会引用原对象的子对象,当只对第一层对象添加或减少时,不会影响副本,但是对子对象添加或修改时,会影响到副本中的子对象**

深复制import copy lst=[['x','y','z',],['a','b','c'],['w','r','t']] n_lst=copy.deepcopy(lst) print(lst) print(n_lst) lst.append(['new element']) print(lst) print(n_lst) lst[1][1]=23 print(lst) print(n_lst) '''显示结果如下: [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't'], ['new element']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] [['x', 'y', 'z'], ['a', 23, 'c'], ['w', 'r', 't'], ['new element']] [['x', 'y', 'z'], ['a', 'b', 'c'], ['w', 'r', 't']] '''

深复制会复制原对象的所有子对象,递归的复制所有内容

任何对原对象的操作都不会对副本产生任何影响

copy模块的copy函数是浅复制,deepcopy为深复制当要浅复制时,使用工厂函数即可,无需使用copy函数复制任意对象import copy class Point(): def __init__(self,x,y): self.x=x self.y=y def __repr__(self): return(f'Point({self.x!r},{self.y!r})') #p1=copy.copy(p) #print(p) #print(p1) class Rectangle(): def __init__(self,left,right): self.left=left self.right=right def __repr__(self): return (f'Rectangle({self.left!r},{self.right!r})') rect=Rectangle(Point(2,3),Point(3,4)) n_rect=copy.copy(rect) #浅复制对象 print(rect) print(n_rect) rect.left.x=23 #对原对象的子对象进行更改,结果表示副本的子对象变动,因为是浅复制 print(rect) print(n_rect) '''显示结果如下: Rectangle(Point(2,3),Point(3,4)) Rectangle(Point(2,3),Point(3,4)) Rectangle(Point(23,3),Point(3,4)) Rectangle(Point(23,3),Point(3,4))''' d_rect=copy.deepcopy(rect) #对原对象进行深复制 print(d_rect) print(rect) rect.right.y=100 #改变原对象的子对象,副本中的子对象不受影响,因为是深复制 print(rect) print(d_rect) '''显示结果如下: Rectangle(Point(2,3),Point(3,4)) Rectangle(Point(2,3),Point(3,4)) Rectangle(Point(2,3),Point(3,100)) Rectangle(Point(2,3),Point(3,4)'''

关键要点创建的浅副本不会克隆原对象的子对象,因此副本和原对象并不完全独立对象的深副本将递归克隆原对象的子对象,副本完全独立于原对象,但创建深副本的速度较慢使用copy模块可以复制任意对象(包括自定义类)namedtuple命名元组from collections import namedtuple Car=namedtuple('Car',['brand','color']) print(Car) my_car=Car('baoshijie','red') print(my_car.brand) print(my_car.color) my_car._asdict my_car._replace(color='yellow') Car._make(['yellow','999'])

namedtuple也是不可变类型可以快速创建不可变类同样适合解包操作namedtuple的第一个参数是typename,作为创建的类名称第二个参数有以下两种形式:

Car=namedtuple('Car',['brand','color']) Car=namedtuple('Car','brand color') #此种形式当使用namedtuple时自动调用split()函数解析参数namedtuple的一些方法:_asdict方法:以字典类型返回_replace方法:替换namedtuple中的参数值_make方法:创建新的类关键要点:collection.namedtuple能方便的在python中手动定义一个内存占用较少的不可变类使用namedtuple能够按照更易理解的结构组织数据,进而简化代码namedtuple提供了一些辅助方法,虽然这些方法以单下划线开头,但是确实公共接口的一部分,可正常使用,以单下划线开头时避免与用户命名发生冲突类变量与实例变量类变量不受特定实例变量的影响,反过来,对类变量的改变,会影响到所有实例变量的内容类变量存储在类本身中,实例变量只是存储在特定实例对象中实例变量的改变不会影响到大环境,只会作用于特定的实例对象上class Dog(): num_legs=4 def __init__(self,name): self.name=name jack=Dog("jack") mike=Dog("Mike") print(jack.name) print(mike.name) print(Dog.num_legs) jack.num_legs=10 print(jack.num_legs) print(mike.num_legs) print(jack.__class__.num_legs)

类变量是针对类的,与特定的实例对象无关

类本身不可调用实例对象属性

实例变量是特定的实例的,在创建实例对象时,调用__init__函数实现,不位于类本身中

在修改特定实例对象时,若创建了与类变量同名的变量时,会覆盖类变量,调用实例对象的新的属性,但是类变量未改变

class CounterClasObj(): _cla_counter=0 def __init__(self): self.__class__._cla_counter+=1 a=CounterClasObj() b=CounterClasObj() c=CounterClasObj() print(CounterClasObj._cla_counter)

注意类变量会被新创建的实例对象的同名属性所覆盖

关键要点类变量用于类的所有实例之间共享数据,类变量属于一个类,类的所有实例共享类变量,而不是属于某一个特定的实例对象实例变量时特定于每个实例的数据,属于单个对象实例,不与类共享实例对象属性,每个实例变量都针对特定实例单独存储一份数据类变量可以被同名的实例变量所覆盖,会出现bug与奇怪的行为实例方法。类方法和静态方法class A(): def method(self): print("instance method called") @classmethod def classmethod(cls): print("class method called",cls) @staticmethod def staticmethod(): print("static method called")

实例方法接受参数self,实例方法通过self可以自由访问该对象的其他属性与方法,可以修改对象的状态实例方法还可以通过self.__class__属性访问类本身,即实例方法可以修改类状态类方法接收参数cls,无法修改实例的状态静态方法,不接受self和cls参数,但可以接受其他任意数量的参数class A(): def method(self): print("instance method called") @classmethod def classmethod(cls): print("class method called",cls) @staticmethod def staticmethod(): print("static method called") obj=A() obj.method() obj.classmethod() obj.staticmethod() #A.method(obj)当生成实例对象时,是把实例对象的名称传递到self中,所以可以直接使用类.method(实例对象名)即可) A.classmethod() A.staticmethod() #A.method()

实例对象可调用类方法

类对象不可以调用实例方法

类对象与实例对象均可调用静态方法

class Pizaa(): def __init__(self,ingre): self.ingre=ingre def __repr__(self): return f'Pizaa({self.ingre!r})' @classmethod def Pizaa1(cls): return cls(["potatom","tomato"]) @classmethod def Pizaa2(cls): return cls(["A","b"]) print(Pizaa.Pizaa1()) print(Pizaa.Pizaa2())

通过此种工厂函数可以创建多个类对象,通过类方法可以按需添加格外的构造函数

import math class Pizza(): def __init__(self,redius,ingridents): self.redius=redius self.ingridents=ingridents def __repr__(self): return f'Pizza({self.redius!r},{self.ingridents})' def area(self): return self.staticmethod(self.redius) @staticmethod def staticmethod(r): return r**2*math.pi p1=Pizza(4,["pota"]) p1.area()

使用静态方法和类方法可以传达开发人员的意图,添加静态方法可以避免无用类,有助于测试代码,可以不创建类实例,像普通函数一样测试即可****

关键要点实例方法需要类实例,可通过self访问实例类方法不需要类实例,不能访问实例(self),可通过cls访问类本身静态方法不能访问self和cls,和普通函数一样,但属于类的名称空间静态方法和类方法能展示和贯彻开发人员的设计意图,有助于代码的维护python中常见的数据结构字典from collections import OrderedDict from collections import ChainMap from collections import defaultdict from types import MappingProxyType d=OrderedDict(one=1,two=2,three=3) print(d) print(d.keys()) print(d.items()) #—————————————————————————————————————————————————————— d1=defaultdict(list) #设置默认返回列表类型,当访问的键不存在时,返回空列表(列表中没有值时) print(d1['one']) d1['one']=1 print(d1['one']) print(d1['two']) #—————————————————————————————————————————————————————— dict1={'one':1,'two':2} dict2={'three':3,'four':4} chaindict=ChainMap(dict1,dict2) print(chaindict) print(chaindict['one']) print(chaindict['four']) #—————————————————————————————————————————————————————— dict1={'one':1,'two':2} readdict1=MappingProxyType(dict1) print(readdict1) print(readdict1['one']) readdict1['three']=3 #返回错误信息,只读字典不可添加或修改,可以修改原字典

OrderedDict可以记住加入键的顺序

defaultdict当访问的键不存在时,可以返回默认类型

ChainMap将多个字典组合,但不是组合成一个字典,当访问键值对时,ChainMap在内部从左至右搜索键,知道找到对应的值为止,若无,则返回错误信息

MappingProxyType创建只读字典

关键要点字典时python的核心数据结构内置的dict可以满足大多数情况python的标准库提供了许多要满足特殊需求的字典数组数据结构数组的信息是连续的存储在内存块中的,是连续的数据结构列表:可变的动态数组

python列表可以包含任意数据类型,包括函数,列表中存储的是PyObject指针,指向不同的对象,而数组是直接存放数据本身

2.元组—不可变容器

元组可包含任意数据类型的元素,添加元素会创建新元组

3.array.array—基本类型数组

此类创建的数组是可变的,行为与列表相似,这种数组是单一数据类型的类型数组

4.str—含有Unicode字符的不可变数组

若需要存储任意对象,且其中含有混合数据类型,可选择列表和元组,前者可变后者不可变若存储数值数据并要求排列紧密且注重性能,可使用array,还可以找第三方库集合集合创建时要注意创建空集合时要使用set()构造函数,若使用{}则会引起起义,会创建一个空字典set1=set("alice") set2=set("mkielasd") print(set1.intersection(set2)) set1.add('one') print(set1)

frozenset—不可变集合不可变集合是静态的,只能查询其中的元素set1=frozenset({'1','2','a'}) print(set1) print(type(set1))

collections.Counter—多重集合

背包类型允许在集合中多次出现同一个元素

既要检查元素是否为集合一部分,又要记录元素在集合中出现的次数就可使用该类型

from collections import Counter obj=Counter() dict1={'one':1,'two':2} dict2={'one':3,'four':4} obj.update(dict1) print(obj) obj.update(dict2) print(obj)

关键要点集合是python及其标准库含有的另一种有用且常用的数据结构frozenset对象可散列且可用作字典和集合的键collections.Counter实现多重集合或背包类型的数据栈(后进先出)

栈的插入与删除操作称为入栈(push)和出栈(pop)

列表内置栈数据结构

列表的向前插入元素是一种性能反模式,应尽量避免,若要将列表作为栈,要使用append(),pop()函数,为了获得最佳性能,基于python列表的栈应该向高索引增长并向低索引缩小

collections.deque—快速稳健的栈

deque实现了双端队列,支持O(1)实践从两端添加和移除元素

python的deque对象以双链表实现,插入与删除性能非常好,但是访问栈中间元素性能较差,耗时为O(n)

from collections import deque d=deque() d.append(1) d.append(2) d.append(3) print(d) d.pop() d.pop() d.pop()

关键要点python中有几个栈的实现,每种实现的性能和使用特性略有不同collections.deque提供安全快速的通用栈实现内置列表类型可以作为栈使用,但要小心只能使用append()和pop()函数来添加删除项,以避免性能下降队列(FIFO)

队列是含有一组对象的容器,支持快速插入与删除的先进先出语义,插入与删除称为入队(enqueue)和出队(dequeue)

队列通常不允许随机访问所包含的对象

collections.deque—快速稳健的队列

deque是支持双端队列的,即可从前后删除与插入

from collections import deque d=deque() d.append(1) d.append(2) d.append(3) print(d) d.popleft() d.popleft() d.popleft()

关键要点python核心语言及其标准库含有几种队列实现列表对象可以用作队列,但性能较差,不建议使用collections.deque非常优秀的队列实现,可用作栈和队列循环与迭代

range类型标识不可变数列,内存占用比普通列表少,range对象不是存储数列的每个值,而是充当迭代器实时计算数列的值

可以使用enumerate来生成索引列表值

items=['1','2','3'] for index,item in enumerate(items): print(index,item)关键要点在python中编写C风格循环没有python特色,要尽量避免手动管理循环索引和终止条件python的for循环实际是for-each循环,可直接在容器或序列中的元素上迭代解析式关键要点解析式是python的一个关键特性,理解和应用解析式可以让代码更加pythonic解析式是简单for循环模式的花哨语法糖除了列表解析式外,还有字典以及集合解析式迭代器的实现原理import time class Repeater(): def __init__(self,value): self.value=value def __iter__(self): return RepeaterIterator(self) class RepeaterIterator(): def __init__(self,source): self.source=source def __next__(self): return self.source.value rep=Repeater("Hello") for i in rep: #实现iter=__iter__(rep) print(i) #实现__next__(iter)方法 time.sleep(5) #————————————————————————————————————————迭代器的具体实现 repeater=Repeater("hello") iterator=__iter__(repeater) #创建iterator作为ReperterIterator实例对象,将repeater作为RepeaterIterator的第二个source参数传进去 __next__(iterator) __next__(iterator) #self就是iterator,作为参数传进RepeaterIterator的__next__方法中,return返回iterator.repeater.value的值 #---------------------------------------------------------------------------------迭代器的具体实现

一个类中的迭代器import time class Repeater(): def __init__(self,value): self.value=value def __iter__(self): return self #返回可迭代对象,此处的对象即实例对象 def __next__(self): return self.value #返回可迭代对象的值 rep=Repeater("one") for i in rep: print(i) time.sleep(3)

返回有限次的迭代#迭代器通过异常机制控制代码迭代的运行,看下面的代码: lst=[1,2,3] iters=iter(lst) next(iters) next(iters) next(iters) next(iters) '''显示结果如下: StopIteration Traceback (most recent call last) in () 4 next(iters) 5 next(iters) ----> 6 next(iters) StopIteration:'''

引发了StopIteration异常,表示耗尽了迭代其中所有的值

class BoundedRepeater(): def __init__(self,value,max_repeats): self.value=value self.max_repeats=max_repeats self.count=0 def __iter__(self): return self def __next__(self): if self.count >= self.max_repeats: raise StopIteration self.count+=1 return self.value brep=BoundedRepeater("one",4) for i in brep: print(i) #————————————————————————————————————————迭代器具体实现代码 repeater=BoundedRepeater("one",4) iterator=__iter__(repeater) while True: try: item=next(iterator) except StopIteration: break print(item)

关键要点迭代器为python对象提供了一个序列接口,占用内存较少且具有python特色,来支持for-in循环之美为了支持迭代,都下个需要提供iter和next方法(双下划线)来实现迭代协议基于类的迭代器只是用python编写的可迭代对象的一种方法,可迭代对象还包括生成器和生成器表达式生成器是简化版的迭代器

无限生成器

生成器使用yield将数据传回给调用者

def repeater(value): while True: yield value rep=repeater("i") next(rep) print(rep)

能够停下来的生成器

def boundedrepeater(value,max_repeats): count=0 while True: if count >= max_repeats: return count+=1 yield value boundedrepeater("hi",4) for i in boundedrepeater("hi",4): print(i)

有限次迭代器优化代码

def boundedrepeater(value,max_repeats): for i in range(max_repeats): yield value boundedrepeater("hi",4) for i in boundedrepeater("hi",4): print(i)关键要点生成器函数是一种语法糖,用于编写支持迭代器协议的对象,与编写基于类的迭代其相比,生成器抽象出许多样板代码yield语句用来暂时终止生成器函数的执行并返回值在生成器中,控制流通过yield语句离开会抛出StopIteration异常生成器表达式

生成器表达式能够更方便的编写迭代器,生成器表达式用一行代码定义迭代器****

生成器表达式一经使用不可重用iterator=("helo" for i in range(3)) for a in iterator: print(a)生成器函数即时生成值

生成器基本模式:

genexpr=(expression for item in collection)

扩展生成器模式:

genexpr=(expression for item in collecton if condition)

等效的代码如下:

def gen(): for item in colleciton: if condition: yield item

关键要点生成器表达式与列表解析式类似,但不够再列表对象,而是基于类的迭代器,或生成器函数即时生成值生成器表达式一经使用不可重用生成器表达式最适合简单的实时迭代器,对于复杂的迭代器,最好编写生成器函数或类的迭代器迭代器链def printnum(): for i in range(10): yield i def printnum_(seq): for i in seq: yield i*i def _printnum(seq): for i in seq: yield -i list(_printnum(printnum_(printnum()))) out=(x for x in range (10)) out_=(i*i for i in out ) _out=(-i for i in out_) list(_out)

关键要点生成器可以链接在一起形成高效且可维护的数据处理管道互相链接的生成器会逐个处理链中的每个元素生成器表达式可以用来编写简洁的管道定义,但会降低代码可读性字典技巧

userid_name={ 320:'bob', 230:'mike', 100:'nancy', } def greeting(user_id): print(userid_name.get(user_id,"there"))

get函数作用:当字典中无所访问的键时,使用默认值

关键要点调试包含关系时应避免显示检查字典的键建议使用异常处理机制或get方法排序字典userid_name={ 320:'bob', -230:'mike', 100:'nancy', } sorted(userid_name.items()) sorted(userid_name.items(),key=lambda x: x[1]) sorted(userid_name.items(),key=lambda x: abs(x[0]))

关键要点在创建字典和其他集合的有序视图时,可以通过key函数,决定排序方式key函数时python的一个重要概念函数时python的一等公民,在python中无处不在的强大合并字典userid_name={ 'a':1, 'b':2, 'c':3, } dict2={ 'd':4, 'e':5, 'f':6, } dict4={ 'g':10, 'j':12, 'a':100 } dict3={**userid_name,**dict2,**dict4} print(dict3)

好啦以上就是python特性的笔记啦,希望对小白们有所帮助



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3