《Python高级编程》(六)类工厂

定义

类工厂本质:类工厂就是一个在运行时创建类的函数。
即允许创建类时根据情况决定其属性,比如,根据用户输入创建属性。
类工厂函数:是一个用于创建并返回类的函数

理解类工厂函数

使用type创建类如下:

def init(self, name):
    self.name = name
def eat(self):
    pass
def go_to_vet(self):
    print "go_to_vet"
return type('Animal', (object,), {
    '__doc__': 'A class representing an arbitrary animal.',
    '__init__': init,
    'eat': eat,
    'go_to_vet': go_to_vet,
})

这种方式的缺点:

  • 这种写法会将函数置于和Animal同一层命名空间下。因此一般不使用type之间创建。
    如果真需要使用type,则可以将其放入一个函数中,如下:
    def create_animal_class():
        def init(self, name):
            self.name = name
        def eat(self):
            pass
        def go_to_vet(self):
            print "go_to_vet"
        return type('Animal', (object,), {
            '__doc__': 'A class representing an arbitrary animal.',
            '__init__': init,
            'eat': eat,
            'go_to_vet': go_to_vet,
        })
    Animal = create_animal_class()
    print Animal   #<class '__main__.Animal'>

通过函数调用即可获得一个自定义创建的Animal类。
使用class关键字创建效果相同:

    def create_animal_class():
        class Animal(object):
	        def init(self, name):
	            self.name = name
	        def eat(self):
	            pass
	        def go_to_vet(self):
	            print "go_to_vet"
		return Animal
    Animal = create_animal_class()
    print Animal   #<class '__main__.Animal'>

何时编写类工厂

  • 在需要基于运行时的信息(如用户输入)创建类时需要编写类工厂
    • 如果在编码时并不知道需要赋值给类的属性时
    • 类工厂示例:(创建类工厂的原因:假如说是为大量不同的第三方网站提供凭据的服务,则需要有多重不同的验证方式。该工厂可以根据数据库查询结果生成属性)
#-*- coding:utf-8 -*-
def get_credential_class(use_proxy=False, tfa=False):
    if use_proxy:
        keys = ['service_name', 'email_address']  # 通过代理身份验证所要的密匙
    else:
        keys = ['username', 'password']
        if tfa:
            keys.append('tfa_token')


    class Credential(object):
        expected_keys = set(keys)

        def __init__(self, **kwargs):
            if self.expected_keys != set(kwargs.keys()):
                raise ValueError('Keys do not match')

            for k, v in kwargs.items():
                setattr(self, k, v)
    return Credential

cred = get_credential_class(0,0)
print cred

运行结果:
<class ‘main.Credential’>

  • 避免类属性一致性问题:处理类与实例之间属性不同的问题
类属性与实例属性
class C(object):
    foo = 'bar'

class I(object):
    def __init__(self):
        self.foo = 'bar'
print C.foo()
print I.foo()   # AttributeError

c1 = C()   
c2 = C()  

c1.foo = 'baz'
print c1.foo   #baz
print c2.foo   # bar

C.foo = 'bacon'
print c1.foo   #baz
print c2.foo   #bacon

print c1.__dict__    # {'foo': 'baz'}
print c2.__dict__    #{}
  • print I.foo() # AttributeError原因
    foo作为C的一个实例被实例化,但并不作为I的属性被实例化。
    由于直接访问I而不是I的实例,因此__init__函数还没有被允许。
  • 一个对象的属性查找顺序遵循首先查找实例对象自己,然后是类,接着是类的父类。
  • 本质:__dict__属性存储着对象的所有属性(和值)
  • 注意:一些内置的数据类型是没有__dict__属性的:
    int,list,dict等这些常用的数据类型是没有__dict__属性的,其实这是可预料的,就算给了它们dict属性也没啥用,毕竟它们只是用来做数据容器的。
属性:指一个对象的数据或者函数
	- 属性的访问:通过句话(.)访问属性
	- 支持运行中添加和修改属性
字段:类的数据变量,例如:name='scolia'
方法:类里面的函数。可分为:
	- 实例方法:第一个参数需要是self,它表示一个具体的实例本身。
	- 类方法:用classmethod,它的第一个参数不是self,是cls,它表示这个类本身。类方法是那些并不需要类的实例就可以执行的方法
	- 静态方法:用staticmethod,可以无视self,而将这个方法当成一个普通的函数使用
#-*- coding:utf-8 -*-
class cls:
    clsvar = 1   #普通字段
    def __init__(self):
        self.insvar = 2

ins1 = cls()
ins2 = cls()

ins1.clsvar = 20
print cls.clsvar     #输出结果为1
print ins1.clsvar    #输出结果为20
print ins2.clsvar    #输出结果为1

#用类名为类变量重新赋值并打印
cls.clsvar = 10
print cls.clsvar     #输出结果为10
print ins1.clsvar    #输出结果为20
print ins2.clsvar    #输出结果为10

#这次直接给实例1没有在类中定义的变量赋值
ins1.x = 11
print ins1.x         #输出结果为11


#然后再用类名给类中没有定义的变量赋值
cls.m = 21
print cls.m          #输出结果为21

#再创建一个实例ins3,然后打印一下ins3的变量
ins3 = cls()
print ins3.insvar    #输出结果为2
print ins3.clsvar    #输出结果为10
print ins3.m         #输出结果为21
print ins3.x         #报错AttributeErro
类方法的限制
class C(object):
    foo = 'bar'

    @classmethod
    def classfoo(cls):
        return cls.foo

print c1.classfoo()  #bacon
print c2.classfoo()  #bacon

注意:类方法无法访问实例属性,它们并不需要一个实例,但需要类本身。
因此c1.classfoo使用的是类的foo而不是实例c1的foo

使用类工厂

使用时机:当你继承一个现有类并且所依赖的类属性必须调整时。
类工厂是生成带有重载属性的恰当子类的一种恰当方式。

class C(object):
    foo = 'bar'

    @classmethod
    def classfoo(cls):
        return cls.foo

def create_C_subclass(new_foo):
    class SubC(C):
        foo = new_foo
    return SubC

S = create_C_subclass('spam')
print S.classfoo()  #spam
E = create_C_subclass('eggs')
print E.classfoo()  #eggs

执行C子类的classfoo类方法创建类的方式返回需要的结果。

单例模式

让类工厂函数难以使用的一点是类工厂返回的是类而不是类的实例。
如果一个实例,则必须调用类工厂函数返回的结果才可以。
单例模式是一种只允许一个实例的类模式。
类工厂示例:

class C(object):
    foo = 'bar'

    @classmethod
    def classfoo(cls):
        return cls.foo

def CPrime(new_foo='bar'):
    if new_foo == 'bar':
        return C()
    class SubC(C):
        foo = new_foo
    return SubC

EE = CPrime('bar')
FF = CPrime('bar1')
print EE  #<__main__.C object at 0x01777CB0>
print FF  #<class '__main__.SubC'>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值