Python语法特点总结

2021-01-17  本文已影响0人  睡不醒的大橘
1. Python对象模型
类型对象与实例化对象
>>> int
<class 'int'>
>>> type(int)
<class 'type'>
>>> type(type)
<class 'type'>
>>> int('1')
1
>>> type(1)
<class 'int'>
>>> issubclass(int,object)
True
>>> type(object)
<class 'type'>
>>> issubclass(type, object)
True
函数对象
def func(x, y):
    return x + y

print(type(func))

>>>
<class 'function'>
func = lambda x,y: x + y
print func(3,4)
def print_func_output(f, x, y):
    print(f(x, y))

func = lambda x,y: x + y
f = func
print_func_output(f, 1, 2)

>>>
3
# map()将第一个参数中的函数应用于列表的每一个元素,返回一个迭代器
[2, 4, 6]
>>> list(map((lambda x: x * 2), [1, 2, 3]))

# filter()将第一个参数中的函数应用于列表的每一个元素,过滤掉函数结果为False的元素,返回一个迭代器
>>> list(filter((lambda x: x % 2 == 0), [1, 2, 3, 4, 5])) 
[2, 4] 

# reduce累进地将第一个参数中的函数作用于列表的每一个元素。
>>> from functools import reduce
>>> reduce((lambda x, y: x + y), [1, 2, 3])
6
2. 类型对象与实例对象
类型对象
class Person:
    num = 0

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print('My name is ' + self.name)

    @classmethod
    def get_num(cls):
        return cls.num

    @staticmethod
    def say_hello():
        print('Hello')


for k, v in Person.__dict__.items():
    print(f'{k}:{v}')

>>>  
__module__:__main__
num:0
__init__:<function Person.__init__ at 0x000001EE4E9C12F0>
introduce:<function Person.introduce at 0x000001EE4E9C1378>
get_num:<classmethod object at 0x000001EE4E9BE9B0>
say_hello:<staticmethod object at 0x000001EE4E9BEC50>
__dict__:<attribute '__dict__' of 'Person' objects>
__weakref__:<attribute '__weakref__' of 'Person' objects>
__doc__:None
Person.say_hello()

>>> 
Hello
print(Person.get_num())

>>> 
0
p = Person('Alice', '20')
Person.introduce(p)
p.introduce()


>>>  
My name is Alice
My name is Alice
实例对象
p = Person('Alice', '20')
for k, v in p.__dict__.items():
    print(f'{k}:{v}')
    
>>> 
name:Alice
age:20
class Person:
    name = 'person'
    num = 0

    def __init__(self, name):
        self.name = name

p = Person('Alice')
print(p.name)
print(p.num)

>>> 
Alice
0
属性和方法可见度
class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age
        
    def __get_age():
        return self.__age()

p = Person('Alice', '20')
p.__age
p.__get_age()

>>>
AttributeError: 'Person' object has no attribute '__age'
AttributeError: 'Person' object has no attribute '__get_age'
print(p.__dict__)
print(p._Person__age)
print(p._Person__get_age())

>>>
{'name': 'Alice', '_Person__age': '20'}
20
20
@property和setter方法
class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):
        if value > 0:
            self.__age = value
        else:
            raise ValueError('Age must > 0')

p = Person('Alice', 20, 160)
print(p.age)
p.age = -10

>>>
Querying age
20
ValueError: Age must > 0
描述符
__get__(),在设置属性时调用该方法;
__set__() ,在读取属性时调用该方法;
__delete__() ,在删除属性时调用该方法;
class PositiveNumber:  # 描述符类

    def __init__(self, attr_name):
        self.attr_name = attr_name  # attr_name为托管实例中存储值的属性的名称。

    def __set__(self, instance, value):  # instance是托管实例,self是描述符实例。
        if value > 0:
            instance.__dict__[self.attr_name] = value  # 此处必须直接存入__dict__,否则会调用setattr函数会导致无限递归。
        else:
            raise ValueError(f'{self.attr_name} must > 0')

    def __get__(self, instance, owner):  # instance是托管实例,owner是托管类
        print(f'Querying {self.attr_name}')
        return instance.__dict__[self.attr_name]


class Person:  # 托管类
    age = PositiveNumber('age')
    height = PositiveNumber('height')

    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height


p = Person('Alice', 20, 160)
print(p.age)
p.height = -10

>>>
Querying age
20
ValueError: age must > 0
__getattribut____setattr____getattr__,
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getattr__(self, item):
        print(f'Person do not have field {item}')

p = Person('Alice', 20)
p.height

>>>
Person do not have attr height
继承

数据描述符 > 实例的__dict__ > 非数据描述符 > 类的__dict__ > 父类 - >父类的父类 ->Object->调用类的__getattr__->若仍不存在,会引发一个 AttributeError 异常

class Parent(object):
 x = 1
 
class Child1(Parent):
 pass
 
class Child2(Parent):
 pass
 
print Parent.x, Child1.x, Child2.x
Child1.x = 2
print Parent.x, Child1.x, Child2.x
Parent.x = 3
print Parent.x, Child1.x, Child2.x

