Python杂记

装饰器

1、python内部函数

python内部函数示例:

def test(*args):
    def add(*args):         #  显示的调用外部函数的参数
        return args
    return add(*args)       #  返回内部函数的直接调用
 
运行结果如下:
test(1,2,3)
(1,2,3)   

内部函数直接引用外部函数参数,外部函数test显示的返回内部函数add的调用
当需要在函数内部多次执行复杂任务时,内部函数非常有用,从而避免了循环和代码的堆叠重复

2、python闭包

内部函数可以看作是一个闭包。闭包是一个可以由另一个函数动态生成的函数,并且可以改变和存储函数外创建的变量的值。

python闭包示例:

def test(a):
    def add():                                #  没用引用外部函数的参数
        return "it's a callable %s" % a       #  直接在内部函数使用外部函数的参数
    return add                                #  返回内部函数本身,不返回内部函数调用
 
运行结果如下:
a1 = test(1)           # 动态生成的一个可以记录外部变量的函数
<function __main__.add>
 
a1()                   # 调用此函数
it's a callable 1
 
test(1)()              # 本身调用过程,先动态生成一个函数再进行调用
it's a callable 1

3、python装饰器

装饰器实质上是一个函数,它把一个函数作为输入并且返回另外一个函数,在装饰器中,通常使用下面这些python技巧:

  • *args 和 **kwargs
  • 闭包
  • 作为参数的函数

python装饰器示例:

def test(func):                           # 将函数作为参数进行传递
    def add(*args,**kwargs):
        print “it's a d”
        return func(*args,**kwargs)       # 内部函数进行相关操作以后,返回传递函数的调用
    return add
 
 
def func(a,b):
    return a+b
 
运行结果如下:
test(func)                # 将func作为函数传递进test函数进行装饰
<function __main__.add>   # 装饰后的函数,类似闭包
 
test(func)(1,2)           # 显示的对装饰后的函数进行调用
it's a d                  # 中间被装饰的过程被print出来
3
 
更简单的方法调用装饰器
@test                     # 同一个函数可以调用多个装饰器,执行过程中不分先后顺序
def func(a,b):
    return a+b

装饰器本身需要传递参数的时候:

def test(cmd):                            # 将参数传递
    def exc(func):                        # 第二步进行函数作为参数传递
         def add(*args,**kwargs):
             print "it's a %s" % cmd
             print "begin"
             return func(*args,**kwargs)
         return add
    return exc
  
 运行结果如下:
 test('haha')
 <function __main__.exc>
  
 test('haha')(func)(1,2)            # 调用装饰器返回结果
 it's a haha
 begin
 3
  
 更简单的方法调用
 @test('haha')                     # test函数进行了参数传递
 def func(a,b):
    return a+b

python装饰器注意事项:
对func进行装饰以后,func的函数命名空间发生了变化

执行 func.__name__
add

Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

import functools
def test(func):
    @functools.wraps(func)
    def add(*args,**kwargs):
        print "it's a decorator"
        return func(*args,**kwargs)
    return add
     
@test
def func(a,b):
    return a+b
     
再次运行,查看命名空间
func.__name__
func                  # 返回了本身

隐藏属性

双下划线开头的属性,__xxx
隐藏属性只能在类的内部访问,无法通过对象访问
其实隐藏属性只不过是Python自动为属性改了一个名字
实际上是将名字修改为了,_类名__属性名
比如 __name -> _Person__name

class Person:
    def __init__(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self , name):
        self.__name = name

p = Person('孙悟空')

# print(p.__name) __开头的属性是隐藏属性,无法通过对象访问
# p.__name = '猪八戒'
print(p._Person__name)
# p._Person__name = '猪八戒'
print(p.get_name())

私有属性
使用_开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
一般我们会将一些私有属性(不希望被外部访问的属性)以_开头
一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性

class Person:
    def __init__(self,name):
        self._name = name

    def get_name(self):
        return self._name

    def set_name(self , name):
        self._name = name

p = Person('孙悟空')

print(p._name)

继承

class Animal:
    def __init__(self,name):
        self._name = name

    def run(self):
        print('动物会跑~~~')

    def sleep(self):
        print('动物睡觉~~~')

    @property
    def name(self):
        return self._name

# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
class Dog(Animal):

    def __init__(self,name,age):
        # 希望可以直接调用父类的__init__来初始化父类中定义的属性
        # super() 可以用来获取当前类的父类,
        #   并且通过super()返回对象调用父类方法时,不需要传递self
        super().__init__(name)
        self._age = age

    def bark(self):
        print('汪汪汪~~~')

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

d = Dog('旺财',18)
print(d.name)
print(d.age)

多重继承

class A(object):
    def test(self):
        print('AAA')

class B(object):
    def test(self):
        print('B中的test()方法~~')

    def test2(self):
        print('BBB')

# 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
# 可以在类名的()后边添加多个类,来实现多重继承
# 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
# 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
# 如果多个父类中有同名的方法,则会现在第一个父类中寻找,然后找第二个,然后找第三个。。。
# 前边父类的方法会覆盖后边父类的方法
class C(A,B):
    pass

# 类名.__bases__ 这个属性可以用来获取当前类的所有父类
# print(C.__bases__) (,)
# print(B.__bases__) (,)

# print(C.__bases__) 
# (, )

c = C()
c.test()

面向对象的三大特征
封装
- 确保对象中的数据安全
继承
- 保证了对象的可扩展性
多态
- 保证了程序的灵活性

类中的属性和方法

class A(object):

    # 类属性
    # 实例属性
    # 类方法
    # 实例方法
    # 静态方法

    # 类属性,直接在类中定义的属性是类属性
    #   类属性可以通过类或类的实例访问到
    #   但是类属性只能通过类对象来修改,无法通过实例对象修改
    count = 0

    def __init__(self):
        # 实例属性,通过实例对象添加的属性属于实例属性
        #   实例属性只能通过实例对象来访问和修改,类对象无法访问修改
        self.name = '孙悟空'

    # 实例方法
    #   在类中定义,以self为第一个参数的方法都是实例方法
    #   实例方法在调用时,Python会将调用对象作为self传入
    #   实例方法可以通过实例和类去调用
    #       当通过实例调用时,会自动将当前调用对象作为self传入
    #       当通过类调用时,不会自动传递self,此时我们必须手动传递self
    def test(self):
        print('这是test方法~~~ ' , self)

    # 类方法
    # 在类内部使用 @classmethod 来修饰的方法属于类方法
    # 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
    #   类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
    #   类方法可以通过类去调用,也可以通过实例调用,没有区别
    @classmethod
    def test_2(cls):
        print('这是test_2方法,他是一个类方法~~~ ',cls)
        print(cls.count)

    # 静态方法
    # 在类中使用 @staticmethod 来修饰的方法属于静态方法
    # 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
    # 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
    # 静态方法一般都是一些工具方法,和当前类无关
    @staticmethod
    def test_3():
        print('test_3执行了~~~')
a = A()
a.test() #实例调用实例方法
A.test(a) #类调用实例方法
a.test_2() # 实例调用类方法
A.test_2() # 类调用类方法
a.test_3()
A.test_3()

你可能感兴趣的:(python,python)