>>>
1 1 1
1 2 1
3 2 3

这个答案的关键是,在 Python 中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到。

因此,在父类中设置 x = 1 会使得类变量 X 在引用该类和其任何子类中的值为 1。这就是因为第一个 print 语句的输出是1 1 1。

随后,如果任何它的子类重写了该值(例如,我们执行语句 Child1.x = 2),然后,该值仅仅在子类中被改变。这就是为什么第二个 print 语句的输出是 1 2 1

最后,如果该值在父类中被改变(例如,我们执行语句 Parent.x = 3),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是 Child2)。这就是为什么第三个 print 输出是 3 2 3。

3. 函数:作用域,闭包,装饰器
作用域
  1. local,局部作用域,即当前函数作用域
  2. enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域
  3. global,全局作用域,即代码所在模块的作用域
  4. built-in,内置作用域,系统固定模块的作用域
闭包
def func_outer(prefix):
    def func_inner(name):
        return prefix + ' ' + name
    return func_inner

func_inner = func_outer('Hello')
print(func_inner('A'))

>>>
Hello A
def func_outer(prefix):
    count = 0
    def func_inner(name):
        nonlocal count
        count += 1
        return '{} {}, id {}'.format(prefix, name, count)
    return func_inner

func_inner = func_outer('Hello')
print(func_inner('A'))
print(func_inner('B'))

>>>
Hello A, id 1
Hello B, id 2
a = 1
def func():
    global a
    a = 2

func()
print(a)

>>>
2
装饰器
# 定义一个装饰器
def trace(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print(f'function: {func.__name__}, parameter: {args},{kwargs}, result: {res}')
        return res
    return wrapper
    
# 使用@修饰函数,其效果等于以该函数为参数调用修饰器,
# 再把修饰器所返回的结果赋给同一个作用域中与原函数同名的变量,
# 即: fibonacci = trace(fibonacci)
@trace
def fibonacci(n):
    if n in (0, 1):
        return n
    return fibonacci(n - 2) + fibonacci(n - 1)

>>>    
function: fibonacci, parameter: (1,),{}, result: 1
function: fibonacci, parameter: (0,),{}, result: 0
function: fibonacci, parameter: (1,),{}, result: 1
function: fibonacci, parameter: (2,),{}, result: 1
function: fibonacci, parameter: (3,),{}, result: 2
4. 列表推导式,生成器,迭代器
列表推导式
>>> ['x' for n in range(5)]
['x', 'x', 'x', 'x', 'x']

>>> a=[1,2,3,4,5]
>>> [x for x in a if x % 2 == 0]
[2, 4]
生成器,迭代器
>>> a=[1,2,3,4,5]
>>> it = (x for x in a if x % 2 == 0)
>>> next(it)
2
>>> next(it)
4
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
a = [1, 2, 3, 4, 5]
it = (x for x in a if x % 2 == 0)
for index, value in enumerate(it):
    print('{}:{}'.format(index, value))

for index, value in enumerate(it):
    print('{}:{}'.format(index, value))
    
>>>
0:2
1:4
a = [1, 2, 3, 4, 5]
it1 = (x for x in a if x % 2 == 0)
it2 = (x for x in a if x % 2 != 0)
for v1, v2 in zip(it1, it2):
    print('{},{}'.format(v1, v2))

>>>
2,1
4,3
def func():
    for i in range(1000):
        yield [i] * 1000

gen = func()
for item in gen:
    print(item)
5. 并发与并行

进程,线程,协程与python的实现

6. 模块加载

1)在由sys.path所指定的路径中,搜寻待引入的模块。

2)从模块中加载代码,并保证这段代码能够正确编译。

3)创建与该模块对应的空对象。

4)把这个空的模块对象,添加到sys.modules里

5)运行模块对象中的代码,以定义其内容。

7. 内存管理
引用计数
>>> import sys
>>> s = '123'
>>> sys.getrefcount(s)
2
>>> n1 = s
>>> sys.getrefcount(s)
3
>>> l = [s]
>>> sys.getrefcount(s)
4
>>> del n1
>>> sys.getrefcount(s)
3
>>> del l
>>> sys.getrefcount(s)
2
标记清除法

1)内向型对象 ,例如 int 、float 、 str 等,这类对象不会引用其他对象,因此无法形成循环引用,无须跟踪;

2)外向型对象 ,例如 tuple 、 list 、 dict 等容器对象,以及函数、类实例等复杂对象,这类对象一般都会引用其他对象,存在形成循环引用的风险,因此是垃圾回收算法关注的重点;

分代回收机制

2)每执行 11 次新生代 GC ,触发一次中生代 GC ;

3)每执行 11 次中生代 GC ,触发一次老生代 GC (老生代 GC 还受其他策略影响,频率更低);

4)执行某个生代 GC 前,年轻生代对象链表也移入该代,一起 GC ;

5)一个对象创建后,随着时间推移将被逐步移入老生代,回收频率逐渐降低;

上一篇 下一篇

猜你喜欢

热点阅读